From cc7596f3b3af8c68b1ced0802a8f7b341d2791af Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 22 Feb 2015 19:44:26 +0000 Subject: [PATCH 001/444] Renamed storage to repository --- .../AbstractStorage.php => Repositories/AbstractRepository.php} | 0 .../AccessTokenRepositoryInterface.php} | 0 .../AuthCodeRepositoryInterface.php} | 0 src/{Storage => Repositories}/ClientInterface.php | 0 src/{Storage => Repositories}/MacTokenInterface.php | 0 src/{Storage => Repositories}/RefreshTokenInterface.php | 0 src/{Storage => Repositories}/ScopeInterface.php | 0 src/{Storage => Repositories}/SessionInterface.php | 0 src/{Storage => Repositories}/StorageInterface.php | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename src/{Storage/AbstractStorage.php => Repositories/AbstractRepository.php} (100%) rename src/{Storage/AccessTokenInterface.php => Repositories/AccessTokenRepositoryInterface.php} (100%) rename src/{Storage/AuthCodeInterface.php => Repositories/AuthCodeRepositoryInterface.php} (100%) rename src/{Storage => Repositories}/ClientInterface.php (100%) rename src/{Storage => Repositories}/MacTokenInterface.php (100%) rename src/{Storage => Repositories}/RefreshTokenInterface.php (100%) rename src/{Storage => Repositories}/ScopeInterface.php (100%) rename src/{Storage => Repositories}/SessionInterface.php (100%) rename src/{Storage => Repositories}/StorageInterface.php (100%) diff --git a/src/Storage/AbstractStorage.php b/src/Repositories/AbstractRepository.php similarity index 100% rename from src/Storage/AbstractStorage.php rename to src/Repositories/AbstractRepository.php diff --git a/src/Storage/AccessTokenInterface.php b/src/Repositories/AccessTokenRepositoryInterface.php similarity index 100% rename from src/Storage/AccessTokenInterface.php rename to src/Repositories/AccessTokenRepositoryInterface.php diff --git a/src/Storage/AuthCodeInterface.php b/src/Repositories/AuthCodeRepositoryInterface.php similarity index 100% rename from src/Storage/AuthCodeInterface.php rename to src/Repositories/AuthCodeRepositoryInterface.php diff --git a/src/Storage/ClientInterface.php b/src/Repositories/ClientInterface.php similarity index 100% rename from src/Storage/ClientInterface.php rename to src/Repositories/ClientInterface.php diff --git a/src/Storage/MacTokenInterface.php b/src/Repositories/MacTokenInterface.php similarity index 100% rename from src/Storage/MacTokenInterface.php rename to src/Repositories/MacTokenInterface.php diff --git a/src/Storage/RefreshTokenInterface.php b/src/Repositories/RefreshTokenInterface.php similarity index 100% rename from src/Storage/RefreshTokenInterface.php rename to src/Repositories/RefreshTokenInterface.php diff --git a/src/Storage/ScopeInterface.php b/src/Repositories/ScopeInterface.php similarity index 100% rename from src/Storage/ScopeInterface.php rename to src/Repositories/ScopeInterface.php diff --git a/src/Storage/SessionInterface.php b/src/Repositories/SessionInterface.php similarity index 100% rename from src/Storage/SessionInterface.php rename to src/Repositories/SessionInterface.php diff --git a/src/Storage/StorageInterface.php b/src/Repositories/StorageInterface.php similarity index 100% rename from src/Storage/StorageInterface.php rename to src/Repositories/StorageInterface.php From 742b51c2cd3758cd513ac17d18c78ac51a9a5bd0 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 1 Mar 2015 21:29:47 +0000 Subject: [PATCH 002/444] Removed domain events --- src/Event/ClientAuthenticationFailedEvent.php | 55 ------------------- src/Event/SessionOwnerEvent.php | 55 ------------------- src/Event/UserAuthenticationFailedEvent.php | 55 ------------------- 3 files changed, 165 deletions(-) delete mode 100644 src/Event/ClientAuthenticationFailedEvent.php delete mode 100644 src/Event/SessionOwnerEvent.php delete mode 100644 src/Event/UserAuthenticationFailedEvent.php diff --git a/src/Event/ClientAuthenticationFailedEvent.php b/src/Event/ClientAuthenticationFailedEvent.php deleted file mode 100644 index 4448bb4e..00000000 --- a/src/Event/ClientAuthenticationFailedEvent.php +++ /dev/null @@ -1,55 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Event; - -use League\Event\AbstractEvent; -use Symfony\Component\HttpFoundation\Request; - -class ClientAuthenticationFailedEvent extends AbstractEvent -{ - /** - * Request - * - * @var \Symfony\Component\HttpFoundation\Request - */ - private $request; - - /** - * Init the event with a request - * - * @param \Symfony\Component\HttpFoundation\Request $request - */ - public function __construct(Request $request) - { - $this->request = $request; - } - - /** - * The name of the event - * - * @return string - */ - public function getName() - { - return 'error.auth.client'; - } - - /** - * Return request - * - * @return \Symfony\Component\HttpFoundation\Request - */ - public function getRequest() - { - return $this->request; - } -} diff --git a/src/Event/SessionOwnerEvent.php b/src/Event/SessionOwnerEvent.php deleted file mode 100644 index 83c4e766..00000000 --- a/src/Event/SessionOwnerEvent.php +++ /dev/null @@ -1,55 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Event; - -use League\Event\AbstractEvent; -use League\OAuth2\Server\Entity\SessionEntity; - -class SessionOwnerEvent extends AbstractEvent -{ - /** - * Session entity - * - * @var \League\OAuth2\Server\Entity\SessionEntity - */ - private $session; - - /** - * Init the event with a session - * - * @param \League\OAuth2\Server\Entity\SessionEntity $session - */ - public function __construct(SessionEntity $session) - { - $this->session = $session; - } - - /** - * The name of the event - * - * @return string - */ - public function getName() - { - return 'session.owner'; - } - - /** - * Return session - * - * @return \League\OAuth2\Server\Entity\SessionEntity - */ - public function getSession() - { - return $this->session; - } -} diff --git a/src/Event/UserAuthenticationFailedEvent.php b/src/Event/UserAuthenticationFailedEvent.php deleted file mode 100644 index 4cd8c4cd..00000000 --- a/src/Event/UserAuthenticationFailedEvent.php +++ /dev/null @@ -1,55 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Event; - -use League\Event\AbstractEvent; -use Symfony\Component\HttpFoundation\Request; - -class UserAuthenticationFailedEvent extends AbstractEvent -{ - /** - * Request - * - * @var \Symfony\Component\HttpFoundation\Request - */ - private $request; - - /** - * Init the event with a request - * - * @param \Symfony\Component\HttpFoundation\Request $request - */ - public function __construct(Request $request) - { - $this->request = $request; - } - - /** - * The name of the event - * - * @return string - */ - public function getName() - { - return 'error.auth.user'; - } - - /** - * Return request - * - * @return \Symfony\Component\HttpFoundation\Request - */ - public function getRequest() - { - return $this->request; - } -} From 5d7eeb05126ace331150a682b85a25326278f742 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 1 Mar 2015 21:29:52 +0000 Subject: [PATCH 003/444] Spelling fix --- src/AuthorizationServer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index 2d9e12f0..d75213e9 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -20,7 +20,7 @@ use League\OAuth2\Server\TokenType\Bearer; class AuthorizationServer extends AbstractServer { /** - * The delimeter between scopes specified in the scope query string parameter + * The delimiter between scopes specified in the scope query string parameter * The OAuth 2 specification states it should be a space but most use a comma * * @var string From 7c57310b67d648a67cd0d563b365cb579bfb9368 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 4 Apr 2015 15:41:31 +0100 Subject: [PATCH 004/444] Removed old fuzz tests --- tests/fuzz/grant-authcode.yml | 9 -- tests/fuzz/grant-client-credentials.yml | 67 -------------- tests/fuzz/grant-password.yml | 88 ------------------- tests/fuzz/tokeninfo-no-access-token.yml | 16 ---- ...okeninfo-no-invalid-token-query-string.yml | 16 ---- tests/fuzz/tokeninfo-no-invalid-token.yml | 20 ----- tests/fuzz/tokeninfo-valid-token-header.yml | 26 ------ tests/fuzz/tokeninfo-valid-token.yml | 22 ----- tests/fuzz/users-token-iamalex.yml | 32 ------- tests/fuzz/users-token-iamphil.yml | 32 ------- 10 files changed, 328 deletions(-) delete mode 100644 tests/fuzz/grant-authcode.yml delete mode 100644 tests/fuzz/grant-client-credentials.yml delete mode 100644 tests/fuzz/grant-password.yml delete mode 100644 tests/fuzz/tokeninfo-no-access-token.yml delete mode 100644 tests/fuzz/tokeninfo-no-invalid-token-query-string.yml delete mode 100644 tests/fuzz/tokeninfo-no-invalid-token.yml delete mode 100644 tests/fuzz/tokeninfo-valid-token-header.yml delete mode 100644 tests/fuzz/tokeninfo-valid-token.yml delete mode 100644 tests/fuzz/users-token-iamalex.yml delete mode 100644 tests/fuzz/users-token-iamphil.yml diff --git a/tests/fuzz/grant-authcode.yml b/tests/fuzz/grant-authcode.yml deleted file mode 100644 index e4df2d68..00000000 --- a/tests/fuzz/grant-authcode.yml +++ /dev/null @@ -1,9 +0,0 @@ -url: 'http://localhost:8000/authcode_grant.php/authorize?client_id=testclient&redirect_uri=http%3A%2F%2Fexample.com%2Fredirect&response_type=code&scope=basic' -request: - method: GET -response: - statusCode: 200 - headers: - - - key: Location - valueRegex: /http:\/\/example.com\/redirect\?code=([a-zA-Z0-9]*)/ diff --git a/tests/fuzz/grant-client-credentials.yml b/tests/fuzz/grant-client-credentials.yml deleted file mode 100644 index 47b9f566..00000000 --- a/tests/fuzz/grant-client-credentials.yml +++ /dev/null @@ -1,67 +0,0 @@ -url: 'http://localhost:8000/other_grants.php/access_token' -request: - method: POST - body: - - - key: client_id - value: testclient - missing: - response.statusCode: 400 - headers.content-type: "application/json" - body.error: invalid_request - body.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." - invalid: - response.statusCode: 401 - headers.content-type: "application/json" - body.error: invalid_client - body.message: "Client authentication failed." - - - key: client_secret - value: secret - missing: - response.statusCode: 400 - headers.content-type: "application/json" - body.error: invalid_request - body.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." - invalid: - response.statusCode: 401 - headers.content-type: "application/json" - body.error: invalid_client - body.message: "Client authentication failed." - - - key: grant_type - value: client_credentials - missing: - response.statusCode: 400 - headers.content-type: "application/json" - body.error: invalid_request - body.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 \"grant_type\" parameter." - invalid: - response.statusCode: 400 - headers.content-type: "application/json" - body.error: unsupported_grant_type - #body.message: "The authorization grant type XXX is not supported by the authorization server." - - - key: scope - value: "basic" - invalid: - response.statusCode: 400 - headers.content-type: "application/json" - body.error: invalid_scope - border.message: fooooooooo -response: - statusCode: 200 - headers: - - - key: Content-type - value: application/json - body: - - - key: expires_in - valueType: integer - - - key: access_token - valueRegex: /([a-zA-Z0-9]*)/ - - - key: token_type - value: Bearer diff --git a/tests/fuzz/grant-password.yml b/tests/fuzz/grant-password.yml deleted file mode 100644 index e0f95827..00000000 --- a/tests/fuzz/grant-password.yml +++ /dev/null @@ -1,88 +0,0 @@ -url: 'http://localhost:8000/other_grants.php/access_token' -request: - method: POST - body: - - - key: client_id - value: testclient - missing: - response.statusCode: 400 - headers.content-type: "application/json" - body.error: invalid_request - body.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." - invalid: - response.statusCode: 401 - headers.content-type: "application/json" - body.error: invalid_client - body.message: "Client authentication failed." - - - key: client_secret - value: secret - missing: - response.statusCode: 400 - headers.content-type: "application/json" - body.error: invalid_request - body.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." - invalid: - response.statusCode: 401 - headers.content-type: "application/json" - body.error: invalid_client - body.message: "Client authentication failed." - - - key: username - value: alexbilbie - missing: - response.statusCode: 400 - headers.content-type: "application/json" - body.error: invalid_request - body.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 \"username\" parameter." - invalid: - response.statusCode: 401 - headers.content-type: "application/json" - body.error: invalid_credentials - body.message: "The user credentials were incorrect." - - - key: password - value: whisky - missing: - response.statusCode: 400 - headers.content-type: "application/json" - body.error: invalid_request - body.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 \"password\" parameter." - invalid: - response.statusCode: 401 - headers.content-type: "application/json" - body.error: invalid_credentials - body.message: "The user credentials were incorrect." - - - key: grant_type - value: password - missing: - response.statusCode: 400 - headers.content-type: "application/json" - body.error: invalid_request - body.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 \"grant_type\" parameter." - invalid: - response.statusCode: 400 - headers.content-type: "application/json" - body.error: unsupported_grant_type - #body.message: "The authorization grant type XXX is not supported by the authorization server." -response: - statusCode: 200 - headers: - - - key: Content-type - value: application/json - body: - - - key: expires_in - valueType: integer - - - key: access_token - valueRegex: /([a-zA-Z0-9]*)/ - - - key: refresh_token - valueRegex: /([a-zA-Z0-9]*)/ - - - key: token_type - value: Bearer diff --git a/tests/fuzz/tokeninfo-no-access-token.yml b/tests/fuzz/tokeninfo-no-access-token.yml deleted file mode 100644 index 253d29e9..00000000 --- a/tests/fuzz/tokeninfo-no-access-token.yml +++ /dev/null @@ -1,16 +0,0 @@ -url: 'http://localhost:8000/api.php/tokeninfo' -request: - method: GET -response: - statusCode: 400 - headers: - - - key: Content-type - value: application/json - body: - - - key: error - value: "invalid_request" - - - key: message - value: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"access token\" parameter." diff --git a/tests/fuzz/tokeninfo-no-invalid-token-query-string.yml b/tests/fuzz/tokeninfo-no-invalid-token-query-string.yml deleted file mode 100644 index 2606eb05..00000000 --- a/tests/fuzz/tokeninfo-no-invalid-token-query-string.yml +++ /dev/null @@ -1,16 +0,0 @@ -url: 'http://localhost:8000/api.php/tokeninfo?access_token=foobar' -request: - method: GET -response: - statusCode: 401 - headers: - - - key: Content-type - value: application/json - body: - - - key: error - value: "access_denied" - - - key: message - value: "The resource owner or authorization server denied the request." diff --git a/tests/fuzz/tokeninfo-no-invalid-token.yml b/tests/fuzz/tokeninfo-no-invalid-token.yml deleted file mode 100644 index eab58240..00000000 --- a/tests/fuzz/tokeninfo-no-invalid-token.yml +++ /dev/null @@ -1,20 +0,0 @@ -url: 'http://localhost:8000/api.php/tokeninfo' -request: - method: GET - headers: - - - key: Authorization - value: Bearer foobar -response: - statusCode: 401 - headers: - - - key: Content-type - value: application/json - body: - - - key: error - value: "access_denied" - - - key: message - value: "The resource owner or authorization server denied the request." diff --git a/tests/fuzz/tokeninfo-valid-token-header.yml b/tests/fuzz/tokeninfo-valid-token-header.yml deleted file mode 100644 index 67f74d69..00000000 --- a/tests/fuzz/tokeninfo-valid-token-header.yml +++ /dev/null @@ -1,26 +0,0 @@ -url: 'http://localhost:8000/api.php/tokeninfo' -request: - method: GET - headers: - - - key: Authorization - value: "Bearer iamgod" -response: - statusCode: 200 - headers: - - - key: Content-type - value: application/json - body: - - - key: owner_id - value: testclient - - - key: owner_type - value: client - - - key: access_token - value: iamgod - - - key: client_id - value: testclient diff --git a/tests/fuzz/tokeninfo-valid-token.yml b/tests/fuzz/tokeninfo-valid-token.yml deleted file mode 100644 index d76def84..00000000 --- a/tests/fuzz/tokeninfo-valid-token.yml +++ /dev/null @@ -1,22 +0,0 @@ -url: 'http://localhost:8000/api.php/tokeninfo?access_token=iamgod' -request: - method: GET -response: - statusCode: 200 - headers: - - - key: Content-type - value: application/json - body: - - - key: owner_id - value: testclient - - - key: owner_type - value: client - - - key: access_token - value: iamgod - - - key: client_id - value: testclient diff --git a/tests/fuzz/users-token-iamalex.yml b/tests/fuzz/users-token-iamalex.yml deleted file mode 100644 index 43086f3e..00000000 --- a/tests/fuzz/users-token-iamalex.yml +++ /dev/null @@ -1,32 +0,0 @@ -url: 'http://localhost:8000/api.php/users' -request: - method: GET - headers: - - - key: Authorization - value: Bearer iamalex -response: - statusCode: 200 - headers: - - - key: Content-type - value: application/json - body: - - - key: 0.username - value: alexbilbie - - - key: 0.name - value: Alex Bilbie - - - key: 0.photo - valueType: string - - - key: 1.username - value: philsturgeon - - - key: 1.name - value: Phil Sturgeon - - - key: 1.photo - valueType: string diff --git a/tests/fuzz/users-token-iamphil.yml b/tests/fuzz/users-token-iamphil.yml deleted file mode 100644 index 98d8e982..00000000 --- a/tests/fuzz/users-token-iamphil.yml +++ /dev/null @@ -1,32 +0,0 @@ -url: 'http://localhost:8000/api.php/users' -request: - method: GET - headers: - - - key: Authorization - value: Bearer iamphil -response: - statusCode: 200 - headers: - - - key: Content-type - value: application/json - body: - - - key: 0.username - value: alexbilbie - - - key: 0.name - value: Alex Bilbie - - - key: 0.email - valueType: string - - - key: 1.username - value: philsturgeon - - - key: 1.name - value: Phil Sturgeon - - - key: 1.email - valueType: string From 027971776b70bc0d5e0c440aa037568b84e40fde Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 4 Apr 2015 15:41:53 +0100 Subject: [PATCH 005/444] Namespace renamed TokenType > TokenTypes --- .../AbstractTokenType.php | 48 +++++-------------- src/{TokenType => TokenTypes}/Bearer.php | 4 +- src/{TokenType => TokenTypes}/MAC.php | 2 +- .../TokenTypeInterface.php | 18 ++----- 4 files changed, 20 insertions(+), 52 deletions(-) rename src/{TokenType => TokenTypes}/AbstractTokenType.php (51%) rename src/{TokenType => TokenTypes}/Bearer.php (90%) rename src/{TokenType => TokenTypes}/MAC.php (98%) rename src/{TokenType => TokenTypes}/TokenTypeInterface.php (75%) diff --git a/src/TokenType/AbstractTokenType.php b/src/TokenTypes/AbstractTokenType.php similarity index 51% rename from src/TokenType/AbstractTokenType.php rename to src/TokenTypes/AbstractTokenType.php index adb8837b..41e5ca4f 100644 --- a/src/TokenType/AbstractTokenType.php +++ b/src/TokenTypes/AbstractTokenType.php @@ -9,12 +9,11 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\TokenType; +namespace League\OAuth2\Server\TokenTypes; -use League\OAuth2\Server\AbstractServer; -use League\OAuth2\Server\Entity\SessionEntity; +use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -abstract class AbstractTokenType +abstract class AbstractTokenType implements TokenTypeInterface { /** * Response array @@ -24,38 +23,9 @@ abstract class AbstractTokenType protected $response = []; /** - * Server - * - * @var \League\OAuth2\Server\AbstractServer $server + * @var \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface */ - protected $server; - - /** - * Server - * - * @var \League\OAuth2\Server\Entity\SessionEntity $session - */ - protected $session; - - /** - * {@inheritdoc} - */ - public function setServer(AbstractServer $server) - { - $this->server = $server; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function setSession(SessionEntity $session) - { - $this->session = $session; - - return $this; - } + protected $accessToken; /** * {@inheritdoc} @@ -72,4 +42,12 @@ abstract class AbstractTokenType { return isset($this->response[$key]) ? $this->response[$key] : null; } + + /** + * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken + */ + public function setAccessToken(AccessTokenEntityInterface $accessToken) + { + $this->accessToken = $accessToken; + } } diff --git a/src/TokenType/Bearer.php b/src/TokenTypes/Bearer.php similarity index 90% rename from src/TokenType/Bearer.php rename to src/TokenTypes/Bearer.php index 797de3ac..47e1a908 100644 --- a/src/TokenType/Bearer.php +++ b/src/TokenTypes/Bearer.php @@ -9,11 +9,11 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\TokenType; +namespace League\OAuth2\Server\TokenTypes; use Symfony\Component\HttpFoundation\Request; -class Bearer extends AbstractTokenType implements TokenTypeInterface +class Bearer extends AbstractTokenType { /** * {@inheritdoc} diff --git a/src/TokenType/MAC.php b/src/TokenTypes/MAC.php similarity index 98% rename from src/TokenType/MAC.php rename to src/TokenTypes/MAC.php index 1eb3b930..48c2274f 100644 --- a/src/TokenType/MAC.php +++ b/src/TokenTypes/MAC.php @@ -9,7 +9,7 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\TokenType; +namespace League\OAuth2\Server\TokenTypes; use League\OAuth2\Server\Util\SecureKey; use Symfony\Component\HttpFoundation\ParameterBag; diff --git a/src/TokenType/TokenTypeInterface.php b/src/TokenTypes/TokenTypeInterface.php similarity index 75% rename from src/TokenType/TokenTypeInterface.php rename to src/TokenTypes/TokenTypeInterface.php index 17c2c1cf..4c4c36d9 100644 --- a/src/TokenType/TokenTypeInterface.php +++ b/src/TokenTypes/TokenTypeInterface.php @@ -9,9 +9,10 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\TokenType; +namespace League\OAuth2\Server\TokenTypes; use League\OAuth2\Server\AbstractServer; +use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entity\SessionEntity; use Symfony\Component\HttpFoundation\Request; @@ -25,13 +26,9 @@ interface TokenTypeInterface public function generateResponse(); /** - * Set the server - * - * @param \League\OAuth2\Server\AbstractServer $server - * - * @return self + * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken */ - public function setServer(AbstractServer $server); + public function setAccessToken(AccessTokenEntityInterface $accessToken); /** * Set a key/value response pair @@ -50,13 +47,6 @@ interface TokenTypeInterface */ public function getParam($key); - /** - * @param \League\OAuth2\Server\Entity\SessionEntity $session - * - * @return self - */ - public function setSession(SessionEntity $session); - /** * Determine the access token in the authorization header * From a73322fb43eaa2c28047c64dcaa1c863490628ae Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 4 Apr 2015 15:42:12 +0100 Subject: [PATCH 006/444] Renamed namespace Util > Utils --- .../KeyAlgorithm/DefaultAlgorithm.php | 2 +- .../KeyAlgorithm/KeyAlgorithmInterface.php | 2 +- src/{Util => Utils}/RedirectUri.php | 10 ++--- src/{Util => Utils}/SecureKey.php | 9 +++-- src/Utils/ServerAwareTrait.php | 38 +++++++++++++++++++ 5 files changed, 51 insertions(+), 10 deletions(-) rename src/{Util => Utils}/KeyAlgorithm/DefaultAlgorithm.php (95%) rename src/{Util => Utils}/KeyAlgorithm/KeyAlgorithmInterface.php (90%) rename src/{Util => Utils}/RedirectUri.php (66%) rename src/{Util => Utils}/SecureKey.php (83%) create mode 100644 src/Utils/ServerAwareTrait.php diff --git a/src/Util/KeyAlgorithm/DefaultAlgorithm.php b/src/Utils/KeyAlgorithm/DefaultAlgorithm.php similarity index 95% rename from src/Util/KeyAlgorithm/DefaultAlgorithm.php rename to src/Utils/KeyAlgorithm/DefaultAlgorithm.php index 70fecb14..cdbe20bf 100644 --- a/src/Util/KeyAlgorithm/DefaultAlgorithm.php +++ b/src/Utils/KeyAlgorithm/DefaultAlgorithm.php @@ -9,7 +9,7 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\Util\KeyAlgorithm; +namespace League\OAuth2\Server\Utils\KeyAlgorithm; class DefaultAlgorithm implements KeyAlgorithmInterface { diff --git a/src/Util/KeyAlgorithm/KeyAlgorithmInterface.php b/src/Utils/KeyAlgorithm/KeyAlgorithmInterface.php similarity index 90% rename from src/Util/KeyAlgorithm/KeyAlgorithmInterface.php rename to src/Utils/KeyAlgorithm/KeyAlgorithmInterface.php index c1237f91..c0f38ad1 100644 --- a/src/Util/KeyAlgorithm/KeyAlgorithmInterface.php +++ b/src/Utils/KeyAlgorithm/KeyAlgorithmInterface.php @@ -9,7 +9,7 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\Util\KeyAlgorithm; +namespace League\OAuth2\Server\Utils\KeyAlgorithm; interface KeyAlgorithmInterface { diff --git a/src/Util/RedirectUri.php b/src/Utils/RedirectUri.php similarity index 66% rename from src/Util/RedirectUri.php rename to src/Utils/RedirectUri.php index 848e854a..d00f29cc 100644 --- a/src/Util/RedirectUri.php +++ b/src/Utils/RedirectUri.php @@ -9,7 +9,7 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\Util; +namespace League\OAuth2\Server\Utils; /** * RedirectUri class @@ -21,14 +21,14 @@ class RedirectUri * * @param string $uri The base URI * @param array $params The query string parameters - * @param string $queryDelimeter The query string delimeter (default: "?") + * @param string $queryDelimiter The query string delimiter (default: "?") * * @return string The updated URI */ - public static function make($uri, $params = [], $queryDelimeter = '?') + public static function make($uri, $params = [], $queryDelimiter = '?') { - $uri .= (strstr($uri, $queryDelimeter) === false) ? $queryDelimeter : '&'; + $uri .= (strstr($uri, $queryDelimiter) === false) ? $queryDelimiter : '&'; - return $uri.http_build_query($params); + return $uri . http_build_query($params); } } diff --git a/src/Util/SecureKey.php b/src/Utils/SecureKey.php similarity index 83% rename from src/Util/SecureKey.php rename to src/Utils/SecureKey.php index 95ca56b0..16dc367e 100644 --- a/src/Util/SecureKey.php +++ b/src/Utils/SecureKey.php @@ -9,16 +9,19 @@ * @link http://github.com/php-loep/oauth2-server */ -namespace League\OAuth2\Server\Util; +namespace League\OAuth2\Server\Utils; -use League\OAuth2\Server\Util\KeyAlgorithm\DefaultAlgorithm; -use League\OAuth2\Server\Util\KeyAlgorithm\KeyAlgorithmInterface; +use League\OAuth2\Server\Utils\KeyAlgorithm\DefaultAlgorithm; +use League\OAuth2\Server\Utils\KeyAlgorithm\KeyAlgorithmInterface; /** * SecureKey class */ class SecureKey { + /** + * @var KeyAlgorithmInterface + */ protected static $algorithm; /** diff --git a/src/Utils/ServerAwareTrait.php b/src/Utils/ServerAwareTrait.php new file mode 100644 index 00000000..b25f6379 --- /dev/null +++ b/src/Utils/ServerAwareTrait.php @@ -0,0 +1,38 @@ +server = $server; + + return $this; + } + + /** + * Return the server + * + * @return \League\OAuth2\Server\AbstractServer + */ + protected function getServer() + { + return $this->server; + } +} \ No newline at end of file From 324b6db5e610bd2db9b2c04455752ba636c87e2d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 4 Apr 2015 15:42:26 +0100 Subject: [PATCH 007/444] Added league/container to dependencies --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 62639269..b73b4d6e 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,8 @@ "require": { "php": ">=5.4.0", "symfony/http-foundation": "~2.4", - "league/event": "1.0.*" + "league/event": "~2.1", + "league/container": "~1.0" }, "require-dev": { "phpunit/phpunit": "4.3.*", From 171be1c422a6a55acc7c3dae2c6b6d914c418c4f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 13:59:38 +0100 Subject: [PATCH 008/444] Updated .gitignore and .gitattributes --- .gitattributes | 5 ++--- .gitignore | 12 ------------ .../AbstractResponseType.php} | 0 .../BearerTokenResponseType.php} | 14 ++++++++++---- src/{TokenTypes => ResponseTypes}/MAC.php | 0 .../ResponseTypeInterface.php} | 0 6 files changed, 12 insertions(+), 19 deletions(-) rename src/{TokenTypes/AbstractTokenType.php => ResponseTypes/AbstractResponseType.php} (100%) rename src/{TokenTypes/Bearer.php => ResponseTypes/BearerTokenResponseType.php} (71%) rename src/{TokenTypes => ResponseTypes}/MAC.php (100%) rename src/{TokenTypes/TokenTypeInterface.php => ResponseTypes/ResponseTypeInterface.php} (100%) diff --git a/.gitattributes b/.gitattributes index 3819f5cd..cae05a90 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,4 @@ tests/ export-ignore phpunit.xml export-ignore -build.xml export-ignore -test export-ignore -.travis.yml export-ignore \ No newline at end of file +.travis.yml export-ignore +.scrutinizer.yml export-ignore \ No newline at end of file diff --git a/.gitignore b/.gitignore index 941a7dcf..3d7227d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,3 @@ /vendor /composer.lock -/build -/docs -/testing -/examples/relational/vendor -/examples/relational/config/oauth2.sqlite3 -/examples/nosql/vendor -/examples/nosql/config/oauth2.sqlite3 -/examples/relational/composer.lock -/tests/codecept/tests/_log -oauth2-server.paw -/output_*/ -/_site .idea \ No newline at end of file diff --git a/src/TokenTypes/AbstractTokenType.php b/src/ResponseTypes/AbstractResponseType.php similarity index 100% rename from src/TokenTypes/AbstractTokenType.php rename to src/ResponseTypes/AbstractResponseType.php diff --git a/src/TokenTypes/Bearer.php b/src/ResponseTypes/BearerTokenResponseType.php similarity index 71% rename from src/TokenTypes/Bearer.php rename to src/ResponseTypes/BearerTokenResponseType.php index 47e1a908..a132b53a 100644 --- a/src/TokenTypes/Bearer.php +++ b/src/ResponseTypes/BearerTokenResponseType.php @@ -11,9 +11,10 @@ namespace League\OAuth2\Server\TokenTypes; +use Period\Period; use Symfony\Component\HttpFoundation\Request; -class Bearer extends AbstractTokenType +class BearerTokenType extends AbstractTokenType { /** * {@inheritdoc} @@ -21,9 +22,12 @@ class Bearer extends AbstractTokenType public function generateResponse() { $return = [ - 'access_token' => $this->getParam('access_token'), - 'token_type' => 'Bearer', - 'expires_in' => $this->getParam('expires_in'), + 'access_token' => $this->accessToken->getIdentifier(), + 'token_type' => 'Bearer', + 'expires_in' => (new Period( + new \DateTime(), + $this->accessToken->getExpiryDateTime()) + )->getTimestampInterval(), ]; if (!is_null($this->getParam('refresh_token'))) { @@ -41,6 +45,8 @@ class Bearer extends AbstractTokenType $header = $request->headers->get('Authorization'); $accessToken = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header)); + // ^(?:\s+)?Bearer\s([a-zA-Z0-9-._~+/=]*) + return ($accessToken === 'Bearer') ? '' : $accessToken; } } diff --git a/src/TokenTypes/MAC.php b/src/ResponseTypes/MAC.php similarity index 100% rename from src/TokenTypes/MAC.php rename to src/ResponseTypes/MAC.php diff --git a/src/TokenTypes/TokenTypeInterface.php b/src/ResponseTypes/ResponseTypeInterface.php similarity index 100% rename from src/TokenTypes/TokenTypeInterface.php rename to src/ResponseTypes/ResponseTypeInterface.php From a48630c83765d442f1ba6caaf95638ecab39fdda Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 14:03:25 +0100 Subject: [PATCH 009/444] New entities, traits and interfaces --- src/Entities/AccessTokenEntity.php | 11 ++ src/Entities/AuthCodeEntity.php | 15 +++ src/Entities/ClientEntity.php | 15 +++ .../Interfaces/AccessTokenEntityInterface.php | 7 + .../Interfaces/AuthCodeEntityInterface.php | 7 + .../Interfaces/ClientEntityInterface.php | 42 ++++++ .../RefreshTokenEntityInterface.php | 17 +++ .../Interfaces/ScopeEntityInterface.php | 17 +++ src/Entities/Interfaces/TokenInterface.php | 79 +++++++++++ src/Entities/RefreshTokenEntity.php | 16 +++ src/Entities/ScopeEntity.php | 14 ++ src/Entities/Traits/ClientEntityTrait.php | 52 ++++++++ src/Entities/Traits/EntityTrait.php | 26 ++++ src/Entities/Traits/RefreshTokenTrait.php | 30 +++++ src/Entities/Traits/TokenEntityTrait.php | 126 ++++++++++++++++++ 15 files changed, 474 insertions(+) create mode 100644 src/Entities/AccessTokenEntity.php create mode 100644 src/Entities/AuthCodeEntity.php create mode 100644 src/Entities/ClientEntity.php create mode 100644 src/Entities/Interfaces/AccessTokenEntityInterface.php create mode 100644 src/Entities/Interfaces/AuthCodeEntityInterface.php create mode 100644 src/Entities/Interfaces/ClientEntityInterface.php create mode 100644 src/Entities/Interfaces/RefreshTokenEntityInterface.php create mode 100644 src/Entities/Interfaces/ScopeEntityInterface.php create mode 100644 src/Entities/Interfaces/TokenInterface.php create mode 100644 src/Entities/RefreshTokenEntity.php create mode 100644 src/Entities/ScopeEntity.php create mode 100644 src/Entities/Traits/ClientEntityTrait.php create mode 100644 src/Entities/Traits/EntityTrait.php create mode 100644 src/Entities/Traits/RefreshTokenTrait.php create mode 100644 src/Entities/Traits/TokenEntityTrait.php diff --git a/src/Entities/AccessTokenEntity.php b/src/Entities/AccessTokenEntity.php new file mode 100644 index 00000000..830c13e1 --- /dev/null +++ b/src/Entities/AccessTokenEntity.php @@ -0,0 +1,11 @@ +secret; + } + + /** + * Set the client's secret + * @param string $secret + * @return string + */ + public function setSecret($secret) + { + $this->secret = $secret; + } + + /** + * Get the client's name + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Set the client's name + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } +} \ No newline at end of file diff --git a/src/Entities/Traits/EntityTrait.php b/src/Entities/Traits/EntityTrait.php new file mode 100644 index 00000000..527506ac --- /dev/null +++ b/src/Entities/Traits/EntityTrait.php @@ -0,0 +1,26 @@ +identifier; + } + + /** + * @param mixed $identifier + */ + public function setIdentifier($identifier) + { + $this->identifier = $identifier; + } +} diff --git a/src/Entities/Traits/RefreshTokenTrait.php b/src/Entities/Traits/RefreshTokenTrait.php new file mode 100644 index 00000000..06f81808 --- /dev/null +++ b/src/Entities/Traits/RefreshTokenTrait.php @@ -0,0 +1,30 @@ +originalAccessToken = $accessToken; + } + + /** + * Get the access token that the refresh token was originally associated with + * @return \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface + */ + public function getOriginalAccessToken() + { + return $this->originalAccessToken; + } +} \ No newline at end of file diff --git a/src/Entities/Traits/TokenEntityTrait.php b/src/Entities/Traits/TokenEntityTrait.php new file mode 100644 index 00000000..bcd756bf --- /dev/null +++ b/src/Entities/Traits/TokenEntityTrait.php @@ -0,0 +1,126 @@ +scopes[$scope->getIdentifier()] = $scope; + } + + /** + * Get an associated scope by the scope's identifier + * @param string $identifier + * @return ScopeEntityInterface|null The scope or null if not found + */ + public function getScopeWithIdentifier($identifier) + { + return (isset($this->scopes[$identifier])) ? $this->scopes[$identifier] : null; + } + + /** + * Return an array of scopes associated with the token + * @return ScopeEntityInterface[] + */ + public function getScopes() + { + return $this->scopes; + } + + /** + * Get the token's expiry date time + * @return \DateTime + */ + public function getExpiryDateTime() + { + return $this->expiryDateTime; + } + + /** + * Set the date time when the token expires + * @param \DateTime $dateTime + */ + public function setExpiryDateTime(\DateTime $dateTime) + { + $this->expiryDateTime = $dateTime; + } + + /** + * Set the token's owner + * @param string $type The type of the owner (e.g. "user", "client" or something more specific) + * @param string|int $identifier The identifier of the owner + */ + public function setOwner($type, $identifier) + { + $this->ownerType = $type; + $this->ownerIdentifier = $identifier; + } + + /** + * Get the token owner's type + * @return string The type of owner (e.g. "user", "client" or something more specific) + */ + public function getOwnerType() + { + return $this->ownerType; + } + + /** + * Get the token owner's identifier + * @return string|int + */ + public function getOwnerIdentifier() + { + return $this->ownerIdentifier; + } + + /** + * Get the client that the token was issued to + * @return ClientEntityInterface + */ + public function getClient() + { + return $this->client; + } + + /** + * Set the client that the token was issued to + * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client + */ + public function setClient(ClientEntityInterface $client) + { + $this->client = $client; + } +} \ No newline at end of file From f3576020902fe731fefce0c919cee8dcfb63c71a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 14:03:34 +0100 Subject: [PATCH 010/444] Removed old traits --- src/Entity/AbstractTokenEntity.php | 209 -------------------- src/Entity/AccessTokenEntity.php | 93 --------- src/Entity/AuthCodeEntity.php | 128 ------------ src/Entity/ClientEntity.php | 111 ----------- src/Entity/EntityTrait.php | 33 ---- src/Entity/RefreshTokenEntity.php | 94 --------- src/Entity/ScopeEntity.php | 90 --------- src/Entity/SessionEntity.php | 308 ----------------------------- 8 files changed, 1066 deletions(-) delete mode 100644 src/Entity/AbstractTokenEntity.php delete mode 100644 src/Entity/AccessTokenEntity.php delete mode 100644 src/Entity/AuthCodeEntity.php delete mode 100644 src/Entity/ClientEntity.php delete mode 100644 src/Entity/EntityTrait.php delete mode 100644 src/Entity/RefreshTokenEntity.php delete mode 100644 src/Entity/ScopeEntity.php delete mode 100644 src/Entity/SessionEntity.php diff --git a/src/Entity/AbstractTokenEntity.php b/src/Entity/AbstractTokenEntity.php deleted file mode 100644 index 5f0465c3..00000000 --- a/src/Entity/AbstractTokenEntity.php +++ /dev/null @@ -1,209 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Entity; - -use League\OAuth2\Server\AbstractServer; -use League\OAuth2\Server\Util\SecureKey; - -/** - * Abstract token class - */ -abstract class AbstractTokenEntity -{ - /** - * Token identifier - * - * @var string - */ - protected $id; - - /** - * Associated session - * - * @var \League\OAuth2\Server\Entity\SessionEntity - */ - protected $session; - - /** - * Session scopes - * - * @var \League\OAuth2\Server\Entity\ScopeEntity[] - */ - protected $scopes; - - /** - * Token expire time - * - * @var int - */ - protected $expireTime = 0; - - /** - * Authorization or resource server - * - * @var \League\OAuth2\Server\AbstractServer - */ - protected $server; - - /** - * __construct - * - * @param \League\OAuth2\Server\AbstractServer $server - * - * @return self - */ - public function __construct(AbstractServer $server) - { - $this->server = $server; - - return $this; - } - - /** - * Set session - * - * @param \League\OAuth2\Server\Entity\SessionEntity $session - * - * @return self - */ - public function setSession(SessionEntity $session) - { - $this->session = $session; - - return $this; - } - - /** - * Set the expire time of the token - * - * @param integer $expireTime Unix time stamp - * - * @return self - */ - public function setExpireTime($expireTime) - { - $this->expireTime = $expireTime; - - return $this; - } - - /** - * Return token expire time - * - * @return int - */ - public function getExpireTime() - { - return $this->expireTime; - } - - /** - * Is the token expired? - * - * @return bool - */ - public function isExpired() - { - return ((time() - $this->expireTime) > 0); - } - - /** - * Set token ID - * - * @param string $id Token ID - * - * @return self - */ - public function setId($id = null) - { - $this->id = ($id !== null) ? $id : SecureKey::generate(); - - return $this; - } - - /** - * Get the token ID - * - * @return string - */ - public function getId() - { - return $this->id; - } - - /** - * Associate a scope - * - * @param \League\OAuth2\Server\Entity\ScopeEntity $scope - * - * @return self - */ - public function associateScope(ScopeEntity $scope) - { - if (!isset($this->scopes[$scope->getId()])) { - $this->scopes[$scope->getId()] = $scope; - } - - return $this; - } - - /** - * Format the local scopes array - * - * @param \League\OAuth2\Server\Entity\ScopeEntity[] - * - * @return array - */ - protected function formatScopes($unformatted = []) - { - if (is_null($unformatted)) { - return []; - } - - $scopes = []; - foreach ($unformatted as $scope) { - if ($scope instanceof ScopeEntity) { - $scopes[$scope->getId()] = $scope; - } - } - - return $scopes; - } - - /** - * Returns the token as a string if the object is cast as a string - * - * @return string - */ - public function __toString() - { - if ($this->id === null) { - return ''; - } - - return $this->id; - } - - /** - * Expire the token - * - * @return void - */ - abstract public function expire(); - - /** - * Save the token - * - * @return void - */ - abstract public function save(); -} diff --git a/src/Entity/AccessTokenEntity.php b/src/Entity/AccessTokenEntity.php deleted file mode 100644 index 7342b498..00000000 --- a/src/Entity/AccessTokenEntity.php +++ /dev/null @@ -1,93 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Entity; - -/** - * Access token entity class - */ -class AccessTokenEntity extends AbstractTokenEntity -{ - /** - * Get session - * - * @return \League\OAuth2\Server\Entity\SessionEntity - */ - public function getSession() - { - if ($this->session instanceof SessionEntity) { - return $this->session; - } - - $this->session = $this->server->getSessionStorage()->getByAccessToken($this); - - return $this->session; - } - - /** - * Check if access token has an associated scope - * - * @param string $scope Scope to check - * - * @return bool - */ - public function hasScope($scope) - { - if ($this->scopes === null) { - $this->getScopes(); - } - - return isset($this->scopes[$scope]); - } - - /** - * Return all scopes associated with the access token - * - * @return \League\OAuth2\Server\Entity\ScopeEntity[] - */ - public function getScopes() - { - if ($this->scopes === null) { - $this->scopes = $this->formatScopes( - $this->server->getAccessTokenStorage()->getScopes($this) - ); - } - - return $this->scopes; - } - - /** - * {@inheritdoc} - */ - public function save() - { - $this->server->getAccessTokenStorage()->create( - $this->getId(), - $this->getExpireTime(), - $this->getSession()->getId() - ); - - // Associate the scope with the token - foreach ($this->getScopes() as $scope) { - $this->server->getAccessTokenStorage()->associateScope($this, $scope); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function expire() - { - $this->server->getAccessTokenStorage()->delete($this); - } -} diff --git a/src/Entity/AuthCodeEntity.php b/src/Entity/AuthCodeEntity.php deleted file mode 100644 index ae106f7f..00000000 --- a/src/Entity/AuthCodeEntity.php +++ /dev/null @@ -1,128 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Entity; - -/** - * Access token entity class - */ -class AuthCodeEntity extends AbstractTokenEntity -{ - /** - * Redirect URI - * - * @var string - */ - protected $redirectUri = ''; - - /** - * Set the redirect URI for the authorization request - * - * @param string $redirectUri - * - * @return self - */ - public function setRedirectUri($redirectUri) - { - $this->redirectUri = $redirectUri; - - return $this; - } - - /** - * Get the redirect URI - * - * @return string - */ - public function getRedirectUri() - { - return $this->redirectUri; - } - - /** - * Generate a redirect URI - * - * @param string $state The state parameter if set by the client - * @param string $queryDelimeter The query delimiter ('?' for auth code grant, '#' for implicit grant) - * - * @return string - */ - public function generateRedirectUri($state = null, $queryDelimeter = '?') - { - $uri = $this->getRedirectUri(); - $uri .= (strstr($this->getRedirectUri(), $queryDelimeter) === false) ? $queryDelimeter : '&'; - - return $uri.http_build_query([ - 'code' => $this->getId(), - 'state' => $state, - ]); - } - - /** - * Get session - * - * @return \League\OAuth2\Server\Entity\SessionEntity - */ - public function getSession() - { - if ($this->session instanceof SessionEntity) { - return $this->session; - } - - $this->session = $this->server->getSessionStorage()->getByAuthCode($this); - - return $this->session; - } - - /** - * Return all scopes associated with the session - * - * @return \League\OAuth2\Server\Entity\ScopeEntity[] - */ - public function getScopes() - { - if ($this->scopes === null) { - $this->scopes = $this->formatScopes( - $this->server->getAuthCodeStorage()->getScopes($this) - ); - } - - return $this->scopes; - } - - /** - * {@inheritdoc} - */ - public function save() - { - $this->server->getAuthCodeStorage()->create( - $this->getId(), - $this->getExpireTime(), - $this->getSession()->getId(), - $this->getRedirectUri() - ); - - // Associate the scope with the token - foreach ($this->getScopes() as $scope) { - $this->server->getAuthCodeStorage()->associateScope($this, $scope); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function expire() - { - $this->server->getAuthCodeStorage()->delete($this); - } -} diff --git a/src/Entity/ClientEntity.php b/src/Entity/ClientEntity.php deleted file mode 100644 index b0e95285..00000000 --- a/src/Entity/ClientEntity.php +++ /dev/null @@ -1,111 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Entity; - -use League\OAuth2\Server\AbstractServer; - -/** - * Client entity class - */ -class ClientEntity -{ - use EntityTrait; - - /** - * Client identifier - * - * @var string - */ - protected $id = null; - - /** - * Client secret - * - * @var string - */ - protected $secret = null; - - /** - * Client name - * - * @var string - */ - protected $name = null; - - /** - * Client redirect URI - * - * @var string - */ - protected $redirectUri = null; - - /** - * Authorization or resource server - * - * @var \League\OAuth2\Server\AbstractServer - */ - protected $server; - - /** - * __construct - * - * @param \League\OAuth2\Server\AbstractServer $server - * - * @return self - */ - public function __construct(AbstractServer $server) - { - $this->server = $server; - - return $this; - } - - /** - * Return the client identifier - * - * @return string - */ - public function getId() - { - return $this->id; - } - - /** - * Return the client secret - * - * @return string - */ - public function getSecret() - { - return $this->secret; - } - - /** - * Get the client name - * - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * Returnt the client redirect URI - * - * @return string - */ - public function getRedirectUri() - { - return $this->redirectUri; - } -} diff --git a/src/Entity/EntityTrait.php b/src/Entity/EntityTrait.php deleted file mode 100644 index 9424fdfd..00000000 --- a/src/Entity/EntityTrait.php +++ /dev/null @@ -1,33 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Entity; - -trait EntityTrait -{ - /** - * Hydrate an entity with properites - * - * @param array $properties - * - * @return self - */ - public function hydrate(array $properties) - { - foreach ($properties as $prop => $val) { - if (property_exists($this, $prop)) { - $this->{$prop} = $val; - } - } - - return $this; - } -} diff --git a/src/Entity/RefreshTokenEntity.php b/src/Entity/RefreshTokenEntity.php deleted file mode 100644 index f1ec89a5..00000000 --- a/src/Entity/RefreshTokenEntity.php +++ /dev/null @@ -1,94 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Entity; - -/** - * Refresh token entity class - */ -class RefreshTokenEntity extends AbstractTokenEntity -{ - /** - * Access token associated to refresh token - * - * @var \League\OAuth2\Server\Entity\AccessTokenEntity - */ - protected $accessTokenEntity; - - /** - * Id of the access token - * - * @var string - */ - protected $accessTokenId; - - /** - * Set the ID of the associated access token - * - * @param string $accessTokenId - * - * @return self - */ - public function setAccessTokenId($accessTokenId) - { - $this->accessTokenId = $accessTokenId; - - return $this; - } - - /** - * Associate an access token - * - * @param \League\OAuth2\Server\Entity\AccessTokenEntity $accessTokenEntity - * - * @return self - */ - public function setAccessToken(AccessTokenEntity $accessTokenEntity) - { - $this->accessTokenEntity = $accessTokenEntity; - - return $this; - } - - /** - * Return access token - * - * @return AccessTokenEntity - */ - public function getAccessToken() - { - if (! $this->accessTokenEntity instanceof AccessTokenEntity) { - $this->accessTokenEntity = $this->server->getAccessTokenStorage()->get($this->accessTokenId); - } - - return $this->accessTokenEntity; - } - - /** - * {@inheritdoc} - */ - public function save() - { - $this->server->getRefreshTokenStorage()->create( - $this->getId(), - $this->getExpireTime(), - $this->getAccessToken()->getId() - ); - } - - /** - * {@inheritdoc} - */ - public function expire() - { - $this->server->getRefreshTokenStorage()->delete($this); - } -} diff --git a/src/Entity/ScopeEntity.php b/src/Entity/ScopeEntity.php deleted file mode 100644 index 1d5c946f..00000000 --- a/src/Entity/ScopeEntity.php +++ /dev/null @@ -1,90 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Entity; - -use League\OAuth2\Server\AbstractServer; - -/** - * Scope entity class - */ -class ScopeEntity implements \JsonSerializable -{ - use EntityTrait; - - /** - * Scope identifier - * - * @var string - */ - protected $id; - - /** - * Scope description - * - * @var string - */ - protected $description; - - /** - * Authorization or resource server - * - * @var \League\OAuth2\Server\AbstractServer - */ - protected $server; - - /** - * __construct - * - * @param \League\OAuth2\Server\AbstractServer $server - * - * @return self - */ - public function __construct(AbstractServer $server) - { - $this->server = $server; - - return $this; - } - - /** - * Return the scope identifer - * - * @return string - */ - public function getId() - { - return $this->id; - } - - /** - * Return the scope's description - * - * @return string - */ - public function getDescription() - { - return $this->description; - } - - /** - * Returns a JSON object when entity is passed into json_encode - * - * @return array - */ - public function jsonSerialize() - { - return [ - 'id' => $this->getId(), - 'description' => $this->getDescription() - ]; - } -} diff --git a/src/Entity/SessionEntity.php b/src/Entity/SessionEntity.php deleted file mode 100644 index c78cead5..00000000 --- a/src/Entity/SessionEntity.php +++ /dev/null @@ -1,308 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Entity; - -use League\OAuth2\Server\AbstractServer; -use League\OAuth2\Server\Event\SessionOwnerEvent; - -/** - * Session entity grant - */ -class SessionEntity -{ - /** - * Session identifier - * - * @var string - */ - protected $id; - - /** - * Client identifier - * - * @var \League\OAuth2\Server\Entity\ClientEntity - */ - protected $client; - - /** - * Session owner identifier - * - * @var string - */ - protected $ownerId; - - /** - * Session owner type (e.g. "user") - * - * @var string - */ - protected $ownerType; - - /** - * Auth code - * - * @var \League\OAuth2\Server\Entity\AuthCodeEntity - */ - protected $authCode; - - /** - * Access token - * - * @var \League\OAuth2\Server\Entity\AccessTokenEntity - */ - protected $accessToken; - - /** - * Refresh token - * - * @var \League\OAuth2\Server\Entity\RefreshTokenEntity - */ - protected $refreshToken; - - /** - * Session scopes - * - * @var \Symfony\Component\HttpFoundation\ParameterBag - */ - protected $scopes; - - /** - * Authorization or resource server - * - * @var \League\OAuth2\Server\AuthorizationServer|\League\OAuth2\Server\ResourceServer - */ - protected $server; - - /** - * __construct - * - * @param \League\OAuth2\Server\AbstractServer $server - * - * @return self - */ - public function __construct(AbstractServer $server) - { - $this->server = $server; - - return $this; - } - - /** - * Set the session identifier - * - * @param string $id - * - * @return self - */ - public function setId($id) - { - $this->id = $id; - - return $this; - } - - /** - * Return the session identifier - * - * @return string - */ - public function getId() - { - return $this->id; - } - - /** - * Associate a scope - * - * @param \League\OAuth2\Server\Entity\ScopeEntity $scope - * - * @return self - */ - public function associateScope(ScopeEntity $scope) - { - if (!isset($this->scopes[$scope->getId()])) { - $this->scopes[$scope->getId()] = $scope; - } - - return $this; - } - - /** - * Check if access token has an associated scope - * - * @param string $scope Scope to check - * - * @return bool - */ - public function hasScope($scope) - { - if ($this->scopes === null) { - $this->getScopes(); - } - - return isset($this->scopes[$scope]); - } - - /** - * Return all scopes associated with the session - * - * @return \League\OAuth2\Server\Entity\ScopeEntity[] - */ - public function getScopes() - { - if ($this->scopes === null) { - $this->scopes = $this->formatScopes($this->server->getSessionStorage()->getScopes($this)); - } - - return $this->scopes; - } - - /** - * Format the local scopes array - * - * @param \League\OAuth2\Server\Entity\Scope[] - * - * @return array - */ - private function formatScopes($unformatted = []) - { - $scopes = []; - if (is_array($unformatted)) { - foreach ($unformatted as $scope) { - if ($scope instanceof ScopeEntity) { - $scopes[$scope->getId()] = $scope; - } - } - } - - return $scopes; - } - - /** - * Associate an access token with the session - * - * @param \League\OAuth2\Server\Entity\AccessTokenEntity $accessToken - * - * @return self - */ - public function associateAccessToken(AccessTokenEntity $accessToken) - { - $this->accessToken = $accessToken; - - return $this; - } - - /** - * Associate a refresh token with the session - * - * @param \League\OAuth2\Server\Entity\RefreshTokenEntity $refreshToken - * - * @return self - */ - public function associateRefreshToken(RefreshTokenEntity $refreshToken) - { - $this->refreshToken = $refreshToken; - - return $this; - } - - /** - * Associate a client with the session - * - * @param \League\OAuth2\Server\Entity\ClientEntity $client The client - * - * @return self - */ - public function associateClient(ClientEntity $client) - { - $this->client = $client; - - return $this; - } - - /** - * Return the session client - * - * @return \League\OAuth2\Server\Entity\ClientEntity - */ - public function getClient() - { - if ($this->client instanceof ClientEntity) { - return $this->client; - } - - $this->client = $this->server->getClientStorage()->getBySession($this); - - return $this->client; - } - - /** - * Set the session owner - * - * @param string $type The type of the owner (e.g. user, app) - * @param string $id The identifier of the owner - * - * @return self - */ - public function setOwner($type, $id) - { - $this->ownerType = $type; - $this->ownerId = $id; - - $this->server->getEventEmitter()->emit(new SessionOwnerEvent($this)); - - return $this; - } - - /** - * Return session owner identifier - * - * @return string - */ - public function getOwnerId() - { - return $this->ownerId; - } - - /** - * Return session owner type - * - * @return string - */ - public function getOwnerType() - { - return $this->ownerType; - } - - /** - * Save the session - * - * @return void - */ - public function save() - { - // Save the session and get an identifier - $id = $this->server->getSessionStorage()->create( - $this->getOwnerType(), - $this->getOwnerId(), - $this->getClient()->getId(), - $this->getClient()->getRedirectUri() - ); - - $this->setId($id); - - // Associate the scope with the session - foreach ($this->getScopes() as $scope) { - $this->server->getSessionStorage()->associateScope($this, $scope); - } - } -} From a16a1dbb7d723cd3ea96b0a8941aec631c6599da Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 14:07:24 +0100 Subject: [PATCH 011/444] Removed old examples --- examples/relational/Model/Users.php | 25 -- .../relational/Storage/AccessTokenStorage.php | 93 ------- .../relational/Storage/AuthCodeStorage.php | 93 ------- examples/relational/Storage/ClientStorage.php | 70 ----- .../Storage/RefreshTokenStorage.php | 55 ---- examples/relational/Storage/ScopeStorage.php | 30 --- .../relational/Storage/SessionStorage.php | 109 -------- examples/relational/api.php | 135 ---------- examples/relational/authcode_grant.php | 117 -------- examples/relational/composer.json | 17 -- examples/relational/config/db.php | 18 -- examples/relational/config/init.php | 249 ------------------ examples/relational/other_grants.php | 97 ------- 13 files changed, 1108 deletions(-) delete mode 100644 examples/relational/Model/Users.php delete mode 100644 examples/relational/Storage/AccessTokenStorage.php delete mode 100644 examples/relational/Storage/AuthCodeStorage.php delete mode 100644 examples/relational/Storage/ClientStorage.php delete mode 100644 examples/relational/Storage/RefreshTokenStorage.php delete mode 100644 examples/relational/Storage/ScopeStorage.php delete mode 100644 examples/relational/Storage/SessionStorage.php delete mode 100644 examples/relational/api.php delete mode 100644 examples/relational/authcode_grant.php delete mode 100644 examples/relational/composer.json delete mode 100644 examples/relational/config/db.php delete mode 100644 examples/relational/config/init.php delete mode 100644 examples/relational/other_grants.php diff --git a/examples/relational/Model/Users.php b/examples/relational/Model/Users.php deleted file mode 100644 index 76caab85..00000000 --- a/examples/relational/Model/Users.php +++ /dev/null @@ -1,25 +0,0 @@ -select(['username', 'password', 'name', 'email', 'photo']); - - if ($username !== null) { - $query->where('username', '=', $username); - } - - $result = $query->get(); - - if (count($result) > 0) { - return $result; - } - - return; - } -} diff --git a/examples/relational/Storage/AccessTokenStorage.php b/examples/relational/Storage/AccessTokenStorage.php deleted file mode 100644 index 59e27362..00000000 --- a/examples/relational/Storage/AccessTokenStorage.php +++ /dev/null @@ -1,93 +0,0 @@ -where('access_token', $token) - ->get(); - - if (count($result) === 1) { - $token = (new AccessTokenEntity($this->server)) - ->setId($result[0]['access_token']) - ->setExpireTime($result[0]['expire_time']); - - return $token; - } - - return; - } - - /** - * {@inheritdoc} - */ - public function getScopes(AccessTokenEntity $token) - { - $result = Capsule::table('oauth_access_token_scopes') - ->select(['oauth_scopes.id', 'oauth_scopes.description']) - ->join('oauth_scopes', 'oauth_access_token_scopes.scope', '=', 'oauth_scopes.id') - ->where('access_token', $token->getId()) - ->get(); - - $response = []; - - if (count($result) > 0) { - foreach ($result as $row) { - $scope = (new ScopeEntity($this->server))->hydrate([ - 'id' => $row['id'], - 'description' => $row['description'], - ]); - $response[] = $scope; - } - } - - return $response; - } - - /** - * {@inheritdoc} - */ - public function create($token, $expireTime, $sessionId) - { - Capsule::table('oauth_access_tokens') - ->insert([ - 'access_token' => $token, - 'session_id' => $sessionId, - 'expire_time' => $expireTime, - ]); - } - - /** - * {@inheritdoc} - */ - public function associateScope(AccessTokenEntity $token, ScopeEntity $scope) - { - Capsule::table('oauth_access_token_scopes') - ->insert([ - 'access_token' => $token->getId(), - 'scope' => $scope->getId(), - ]); - } - - /** - * {@inheritdoc} - */ - public function delete(AccessTokenEntity $token) - { - Capsule::table('oauth_access_token_scopes') - ->where('access_token', $token->getId()) - ->delete(); - } -} diff --git a/examples/relational/Storage/AuthCodeStorage.php b/examples/relational/Storage/AuthCodeStorage.php deleted file mode 100644 index c0f84d9a..00000000 --- a/examples/relational/Storage/AuthCodeStorage.php +++ /dev/null @@ -1,93 +0,0 @@ -where('auth_code', $code) - ->where('expire_time', '>=', time()) - ->get(); - - if (count($result) === 1) { - $token = new AuthCodeEntity($this->server); - $token->setId($result[0]['auth_code']); - $token->setRedirectUri($result[0]['client_redirect_uri']); - $token->setExpireTime($result[0]['expire_time']); - - return $token; - } - - return; - } - - public function create($token, $expireTime, $sessionId, $redirectUri) - { - Capsule::table('oauth_auth_codes') - ->insert([ - 'auth_code' => $token, - 'client_redirect_uri' => $redirectUri, - 'session_id' => $sessionId, - 'expire_time' => $expireTime, - ]); - } - - /** - * {@inheritdoc} - */ - public function getScopes(AuthCodeEntity $token) - { - $result = Capsule::table('oauth_auth_code_scopes') - ->select(['oauth_scopes.id', 'oauth_scopes.description']) - ->join('oauth_scopes', 'oauth_auth_code_scopes.scope', '=', 'oauth_scopes.id') - ->where('auth_code', $token->getId()) - ->get(); - - $response = []; - - if (count($result) > 0) { - foreach ($result as $row) { - $scope = (new ScopeEntity($this->server))->hydrate([ - 'id' => $row['id'], - 'description' => $row['description'], - ]); - $response[] = $scope; - } - } - - return $response; - } - - /** - * {@inheritdoc} - */ - public function associateScope(AuthCodeEntity $token, ScopeEntity $scope) - { - Capsule::table('oauth_auth_code_scopes') - ->insert([ - 'auth_code' => $token->getId(), - 'scope' => $scope->getId(), - ]); - } - - /** - * {@inheritdoc} - */ - public function delete(AuthCodeEntity $token) - { - Capsule::table('oauth_auth_codes') - ->where('auth_code', $token->getId()) - ->delete(); - } -} diff --git a/examples/relational/Storage/ClientStorage.php b/examples/relational/Storage/ClientStorage.php deleted file mode 100644 index 9d62263d..00000000 --- a/examples/relational/Storage/ClientStorage.php +++ /dev/null @@ -1,70 +0,0 @@ -select('oauth_clients.*') - ->where('oauth_clients.id', $clientId); - - if ($clientSecret !== null) { - $query->where('oauth_clients.secret', $clientSecret); - } - - if ($redirectUri) { - $query->join('oauth_client_redirect_uris', 'oauth_clients.id', '=', 'oauth_client_redirect_uris.client_id') - ->select(['oauth_clients.*', 'oauth_client_redirect_uris.*']) - ->where('oauth_client_redirect_uris.redirect_uri', $redirectUri); - } - - $result = $query->get(); - - if (count($result) === 1) { - $client = new ClientEntity($this->server); - $client->hydrate([ - 'id' => $result[0]['id'], - 'name' => $result[0]['name'], - ]); - - return $client; - } - - return; - } - - /** - * {@inheritdoc} - */ - public function getBySession(SessionEntity $session) - { - $result = Capsule::table('oauth_clients') - ->select(['oauth_clients.id', 'oauth_clients.name']) - ->join('oauth_sessions', 'oauth_clients.id', '=', 'oauth_sessions.client_id') - ->where('oauth_sessions.id', $session->getId()) - ->get(); - - if (count($result) === 1) { - $client = new ClientEntity($this->server); - $client->hydrate([ - 'id' => $result[0]['id'], - 'name' => $result[0]['name'], - ]); - - return $client; - } - - return; - } -} diff --git a/examples/relational/Storage/RefreshTokenStorage.php b/examples/relational/Storage/RefreshTokenStorage.php deleted file mode 100644 index 580efaf1..00000000 --- a/examples/relational/Storage/RefreshTokenStorage.php +++ /dev/null @@ -1,55 +0,0 @@ -where('refresh_token', $token) - ->get(); - - if (count($result) === 1) { - $token = (new RefreshTokenEntity($this->server)) - ->setId($result[0]['refresh_token']) - ->setExpireTime($result[0]['expire_time']) - ->setAccessTokenId($result[0]['access_token']); - - return $token; - } - - return; - } - - /** - * {@inheritdoc} - */ - public function create($token, $expireTime, $accessToken) - { - Capsule::table('oauth_refresh_tokens') - ->insert([ - 'refresh_token' => $token, - 'access_token' => $accessToken, - 'expire_time' => $expireTime, - ]); - } - - /** - * {@inheritdoc} - */ - public function delete(RefreshTokenEntity $token) - { - Capsule::table('oauth_refresh_tokens') - ->where('refresh_token', $token->getId()) - ->delete(); - } -} diff --git a/examples/relational/Storage/ScopeStorage.php b/examples/relational/Storage/ScopeStorage.php deleted file mode 100644 index 4a6dd20e..00000000 --- a/examples/relational/Storage/ScopeStorage.php +++ /dev/null @@ -1,30 +0,0 @@ -where('id', $scope) - ->get(); - - if (count($result) === 0) { - return; - } - - return (new ScopeEntity($this->server))->hydrate([ - 'id' => $result[0]['id'], - 'description' => $result[0]['description'], - ]); - } -} diff --git a/examples/relational/Storage/SessionStorage.php b/examples/relational/Storage/SessionStorage.php deleted file mode 100644 index 612b1489..00000000 --- a/examples/relational/Storage/SessionStorage.php +++ /dev/null @@ -1,109 +0,0 @@ -select(['oauth_sessions.id', 'oauth_sessions.owner_type', 'oauth_sessions.owner_id', 'oauth_sessions.client_id', 'oauth_sessions.client_redirect_uri']) - ->join('oauth_access_tokens', 'oauth_access_tokens.session_id', '=', 'oauth_sessions.id') - ->where('oauth_access_tokens.access_token', $accessToken->getId()) - ->get(); - - if (count($result) === 1) { - $session = new SessionEntity($this->server); - $session->setId($result[0]['id']); - $session->setOwner($result[0]['owner_type'], $result[0]['owner_id']); - - return $session; - } - - return; - } - - /** - * {@inheritdoc} - */ - public function getByAuthCode(AuthCodeEntity $authCode) - { - $result = Capsule::table('oauth_sessions') - ->select(['oauth_sessions.id', 'oauth_sessions.owner_type', 'oauth_sessions.owner_id', 'oauth_sessions.client_id', 'oauth_sessions.client_redirect_uri']) - ->join('oauth_auth_codes', 'oauth_auth_codes.session_id', '=', 'oauth_sessions.id') - ->where('oauth_auth_codes.auth_code', $authCode->getId()) - ->get(); - - if (count($result) === 1) { - $session = new SessionEntity($this->server); - $session->setId($result[0]['id']); - $session->setOwner($result[0]['owner_type'], $result[0]['owner_id']); - - return $session; - } - - return; - } - - /** - * {@inheritdoc} - */ - public function getScopes(SessionEntity $session) - { - $result = Capsule::table('oauth_sessions') - ->select('oauth_scopes.*') - ->join('oauth_session_scopes', 'oauth_sessions.id', '=', 'oauth_session_scopes.session_id') - ->join('oauth_scopes', 'oauth_scopes.id', '=', 'oauth_session_scopes.scope') - ->where('oauth_sessions.id', $session->getId()) - ->get(); - - $scopes = []; - - foreach ($result as $scope) { - $scopes[] = (new ScopeEntity($this->server))->hydrate([ - 'id' => $scope['id'], - 'description' => $scope['description'], - ]); - } - - return $scopes; - } - - /** - * {@inheritdoc} - */ - public function create($ownerType, $ownerId, $clientId, $clientRedirectUri = null) - { - $id = Capsule::table('oauth_sessions') - ->insertGetId([ - 'owner_type' => $ownerType, - 'owner_id' => $ownerId, - 'client_id' => $clientId, - ]); - - return $id; - } - - /** - * {@inheritdoc} - */ - public function associateScope(SessionEntity $session, ScopeEntity $scope) - { - Capsule::table('oauth_session_scopes') - ->insert([ - 'session_id' => $session->getId(), - 'scope' => $scope->getId(), - ]); - } -} diff --git a/examples/relational/api.php b/examples/relational/api.php deleted file mode 100644 index 2731aa24..00000000 --- a/examples/relational/api.php +++ /dev/null @@ -1,135 +0,0 @@ -createFromGlobals(); -$router = new \Orno\Route\RouteCollection(); -$router->setStrategy(\Orno\Route\RouteStrategyInterface::RESTFUL_STRATEGY); - -// Set up the OAuth 2.0 resource server -$sessionStorage = new Storage\SessionStorage(); -$accessTokenStorage = new Storage\AccessTokenStorage(); -$clientStorage = new Storage\ClientStorage(); -$scopeStorage = new Storage\ScopeStorage(); - -$server = new ResourceServer( - $sessionStorage, - $accessTokenStorage, - $clientStorage, - $scopeStorage -); - -// Routing setup -$request = (new Request())->createFromGlobals(); -$router = new \Orno\Route\RouteCollection(); - -// GET /tokeninfo -$router->get('/tokeninfo', function (Request $request) use ($server) { - - $accessToken = $server->getAccessToken(); - $session = $server->getSessionStorage()->getByAccessToken($accessToken); - $token = [ - 'owner_id' => $session->getOwnerId(), - 'owner_type' => $session->getOwnerType(), - 'access_token' => $accessToken, - 'client_id' => $session->getClient()->getId(), - 'scopes' => $accessToken->getScopes(), - ]; - - return new Response(json_encode($token)); - -}); - -// GET /users -$router->get('/users', function (Request $request) use ($server) { - - $results = (new Model\Users())->get(); - - $users = []; - - foreach ($results as $result) { - $user = [ - 'username' => $result['username'], - 'name' => $result['name'], - ]; - - if ($server->getAccessToken()->hasScope('email')) { - $user['email'] = $result['email']; - } - - if ($server->getAccessToken()->hasScope('photo')) { - $user['photo'] = $result['photo']; - } - - $users[] = $user; - } - - return new Response(json_encode($users)); -}); - -// GET /users/{username} -$router->get('/users/{username}', function (Request $request, Response $response, array $args) use ($server) { - - $result = (new Model\Users())->get($args['username']); - - if (count($result) === 0) { - throw new NotFoundException(); - } - - $user = [ - 'username' => $result[0]['username'], - 'name' => $result[0]['name'], - ]; - - if ($server->getAccessToken()->hasScope('email')) { - $user['email'] = $result[0]['email']; - } - - if ($server->getAccessToken()->hasScope('photo')) { - $user['photo'] = $result[0]['photo']; - } - - return new Response(json_encode($user)); -}); - -$dispatcher = $router->getDispatcher(); - -try { - // Check that access token is present - $server->isValidRequest(false); - - // A successful response - $response = $dispatcher->dispatch( - $request->getMethod(), - $request->getPathInfo() - ); -} catch (\Orno\Http\Exception $e) { - // A failed response - $response = $e->getJsonResponse(); - $response->setContent(json_encode(['status_code' => $e->getStatusCode(), 'message' => $e->getMessage()])); -} catch (\League\OAuth2\Server\Exception\OAuthException $e) { - $response = new Response(json_encode([ - 'error' => $e->errorType, - 'message' => $e->getMessage(), - ]), $e->httpStatusCode); - - foreach ($e->getHttpHeaders() as $header) { - $response->headers($header); - } -} catch (\Exception $e) { - $response = new Orno\Http\Response(); - $response->setStatusCode(500); - $response->setContent(json_encode(['status_code' => 500, 'message' => $e->getMessage()])); -} finally { - // Return the response - $response->headers->set('Content-type', 'application/json'); - $response->send(); -} diff --git a/examples/relational/authcode_grant.php b/examples/relational/authcode_grant.php deleted file mode 100644 index 380025e6..00000000 --- a/examples/relational/authcode_grant.php +++ /dev/null @@ -1,117 +0,0 @@ -createFromGlobals(); -$router = new \Orno\Route\RouteCollection(); -$router->setStrategy(\Orno\Route\RouteStrategyInterface::RESTFUL_STRATEGY); - -// Set up the OAuth 2.0 authorization server -$server = new \League\OAuth2\Server\AuthorizationServer(); -$server->setSessionStorage(new Storage\SessionStorage()); -$server->setAccessTokenStorage(new Storage\AccessTokenStorage()); -$server->setRefreshTokenStorage(new Storage\RefreshTokenStorage()); -$server->setClientStorage(new Storage\ClientStorage()); -$server->setScopeStorage(new Storage\ScopeStorage()); -$server->setAuthCodeStorage(new Storage\AuthCodeStorage()); - -$authCodeGrant = new \League\OAuth2\Server\Grant\AuthCodeGrant(); -$server->addGrantType($authCodeGrant); - -$refrehTokenGrant = new \League\OAuth2\Server\Grant\RefreshTokenGrant(); -$server->addGrantType($refrehTokenGrant); - -// Routing setup -$request = (new Request())->createFromGlobals(); -$router = new \Orno\Route\RouteCollection(); - -$router->get('/authorize', function (Request $request) use ($server) { - - // First ensure the parameters in the query string are correct - - try { - $authParams = $server->getGrantType('authorization_code')->checkAuthorizeParams(); - } catch (\Exception $e) { - return new Response( - json_encode([ - 'error' => $e->errorType, - 'message' => $e->getMessage(), - ]), - $e->httpStatusCode, - $e->getHttpHeaders() - ); - } - - // Normally at this point you would show the user a sign-in screen and ask them to authorize the requested scopes - - // ... - - // ... - - // ... - - // Create a new authorize request which will respond with a redirect URI that the user will be redirected to - - $redirectUri = $server->getGrantType('authorization_code')->newAuthorizeRequest('user', 1, $authParams); - - $response = new Response('', 200, [ - 'Location' => $redirectUri - ]); - - return $response; -}); - -$router->post('/access_token', function (Request $request) use ($server) { - - try { - $response = $server->issueAccessToken(); - - return new Response(json_encode($response), 200); - } catch (\Exception $e) { - return new Response( - json_encode([ - 'error' => $e->errorType, - 'message' => $e->getMessage(), - ]), - $e->httpStatusCode, - $e->getHttpHeaders() - ); - } - -}); - -$dispatcher = $router->getDispatcher(); - -try { - // A successful response - $response = $dispatcher->dispatch( - $request->getMethod(), - $request->getPathInfo() - ); -} catch (\Orno\Http\Exception $e) { - // A failed response - $response = $e->getJsonResponse(); - $response->setContent(json_encode(['status_code' => $e->getStatusCode(), 'message' => $e->getMessage()])); -} catch (\League\OAuth2\Server\Exception\OAuthException $e) { - $response = new Response(json_encode([ - 'error' => $e->errorType, - 'message' => $e->getMessage(), - ]), $e->httpStatusCode); - - foreach ($e->getHttpHeaders() as $header) { - $response->headers($header); - } -} catch (\Exception $e) { - $response = new Orno\Http\Response(); - $response->setStatusCode(500); - $response->setContent(json_encode(['status_code' => 500, 'message' => $e->getMessage()])); -} finally { - // Return the response - $response->headers->set('Content-type', 'application/json'); - $response->send(); -} diff --git a/examples/relational/composer.json b/examples/relational/composer.json deleted file mode 100644 index 34bd57cf..00000000 --- a/examples/relational/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "require": { - "illuminate/database": "4.1.*", - "orno/route": "1.*", - "ircmaxell/password-compat": "1.0.2", - "league/event": "0.2.0" - }, - "autoload": { - "psr-4": { - "League\\OAuth2\\Server\\": "../../src/", - "RelationalExample\\": "." - }, - "files": [ - "config/db.php" - ] - } -} \ No newline at end of file diff --git a/examples/relational/config/db.php b/examples/relational/config/db.php deleted file mode 100644 index de883979..00000000 --- a/examples/relational/config/db.php +++ /dev/null @@ -1,18 +0,0 @@ -addConnection([ - 'driver' => 'sqlite', - 'database' => __DIR__.'/oauth2.sqlite3', - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', -]); - -$capsule->setAsGlobal(); diff --git a/examples/relational/config/init.php b/examples/relational/config/init.php deleted file mode 100644 index 85ba40f0..00000000 --- a/examples/relational/config/init.php +++ /dev/null @@ -1,249 +0,0 @@ -create('users', function ($table) { - $table->increments('id'); - $table->string('username'); - $table->string('password'); - $table->string('name'); - $table->string('email'); - $table->string('photo'); -}); - -Capsule::table('users')->insert([ - 'username' => 'alexbilbie', - 'password' => password_hash('whisky', PASSWORD_DEFAULT), - 'name' => 'Alex Bilbie', - 'email' => 'hello@alexbilbie.com', - 'photo' => 'https://s.gravatar.com/avatar/14902eb1dac66b8458ebbb481d80f0a3', -]); - -Capsule::table('users')->insert([ - 'username' => 'philsturgeon', - 'password' => password_hash('cider', PASSWORD_DEFAULT), - 'name' => 'Phil Sturgeon', - 'email' => 'email@philsturgeon.co.uk', - 'photo' => 'https://s.gravatar.com/avatar/14df293d6c5cd6f05996dfc606a6a951', -]); - -/******************************************************************************/ - -print 'Creating clients table'.PHP_EOL; - -Capsule::schema()->create('oauth_clients', function ($table) { - $table->string('id'); - $table->string('secret'); - $table->string('name'); - $table->primary('id'); -}); - -Capsule::table('oauth_clients')->insert([ - 'id' => 'testclient', - 'secret' => 'secret', - 'name' => 'Test Client', -]); - -/******************************************************************************/ - -print 'Creating client redirect uris table'.PHP_EOL; - -Capsule::schema()->create('oauth_client_redirect_uris', function ($table) { - $table->increments('id'); - $table->string('client_id'); - $table->string('redirect_uri'); -}); - -Capsule::table('oauth_client_redirect_uris')->insert([ - 'client_id' => 'testclient', - 'redirect_uri' => 'http://example.com/redirect', -]); - -/******************************************************************************/ - -print 'Creating scopes table'.PHP_EOL; - -Capsule::schema()->create('oauth_scopes', function ($table) { - $table->string('id'); - $table->string('description'); - $table->primary('id'); -}); - -Capsule::table('oauth_scopes')->insert([ - 'id' => 'basic', - 'description' => 'Basic details about your account', -]); - -Capsule::table('oauth_scopes')->insert([ - 'id' => 'email', - 'description' => 'Your email address', -]); - -Capsule::table('oauth_scopes')->insert([ - 'id' => 'photo', - 'description' => 'Your photo', -]); - -/******************************************************************************/ - -print 'Creating sessions table'.PHP_EOL; - -Capsule::schema()->create('oauth_sessions', function ($table) { - $table->increments('id')->unsigned(); - $table->string('owner_type'); - $table->string('owner_id'); - $table->string('client_id'); - $table->string('client_redirect_uri')->nullable(); - - $table->foreign('client_id')->references('id')->on('oauth_clients')->onDelete('cascade'); -}); - -Capsule::table('oauth_sessions')->insert([ - 'owner_type' => 'client', - 'owner_id' => 'testclient', - 'client_id' => 'testclient', -]); - -Capsule::table('oauth_sessions')->insert([ - 'owner_type' => 'user', - 'owner_id' => '1', - 'client_id' => 'testclient', -]); - -Capsule::table('oauth_sessions')->insert([ - 'owner_type' => 'user', - 'owner_id' => '2', - 'client_id' => 'testclient', -]); - -/******************************************************************************/ - -print 'Creating access tokens table'.PHP_EOL; - -Capsule::schema()->create('oauth_access_tokens', function ($table) { - $table->string('access_token')->primary(); - $table->integer('session_id')->unsigned(); - $table->integer('expire_time'); - - $table->foreign('session_id')->references('id')->on('oauth_sessions')->onDelete('cascade'); -}); - -Capsule::table('oauth_access_tokens')->insert([ - 'access_token' => 'iamgod', - 'session_id' => '1', - 'expire_time' => time() + 86400, -]); - -Capsule::table('oauth_access_tokens')->insert([ - 'access_token' => 'iamalex', - 'session_id' => '2', - 'expire_time' => time() + 86400, -]); - -Capsule::table('oauth_access_tokens')->insert([ - 'access_token' => 'iamphil', - 'session_id' => '3', - 'expire_time' => time() + 86400, -]); - -/******************************************************************************/ - -print 'Creating refresh tokens table'.PHP_EOL; - -Capsule::schema()->create('oauth_refresh_tokens', function ($table) { - $table->string('refresh_token')->primary(); - $table->integer('expire_time'); - $table->string('access_token'); - - $table->foreign('access_token')->references('access_token')->on('oauth_access_tokens')->onDelete('cascade'); -}); - -/******************************************************************************/ - -print 'Creating auth codes table'.PHP_EOL; - -Capsule::schema()->create('oauth_auth_codes', function ($table) { - $table->string('auth_code')->primary(); - $table->integer('session_id')->unsigned(); - $table->integer('expire_time'); - $table->string('client_redirect_uri'); - - $table->foreign('session_id')->references('id')->on('oauth_sessions')->onDelete('cascade'); -}); - -/******************************************************************************/ - -print 'Creating oauth access token scopes table'.PHP_EOL; - -Capsule::schema()->create('oauth_access_token_scopes', function ($table) { - $table->increments('id')->unsigned(); - $table->string('access_token'); - $table->string('scope'); - - $table->foreign('access_token')->references('access_token')->on('oauth_access_tokens')->onDelete('cascade'); - $table->foreign('scope')->references('id')->on('oauth_scopes')->onDelete('cascade'); -}); - -Capsule::table('oauth_access_token_scopes')->insert([ - 'access_token' => 'iamgod', - 'scope' => 'basic', -]); - -Capsule::table('oauth_access_token_scopes')->insert([ - 'access_token' => 'iamgod', - 'scope' => 'email', -]); - -Capsule::table('oauth_access_token_scopes')->insert([ - 'access_token' => 'iamgod', - 'scope' => 'photo', -]); - -Capsule::table('oauth_access_token_scopes')->insert([ - 'access_token' => 'iamphil', - 'scope' => 'email', -]); - -Capsule::table('oauth_access_token_scopes')->insert([ - 'access_token' => 'iamalex', - 'scope' => 'photo', -]); - -/******************************************************************************/ - -print 'Creating oauth auth code scopes table'.PHP_EOL; - -Capsule::schema()->create('oauth_auth_code_scopes', function ($table) { - $table->increments('id'); - $table->string('auth_code'); - $table->string('scope'); - - $table->foreign('auth_code')->references('auth_code')->on('oauth_auth_codes')->onDelete('cascade'); - $table->foreign('scope')->references('id')->on('oauth_scopes')->onDelete('cascade'); -}); - -/******************************************************************************/ - -print 'Creating oauth session scopes table'.PHP_EOL; - -Capsule::schema()->create('oauth_session_scopes', function ($table) { - $table->increments('id')->unsigned(); - $table->integer('session_id')->unsigned(); - $table->string('scope'); - - $table->foreign('session_id')->references('id')->on('oauth_sessions')->onDelete('cascade'); - $table->foreign('scope')->references('id')->on('oauth_scopes')->onDelete('cascade'); -}); diff --git a/examples/relational/other_grants.php b/examples/relational/other_grants.php deleted file mode 100644 index a59d201e..00000000 --- a/examples/relational/other_grants.php +++ /dev/null @@ -1,97 +0,0 @@ -createFromGlobals(); -$router = new \Orno\Route\RouteCollection(); -$router->setStrategy(\Orno\Route\RouteStrategyInterface::RESTFUL_STRATEGY); - -// Set up the OAuth 2.0 authorization server -$server = new \League\OAuth2\Server\AuthorizationServer(); -$server->setSessionStorage(new Storage\SessionStorage()); -$server->setAccessTokenStorage(new Storage\AccessTokenStorage()); -$server->setRefreshTokenStorage(new Storage\RefreshTokenStorage()); -$server->setClientStorage(new Storage\ClientStorage()); -$server->setScopeStorage(new Storage\ScopeStorage()); -$server->setAuthCodeStorage(new Storage\AuthCodeStorage()); - -$clientCredentials = new \League\OAuth2\Server\Grant\ClientCredentialsGrant(); -$server->addGrantType($clientCredentials); - -$passwordGrant = new \League\OAuth2\Server\Grant\PasswordGrant(); -$passwordGrant->setVerifyCredentialsCallback(function ($username, $password) { - $result = (new Model\Users())->get($username); - if (count($result) !== 1) { - return false; - } - - if (password_verify($password, $result[0]['password'])) { - return $username; - } - - return false; -}); -$server->addGrantType($passwordGrant); - -$refrehTokenGrant = new \League\OAuth2\Server\Grant\RefreshTokenGrant(); -$server->addGrantType($refrehTokenGrant); - -// Routing setup -$request = (new Request())->createFromGlobals(); -$router = new \Orno\Route\RouteCollection(); - -$router->post('/access_token', function (Request $request) use ($server) { - - try { - $response = $server->issueAccessToken(); - - return new Response(json_encode($response), 200); - } catch (\Exception $e) { - return new Response( - json_encode([ - 'error' => $e->errorType, - 'message' => $e->getMessage(), - ]), - $e->httpStatusCode, - $e->getHttpHeaders() - ); - } - -}); - -$dispatcher = $router->getDispatcher(); - -try { - // A successful response - $response = $dispatcher->dispatch( - $request->getMethod(), - $request->getPathInfo() - ); -} catch (\Orno\Http\Exception $e) { - // A failed response - $response = $e->getJsonResponse(); - $response->setContent(json_encode(['status_code' => $e->getStatusCode(), 'message' => $e->getMessage()])); -} catch (\League\OAuth2\Server\Exception\OAuthException $e) { - $response = new Response(json_encode([ - 'error' => $e->errorType, - 'message' => $e->getMessage(), - ]), $e->httpStatusCode); - - foreach ($e->getHttpHeaders() as $header) { - $response->headers($header); - } -} catch (\Exception $e) { - $response = new Orno\Http\Response(); - $response->setStatusCode(500); - $response->setContent(json_encode(['status_code' => 500, 'message' => $e->getMessage()])); -} finally { - // Return the response - $response->headers->set('Content-type', 'application/json'); - $response->send(); -} From 5fcf01f4c8bd2ff215d369dbac6115b90c3848e3 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 17:00:01 +0100 Subject: [PATCH 012/444] Updated composer dev requirements --- composer.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b73b4d6e..42950d9a 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,9 @@ }, "require-dev": { "phpunit/phpunit": "4.3.*", - "mockery/mockery": "0.9.*" + "mockery/mockery": "0.9.*", + "codeception/codeception": "~2.0", + "flow/jsonpath": "0.2.*" }, "repositories": [ { From 3721ecb40aed0095210d68784063a98e86aa8b11 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 17:00:43 +0100 Subject: [PATCH 013/444] Updated repository interfaces --- src/Repositories/AbstractRepository.php | 51 ------------- .../AccessTokenRepositoryInterface.php | 44 +++++------- src/Repositories/ClientInterface.php | 41 ----------- .../ClientRepositoryInterface.php | 30 ++++++++ src/Repositories/RepositoryInterface.php | 19 +++++ src/Repositories/ScopeInterface.php | 29 -------- src/Repositories/ScopeRepositoryInterface.php | 29 ++++++++ src/Repositories/SessionInterface.php | 72 ------------------- src/Repositories/StorageInterface.php | 27 ------- 9 files changed, 96 insertions(+), 246 deletions(-) delete mode 100644 src/Repositories/AbstractRepository.php delete mode 100644 src/Repositories/ClientInterface.php create mode 100644 src/Repositories/ClientRepositoryInterface.php create mode 100644 src/Repositories/RepositoryInterface.php delete mode 100644 src/Repositories/ScopeInterface.php create mode 100644 src/Repositories/ScopeRepositoryInterface.php delete mode 100644 src/Repositories/SessionInterface.php delete mode 100644 src/Repositories/StorageInterface.php diff --git a/src/Repositories/AbstractRepository.php b/src/Repositories/AbstractRepository.php deleted file mode 100644 index 2bfb5601..00000000 --- a/src/Repositories/AbstractRepository.php +++ /dev/null @@ -1,51 +0,0 @@ - - * @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\AbstractServer; - -/** - * Abstract storage class - */ -abstract class AbstractStorage implements StorageInterface -{ - /** - * Server - * - * @var \League\OAuth2\Server\AbstractServer $server - */ - protected $server; - - /** - * Set the server - * - * @param \League\OAuth2\Server\AbstractServer $server - * - * @return self - */ - public function setServer(AbstractServer $server) - { - $this->server = $server; - - return $this; - } - - /** - * Return the server - * - * @return \League\OAuth2\Server\AbstractServer - */ - protected function getServer() - { - return $this->server; - } -} diff --git a/src/Repositories/AccessTokenRepositoryInterface.php b/src/Repositories/AccessTokenRepositoryInterface.php index 5f852b80..41e3011c 100644 --- a/src/Repositories/AccessTokenRepositoryInterface.php +++ b/src/Repositories/AccessTokenRepositoryInterface.php @@ -9,61 +9,53 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\Storage; +namespace League\OAuth2\Server\Repositories; -use League\OAuth2\Server\Entity\AccessTokenEntity; -use League\OAuth2\Server\Entity\ScopeEntity; +use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; /** * Access token interface */ -interface AccessTokenInterface extends StorageInterface +interface AccessTokenRepositoryInterface extends RepositoryInterface { /** * Get an instance of Entity\AccessTokenEntity * - * @param string $token The access token + * @param string $tokenIdentifier The access token identifier * - * @return \League\OAuth2\Server\Entity\AccessTokenEntity + * @return \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface */ - public function get($token); + public function get($tokenIdentifier); /** * Get the scopes for an access token * - * @param \League\OAuth2\Server\Entity\AccessTokenEntity $token The access token + * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $token * - * @return array Array of \League\OAuth2\Server\Entity\ScopeEntity + * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] */ - public function getScopes(AccessTokenEntity $token); + public function getScopes(AccessTokenEntityInterface $token); /** * Creates a new access token * - * @param string $token The access token - * @param integer $expireTime The expire time expressed as a unix timestamp - * @param string|integer $sessionId The session ID - * - * @return void + * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessTokenEntity */ - public function create($token, $expireTime, $sessionId); + public function create(AccessTokenEntityInterface $accessTokenEntity); /** - * Associate a scope with an acess token + * Associate a scope with an access token * - * @param \League\OAuth2\Server\Entity\AccessTokenEntity $token The access token - * @param \League\OAuth2\Server\Entity\ScopeEntity $scope The scope - * - * @return void + * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessTokenEntityInterface + * @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface $scope */ - public function associateScope(AccessTokenEntity $token, ScopeEntity $scope); + public function associateScope(AccessTokenEntityInterface $accessTokenEntityInterface, ScopeEntityInterface $scope); /** * Delete an access token * - * @param \League\OAuth2\Server\Entity\AccessTokenEntity $token The access token to delete - * - * @return void + * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken */ - public function delete(AccessTokenEntity $token); + public function delete(AccessTokenEntityInterface $accessToken); } diff --git a/src/Repositories/ClientInterface.php b/src/Repositories/ClientInterface.php deleted file mode 100644 index 4e9cc39a..00000000 --- a/src/Repositories/ClientInterface.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @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\Entity\SessionEntity; - -/** - * Client storage interface - */ -interface ClientInterface extends StorageInterface -{ - /** - * Validate a client - * - * @param string $clientId The client's ID - * @param string $clientSecret The client's secret (default = "null") - * @param string $redirectUri The client's redirect URI (default = "null") - * @param string $grantType The grant type used (default = "null") - * - * @return \League\OAuth2\Server\Entity\ClientEntity - */ - public function get($clientId, $clientSecret = null, $redirectUri = null, $grantType = null); - - /** - * Get the client associated with a session - * - * @param \League\OAuth2\Server\Entity\SessionEntity $session The session - * - * @return \League\OAuth2\Server\Entity\ClientEntity - */ - public function getBySession(SessionEntity $session); -} diff --git a/src/Repositories/ClientRepositoryInterface.php b/src/Repositories/ClientRepositoryInterface.php new file mode 100644 index 00000000..09360909 --- /dev/null +++ b/src/Repositories/ClientRepositoryInterface.php @@ -0,0 +1,30 @@ + + * @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 + */ +interface ClientRepositoryInterface extends RepositoryInterface +{ + /** + * Get a client + * + * @param string $clientIdentifier The client's identifier + * @param string $clientSecret The client's secret (default = "null") + * @param string $redirectUri The client's redirect URI (default = "null") + * @param string $grantType The grant type used (default = "null") + * + * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface + */ + public function get($clientIdentifier, $clientSecret = null, $redirectUri = null, $grantType = null); +} diff --git a/src/Repositories/RepositoryInterface.php b/src/Repositories/RepositoryInterface.php new file mode 100644 index 00000000..030c116f --- /dev/null +++ b/src/Repositories/RepositoryInterface.php @@ -0,0 +1,19 @@ + + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * @link https://github.com/thephpleague/oauth2-server + */ + +namespace League\OAuth2\Server\Repositories; + +/** + * Repository interface + */ +interface RepositoryInterface +{ +} diff --git a/src/Repositories/ScopeInterface.php b/src/Repositories/ScopeInterface.php deleted file mode 100644 index e8bc10b0..00000000 --- a/src/Repositories/ScopeInterface.php +++ /dev/null @@ -1,29 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Storage; - -/** - * Scope interface - */ -interface ScopeInterface extends StorageInterface -{ - /** - * Return information about a scope - * - * @param string $scope The scope - * @param string $grantType The grant type used in the request (default = "null") - * @param string $clientId The client sending the request (default = "null") - * - * @return \League\OAuth2\Server\Entity\ScopeEntity - */ - public function get($scope, $grantType = null, $clientId = null); -} diff --git a/src/Repositories/ScopeRepositoryInterface.php b/src/Repositories/ScopeRepositoryInterface.php new file mode 100644 index 00000000..20bf2590 --- /dev/null +++ b/src/Repositories/ScopeRepositoryInterface.php @@ -0,0 +1,29 @@ + + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * @link https://github.com/thephpleague/oauth2-server + */ + +namespace League\OAuth2\Server\Repositories; + +/** + * Scope interface + */ +interface ScopeRepositoryInterface extends RepositoryInterface +{ + /** + * Return information about a scope + * + * @param string $scopeIdentifier The scope identifier + * @param string $grantType The grant type used in the request (default = "null") + * @param string $clientId The client sending the request (default = "null") + * + * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface + */ + public function get($scopeIdentifier, $grantType = null, $clientId = null); +} diff --git a/src/Repositories/SessionInterface.php b/src/Repositories/SessionInterface.php deleted file mode 100644 index ab205180..00000000 --- a/src/Repositories/SessionInterface.php +++ /dev/null @@ -1,72 +0,0 @@ - - * @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\Entity\AccessTokenEntity; -use League\OAuth2\Server\Entity\AuthCodeEntity; -use League\OAuth2\Server\Entity\ScopeEntity; -use League\OAuth2\Server\Entity\SessionEntity; - -/** - * Session storage interface - */ -interface SessionInterface extends StorageInterface -{ - /** - * Get a session from an access token - * - * @param \League\OAuth2\Server\Entity\AccessTokenEntity $accessToken The access token - * - * @return \League\OAuth2\Server\Entity\SessionEntity - */ - public function getByAccessToken(AccessTokenEntity $accessToken); - - /** - * Get a session from an auth code - * - * @param \League\OAuth2\Server\Entity\AuthCodeEntity $authCode The auth code - * - * @return \League\OAuth2\Server\Entity\SessionEntity - */ - public function getByAuthCode(AuthCodeEntity $authCode); - - /** - * Get a session's scopes - * - * @param \League\OAuth2\Server\Entity\SessionEntity - * - * @return array Array of \League\OAuth2\Server\Entity\ScopeEntity - */ - public function getScopes(SessionEntity $session); - - /** - * Create a new session - * - * @param string $ownerType Session owner's type (user, client) - * @param string $ownerId Session owner's ID - * @param string $clientId Client ID - * @param string $clientRedirectUri Client redirect URI (default = null) - * - * @return integer The session's ID - */ - public function create($ownerType, $ownerId, $clientId, $clientRedirectUri = null); - - /** - * Associate a scope with a session - * - * @param \League\OAuth2\Server\Entity\SessionEntity $session The session - * @param \League\OAuth2\Server\Entity\ScopeEntity $scope The scope - * - * @return void - */ - public function associateScope(SessionEntity $session, ScopeEntity $scope); -} diff --git a/src/Repositories/StorageInterface.php b/src/Repositories/StorageInterface.php deleted file mode 100644 index ff9614b5..00000000 --- a/src/Repositories/StorageInterface.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @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\AbstractServer; - -/** - * Storage interface - */ -interface StorageInterface -{ - /** - * Set the server - * - * @param \League\OAuth2\Server\AbstractServer $server - */ - public function setServer(AbstractServer $server); -} From 36a1a430b5e966e12d052b4c2fa9da97b698528c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 17:01:00 +0100 Subject: [PATCH 014/444] Updated response types --- src/ResponseTypes/AbstractResponseType.php | 21 +++++++++++++++++-- src/ResponseTypes/BearerTokenResponseType.php | 10 +++------ src/ResponseTypes/ResponseTypeInterface.php | 10 +++++++-- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/ResponseTypes/AbstractResponseType.php b/src/ResponseTypes/AbstractResponseType.php index 41e5ca4f..5b874c08 100644 --- a/src/ResponseTypes/AbstractResponseType.php +++ b/src/ResponseTypes/AbstractResponseType.php @@ -9,11 +9,12 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\TokenTypes; +namespace League\OAuth2\Server\ResponseTypes; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; +use Symfony\Component\HttpFoundation\Response; -abstract class AbstractTokenType implements TokenTypeInterface +abstract class AbstractResponseType implements ResponseTypeInterface { /** * Response array @@ -50,4 +51,20 @@ abstract class AbstractTokenType implements TokenTypeInterface { $this->accessToken = $accessToken; } + + /** + * @return \Symfony\Component\HttpFoundation\Response + */ + public function generateHttpResponse() + { + return new Response( + json_encode($this->generateResponse()), + 200, + [ + 'Content-type' => 'application/json', + 'Cache-Control' => 'no-store', + 'Pragma' => 'no-cache' + ] + ); + } } diff --git a/src/ResponseTypes/BearerTokenResponseType.php b/src/ResponseTypes/BearerTokenResponseType.php index a132b53a..b3b61b52 100644 --- a/src/ResponseTypes/BearerTokenResponseType.php +++ b/src/ResponseTypes/BearerTokenResponseType.php @@ -9,12 +9,11 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\TokenTypes; +namespace League\OAuth2\Server\ResponseTypes; -use Period\Period; use Symfony\Component\HttpFoundation\Request; -class BearerTokenType extends AbstractTokenType +class BearerTokenResponseType extends AbstractResponseType { /** * {@inheritdoc} @@ -24,10 +23,7 @@ class BearerTokenType extends AbstractTokenType $return = [ 'access_token' => $this->accessToken->getIdentifier(), 'token_type' => 'Bearer', - 'expires_in' => (new Period( - new \DateTime(), - $this->accessToken->getExpiryDateTime()) - )->getTimestampInterval(), + 'expires_in' => $this->accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp() ]; if (!is_null($this->getParam('refresh_token'))) { diff --git a/src/ResponseTypes/ResponseTypeInterface.php b/src/ResponseTypes/ResponseTypeInterface.php index 4c4c36d9..2bd83dd9 100644 --- a/src/ResponseTypes/ResponseTypeInterface.php +++ b/src/ResponseTypes/ResponseTypeInterface.php @@ -9,14 +9,15 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\TokenTypes; +namespace League\OAuth2\Server\ResponseTypes; use League\OAuth2\Server\AbstractServer; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entity\SessionEntity; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; -interface TokenTypeInterface +interface ResponseTypeInterface { /** * Generate a response @@ -55,4 +56,9 @@ interface TokenTypeInterface * @return string */ public function determineAccessTokenInHeader(Request $request); + + /** + * @return Response + */ + public function generateHttpResponse(); } From f964fd2962c1259403dce3e5528f645ad0ca9d2a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 17:01:19 +0100 Subject: [PATCH 015/444] Updated abstract grant and client credentials grant --- src/Grant/AbstractGrant.php | 178 +++++++++------------------ src/Grant/ClientCredentialsGrant.php | 102 ++++++--------- 2 files changed, 102 insertions(+), 178 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index fd5cb52f..3734f91a 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -11,10 +11,13 @@ namespace League\OAuth2\Server\Grant; -use League\OAuth2\Server\AuthorizationServer; -use League\OAuth2\Server\Entity\ClientEntity; -use League\OAuth2\Server\Entity\ScopeEntity; +use League\Event\Emitter; +use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Exception; +use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; /** * Abstract grant class @@ -29,32 +32,54 @@ abstract class AbstractGrant implements GrantTypeInterface protected $identifier = ''; /** - * Response type + * Grant responds with * * @var string */ - protected $responseType; + protected $respondsWith = 'token'; /** - * Callback to authenticate a user's name and password - * - * @var callable + * @var \Symfony\Component\HttpFoundation\Request */ - protected $callback; + protected $request; /** - * AuthServer instance - * - * @var \League\OAuth2\Server\AuthorizationServer + * @var ClientRepositoryInterface */ - protected $server; + protected $clientRepository; /** - * Access token expires in override - * - * @var int + * @var AccessTokenRepositoryInterface */ - protected $accessTokenTTL; + protected $accessTokenRepository; + + /** + * @var \League\Event\Emitter + */ + protected $emitter; + + /** + * @var ScopeRepositoryInterface + */ + protected $scopeRepository; + + /** + * @param \League\Event\Emitter $emitter + * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository + * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository + * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository + */ + public function __construct( + Emitter $emitter, + ClientRepositoryInterface $clientRepository, + ScopeRepositoryInterface $scopeRepository, + AccessTokenRepositoryInterface $accessTokenRepository + ) { + $this->emitter = $emitter; + $this->clientRepository = $clientRepository; + $this->scopeRepository = $scopeRepository; + $this->accessTokenRepository = $accessTokenRepository; + } /** * {@inheritdoc} @@ -67,74 +92,27 @@ abstract class AbstractGrant implements GrantTypeInterface /** * {@inheritdoc} */ - public function setIdentifier($identifier) + public function respondsWith() { - $this->identifier = $identifier; - - return $this; + return $this->respondsWith; } /** - * {@inheritdoc} + * @param string $scopeParamValue A string containing a delimited set of scope identifiers + * @param string $scopeDelimiter The delimiter between the scopes in the value string + * @param ClientEntityInterface $client + * @param string $redirectUri + * + * @return \League\OAuth2\Server\Entities\ScopeEntity[] + * @throws \League\OAuth2\Server\Exception\InvalidScopeException */ - public function getResponseType() - { - return $this->responseType; - } - - /** - * Get the TTL for an access token - * - * @return int The TTL - */ - public function getAccessTokenTTL() - { - if ($this->accessTokenTTL) { - return $this->accessTokenTTL; - } - - return $this->server->getAccessTokenTTL(); - } - - /** - * Override the default access token expire time - * - * @param int $accessTokenTTL - * - * @return self - */ - public function setAccessTokenTTL($accessTokenTTL) - { - $this->accessTokenTTL = $accessTokenTTL; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function setAuthorizationServer(AuthorizationServer $server) - { - $this->server = $server; - - return $this; - } - - /** - * Given a list of scopes, validate them and return an array of Scope entities - * - * @param string $scopeParam A string of scopes (e.g. "profile email birthday") - * @param \League\OAuth2\Server\Entity\ClientEntity $client Client entity - * @param string|null $redirectUri The redirect URI to return the user to - * - * @return \League\OAuth2\Server\Entity\ScopeEntity[] - * - * @throws \League\OAuth2\Server\Exception\InvalidScopeException If scope is invalid, or no scopes passed when required - * @throws - */ - public function validateScopes($scopeParam = '', ClientEntity $client, $redirectUri = null) - { - $scopesList = explode($this->server->getScopeDelimiter(), $scopeParam); + public function validateScopes( + $scopeParamValue, + $scopeDelimiter, + ClientEntityInterface $client, + $redirectUri = null + ) { + $scopesList = explode($scopeDelimiter, trim($scopeParamValue)); for ($i = 0; $i < count($scopesList); $i++) { $scopesList[$i] = trim($scopesList[$i]); @@ -143,53 +121,19 @@ abstract class AbstractGrant implements GrantTypeInterface } } - if ( - $this->server->scopeParamRequired() === true - && $this->server->getDefaultScope() === null - && count($scopesList) === 0 - ) { - throw new Exception\InvalidRequestException('scope'); - } elseif (count($scopesList) === 0 && $this->server->getDefaultScope() !== null) { - if (is_array($this->server->getDefaultScope())) { - $scopesList = $this->server->getDefaultScope(); - } else { - $scopesList = [0 => $this->server->getDefaultScope()]; - } - } - $scopes = []; - foreach ($scopesList as $scopeItem) { - $scope = $this->server->getScopeStorage()->get( + $scope = $this->scopeRepository->get( $scopeItem, $this->getIdentifier(), - $client->getId() + $client->getIdentifier() ); if (($scope instanceof ScopeEntity) === false) { throw new Exception\InvalidScopeException($scopeItem, $redirectUri); } - $scopes[$scope->getId()] = $scope; - } - - return $scopes; - } - - /** - * Format the local scopes array - * - * @param \League\OAuth2\Server\Entity\ScopeEntity[] - * - * @return array - */ - protected function formatScopes($unformated = []) - { - $scopes = []; - foreach ($unformated as $scope) { - if ($scope instanceof ScopeEntity) { - $scopes[$scope->getId()] = $scope; - } + $scopes[] = $scope; } return $scopes; diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index e219c633..f875143d 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -11,12 +11,14 @@ namespace League\OAuth2\Server\Grant; -use League\OAuth2\Server\Entity\AccessTokenEntity; -use League\OAuth2\Server\Entity\ClientEntity; -use League\OAuth2\Server\Entity\SessionEntity; -use League\OAuth2\Server\Event; +use DateInterval; +use League\Event\Event; +use League\OAuth2\Server\Entities\AccessTokenEntity; +use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Exception; -use League\OAuth2\Server\Util\SecureKey; +use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; +use League\OAuth2\Server\Utils\SecureKey; +use Symfony\Component\HttpFoundation\Request; /** * Client credentials grant class @@ -31,92 +33,70 @@ class ClientCredentialsGrant extends AbstractGrant protected $identifier = 'client_credentials'; /** - * Response type + * Return an access token * - * @var string + * @param \Symfony\Component\HttpFoundation\Request $request + * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType + * @param \DateInterval $accessTokenTTL + * @param string $scopeDelimiter + * + * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface + * @throws \League\OAuth2\Server\Exception\InvalidClientException + * @throws \League\OAuth2\Server\Exception\InvalidRequestException + * @throws \League\OAuth2\Server\Exception\InvalidScopeException */ - protected $responseType = null; - - /** - * AuthServer instance - * - * @var \League\OAuth2\Server\AuthorizationServer - */ - protected $server = null; - - /** - * Access token expires in override - * - * @var int - */ - protected $accessTokenTTL = null; - - /** - * Complete the client credentials grant - * - * @return array - * - * @throws - */ - public function completeFlow() - { + public function getAccessTokenAsType( + Request $request, + ResponseTypeInterface $responseType, + DateInterval $accessTokenTTL, + $scopeDelimiter = ' ' + ) { // Get the required params - $clientId = $this->server->getRequest()->request->get('client_id', $this->server->getRequest()->getUser()); + $clientId = $request->request->get('client_id', $request->getUser()); if (is_null($clientId)) { throw new Exception\InvalidRequestException('client_id'); } - $clientSecret = $this->server->getRequest()->request->get('client_secret', - $this->server->getRequest()->getPassword()); + $clientSecret = $request->request->get('client_secret', $request->getPassword()); if (is_null($clientSecret)) { throw new Exception\InvalidRequestException('client_secret'); } // Validate client ID and client secret - $client = $this->server->getClientStorage()->get( + $client = $this->clientRepository->get( $clientId, $clientSecret, null, $this->getIdentifier() ); - if (($client instanceof ClientEntity) === false) { - $this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($this->server->getRequest())); + if (($client instanceof ClientEntityInterface) === false) { + $this->emitter->emit(new Event('client.authentication.failed', $request)); throw new Exception\InvalidClientException(); } // Validate any scopes that are in the request - $scopeParam = $this->server->getRequest()->request->get('scope', ''); - $scopes = $this->validateScopes($scopeParam, $client); - - // Create a new session - $session = new SessionEntity($this->server); - $session->setOwner('client', $client->getId()); - $session->associateClient($client); + $scopeParam = $request->request->get('scope', ''); + $scopes = $this->validateScopes($scopeParam, $scopeDelimiter, $client); // Generate an access token - $accessToken = new AccessTokenEntity($this->server); - $accessToken->setId(SecureKey::generate()); - $accessToken->setExpireTime($this->getAccessTokenTTL() + time()); + $accessToken = new AccessTokenEntity(); + $accessToken->setIdentifier(SecureKey::generate()); + $accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL)); + $accessToken->setClient($client); + $accessToken->setOwner('client', $client->getIdentifier()); // Associate scopes with the session and access token foreach ($scopes as $scope) { - $session->associateScope($scope); + $accessToken->addScope($scope); } - foreach ($session->getScopes() as $scope) { - $accessToken->associateScope($scope); - } + // Save the token + $this->accessTokenRepository->create($accessToken); - // Save everything - $session->save(); - $accessToken->setSession($session); - $accessToken->save(); + // Inject access token into token type + $responseType->setAccessToken($accessToken); - $this->server->getTokenType()->setSession($session); - $this->server->getTokenType()->setParam('access_token', $accessToken->getId()); - $this->server->getTokenType()->setParam('expires_in', $this->getAccessTokenTTL()); - - return $this->server->getTokenType()->generateResponse(); + return $responseType; } } From f1da0d29435ef087c30d39cf59d3dd461d5ebdb4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 17:01:41 +0100 Subject: [PATCH 016/444] Added ClientCredentialsGrantServerProvider --- .../ClientCredentialsGrantServerProvider.php | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/ServiceProviders/ClientCredentialsGrantServerProvider.php diff --git a/src/ServiceProviders/ClientCredentialsGrantServerProvider.php b/src/ServiceProviders/ClientCredentialsGrantServerProvider.php new file mode 100644 index 00000000..97232f94 --- /dev/null +++ b/src/ServiceProviders/ClientCredentialsGrantServerProvider.php @@ -0,0 +1,29 @@ +getContainer(); + + $container->add('ClientCredentialsGrant', function () use ($container) { + $grant = new ClientCredentialsGrant( + $container->get('emitter'), + $container->get('ClientRepository'), + $container->get('ScopeRepository'), + $container->get('AccessTokenRepository') + ); + return $grant; + }); + } +} From 164de644e9253a4bcfe2040277203ecf18e6577c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 17:02:43 +0100 Subject: [PATCH 017/444] First commit of new examples --- examples/README.md | 3 + examples/client-credentials/index.php | 23 + examples/composer.json | 13 + examples/composer.lock | 1070 +++++++++++++++++ .../Repositories/AccessTokenRepository.php | 65 + .../src/Repositories/ClientRepository.php | 51 + examples/src/Repositories/ScopeRepository.php | 38 + 7 files changed, 1263 insertions(+) create mode 100644 examples/README.md create mode 100644 examples/client-credentials/index.php create mode 100644 examples/composer.json create mode 100644 examples/composer.lock create mode 100644 examples/src/Repositories/AccessTokenRepository.php create mode 100644 examples/src/Repositories/ClientRepository.php create mode 100644 examples/src/Repositories/ScopeRepository.php diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..884da28b --- /dev/null +++ b/examples/README.md @@ -0,0 +1,3 @@ +# Example implementations + +Just run `composer install --no-dev` in this directory to get started. \ No newline at end of file diff --git a/examples/client-credentials/index.php b/examples/client-credentials/index.php new file mode 100644 index 00000000..de29ebe8 --- /dev/null +++ b/examples/client-credentials/index.php @@ -0,0 +1,23 @@ +addRepository(new \OAuth2ServerExamples\Repositories\ClientRepository()); +$server->addRepository(new \OAuth2ServerExamples\Repositories\ScopeRepository()); +$server->addRepository(new \OAuth2ServerExamples\Repositories\AccessTokenRepository()); + +// Enable the client credentials grant which will return access tokens that last for 24 hours +$server->enableGrantType('ClientCredentialsGrant', null, new \DateInterval('PT24H')); + +// Setup the routing +$application = new \Proton\Application(); +$application->post('/access_token', function (Request $request) use ($server) { + return $server->getAccessTokenResponse($request); +}); + +// Run the app +$application->run(); diff --git a/examples/composer.json b/examples/composer.json new file mode 100644 index 00000000..6485183e --- /dev/null +++ b/examples/composer.json @@ -0,0 +1,13 @@ +{ + "name": "", + "require": { + "alexbilbie/proton": "~1.4", + "illuminate/database": "~5.0" + }, + "autoload": { + "psr-4": { + "League\\OAuth2\\Server\\": "../src/", + "OAuth2ServerExamples\\": "src/" + } + } +} \ No newline at end of file diff --git a/examples/composer.lock b/examples/composer.lock new file mode 100644 index 00000000..30e6f2f6 --- /dev/null +++ b/examples/composer.lock @@ -0,0 +1,1070 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "1b6c8d343ed4a6d2ff7b178d989d7516", + "packages": [ + { + "name": "alexbilbie/proton", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/alexbilbie/Proton.git", + "reference": "007dd09af084167e834a6bb80f3777c6faabbe22" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alexbilbie/Proton/zipball/007dd09af084167e834a6bb80f3777c6faabbe22", + "reference": "007dd09af084167e834a6bb80f3777c6faabbe22", + "shasum": "" + }, + "require": { + "league/container": "~1.0", + "league/event": "~2.1", + "league/route": "~1.0", + "monolog/monolog": "~1.12", + "php": ">=5.4.0", + "symfony/http-kernel": "~2.5" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "autoload": { + "psr-4": { + "Proton\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alex Bilbie", + "email": "hello@alexbilbie.com" + } + ], + "description": "Micro PHP framework", + "homepage": "https://github.com/alexbilbie/proton", + "keywords": [ + "HttpKernelInterface", + "StackPHP", + "framework", + "micro", + "middleware", + "proton" + ], + "time": "2015-03-26 17:35:31" + }, + { + "name": "danielstjules/stringy", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/danielstjules/Stringy.git", + "reference": "3cf18e9e424a6dedc38b7eb7ef580edb0929461b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/danielstjules/Stringy/zipball/3cf18e9e424a6dedc38b7eb7ef580edb0929461b", + "reference": "3cf18e9e424a6dedc38b7eb7ef580edb0929461b", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Stringy\\": "src/" + }, + "files": [ + "src/Create.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel St. Jules", + "email": "danielst.jules@gmail.com", + "homepage": "http://www.danielstjules.com" + } + ], + "description": "A string manipulation library with multibyte support", + "homepage": "https://github.com/danielstjules/Stringy", + "keywords": [ + "UTF", + "helpers", + "manipulation", + "methods", + "multibyte", + "string", + "utf-8", + "utility", + "utils" + ], + "time": "2015-02-10 06:19:18" + }, + { + "name": "doctrine/inflector", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "0bcb2e79d8571787f18b7eb036ed3d004908e604" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/0bcb2e79d8571787f18b7eb036ed3d004908e604", + "reference": "0bcb2e79d8571787f18b7eb036ed3d004908e604", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Inflector\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Common String Manipulations with regard to casing and singular/plural rules.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string" + ], + "time": "2014-12-20 21:24:13" + }, + { + "name": "illuminate/container", + "version": "v5.0.26", + "source": { + "type": "git", + "url": "https://github.com/illuminate/container.git", + "reference": "a11c01c1d8b6941bd7ef2f104749ada5e34f146e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/container/zipball/a11c01c1d8b6941bd7ef2f104749ada5e34f146e", + "reference": "a11c01c1d8b6941bd7ef2f104749ada5e34f146e", + "shasum": "" + }, + "require": { + "illuminate/contracts": "5.0.*", + "php": ">=5.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Container\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylorotwell@gmail.com" + } + ], + "description": "The Illuminate Container package.", + "homepage": "http://laravel.com", + "time": "2015-03-25 17:06:14" + }, + { + "name": "illuminate/contracts", + "version": "v5.0.0", + "source": { + "type": "git", + "url": "https://github.com/illuminate/contracts.git", + "reference": "78f1dba092d5fcb6d3a19537662abe31c4d128fd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/78f1dba092d5fcb6d3a19537662abe31c4d128fd", + "reference": "78f1dba092d5fcb6d3a19537662abe31c4d128fd", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Contracts\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylorotwell@gmail.com" + } + ], + "description": "The Illuminate Contracts package.", + "time": "2015-01-30 16:27:08" + }, + { + "name": "illuminate/database", + "version": "v5.0.27", + "source": { + "type": "git", + "url": "https://github.com/illuminate/database.git", + "reference": "8d41d6a2c20b4295f7f77b5ee1ac91d9060510f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/database/zipball/8d41d6a2c20b4295f7f77b5ee1ac91d9060510f5", + "reference": "8d41d6a2c20b4295f7f77b5ee1ac91d9060510f5", + "shasum": "" + }, + "require": { + "illuminate/container": "5.0.*", + "illuminate/contracts": "5.0.*", + "illuminate/support": "5.0.*", + "nesbot/carbon": "~1.0", + "php": ">=5.4.0" + }, + "suggest": { + "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.4).", + "illuminate/console": "Required to use the database commands (5.0.*).", + "illuminate/events": "Required to use the observers with Eloquent (5.0.*).", + "illuminate/filesystem": "Required to use the migrations (5.0.*)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Database\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylorotwell@gmail.com" + } + ], + "description": "The Illuminate Database package.", + "homepage": "http://laravel.com", + "keywords": [ + "database", + "laravel", + "orm", + "sql" + ], + "time": "2015-04-04 01:34:34" + }, + { + "name": "illuminate/support", + "version": "v5.0.26", + "source": { + "type": "git", + "url": "https://github.com/illuminate/support.git", + "reference": "29e8618a45d090572e092abf193a257bf28c48d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/support/zipball/29e8618a45d090572e092abf193a257bf28c48d9", + "reference": "29e8618a45d090572e092abf193a257bf28c48d9", + "shasum": "" + }, + "require": { + "danielstjules/stringy": "~1.8", + "doctrine/inflector": "~1.0", + "ext-mbstring": "*", + "illuminate/contracts": "5.0.*", + "php": ">=5.4.0" + }, + "suggest": { + "jeremeamia/superclosure": "Required to be able to serialize closures (~2.0)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Support\\": "" + }, + "files": [ + "helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylorotwell@gmail.com" + } + ], + "description": "The Illuminate Support package.", + "homepage": "http://laravel.com", + "time": "2015-03-27 14:49:11" + }, + { + "name": "league/container", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/container.git", + "reference": "6cbb3d83bfb979eaf43cd3c279c22abf3fbcf9ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/container/zipball/6cbb3d83bfb979eaf43cd3c279c22abf3fbcf9ff", + "reference": "6cbb3d83bfb979eaf43cd3c279c22abf3fbcf9ff", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "replace": { + "orno/di": "~2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Container\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Phil Bennett", + "email": "philipobenito@gmail.com", + "homepage": "http://philipobenito.github.io", + "role": "Developer" + } + ], + "description": "A fast and intuitive dependency injection container.", + "homepage": "https://github.com/thephpleague/container", + "keywords": [ + "container", + "dependency", + "di", + "injection", + "league" + ], + "time": "2015-02-21 18:55:49" + }, + { + "name": "league/event", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/event.git", + "reference": "cecc6213023a8b18efb163853569082051e5f1ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/event/zipball/cecc6213023a8b18efb163853569082051e5f1ea", + "reference": "cecc6213023a8b18efb163853569082051e5f1ea", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "henrikbjorn/phpspec-code-coverage": "~1.0.1", + "phpspec/phpspec": "~2.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Event\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Event package", + "keywords": [ + "emitter", + "event", + "listener" + ], + "time": "2015-03-30 07:53:52" + }, + { + "name": "league/route", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/route.git", + "reference": "06b0b3cb203f329875ad534d0f8a049d23767005" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/route/zipball/06b0b3cb203f329875ad534d0f8a049d23767005", + "reference": "06b0b3cb203f329875ad534d0f8a049d23767005", + "shasum": "" + }, + "require": { + "league/container": "~1.0", + "nikic/fast-route": "~0.3", + "php": ">=5.4.0", + "symfony/http-foundation": "~2.6" + }, + "replace": { + "orno/http": "~1.0", + "orno/route": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Route\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Phil Bennett", + "email": "philipobenito@gmail.com", + "homepage": "http://philipobenito.github.io", + "role": "Developer" + } + ], + "description": "A fast routing and dispatch package built on top of FastRoute.", + "homepage": "https://github.com/thephpleague/route", + "keywords": [ + "league", + "route" + ], + "time": "2015-02-24 18:34:01" + }, + { + "name": "monolog/monolog", + "version": "1.13.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "c31a2c4e8db5da8b46c74cf275d7f109c0f249ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c31a2c4e8db5da8b46c74cf275d7f109c0f249ac", + "reference": "c31a2c4e8db5da8b46c74cf275d7f109c0f249ac", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "~2.4, >2.4.8", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "phpunit/phpunit": "~4.0", + "raven/raven": "~0.5", + "ruflin/elastica": "0.90.*", + "swiftmailer/swiftmailer": "~5.3", + "videlalvaro/php-amqplib": "~2.4" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "raven/raven": "Allow sending log messages to a Sentry server", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.13.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "time": "2015-03-09 09:58:04" + }, + { + "name": "nesbot/carbon", + "version": "1.18.0", + "source": { + "type": "git", + "url": "https://github.com/briannesbitt/Carbon.git", + "reference": "99e2f69f7bdc2cc4334b2d00f1e0ba450623ea36" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/99e2f69f7bdc2cc4334b2d00f1e0ba450623ea36", + "reference": "99e2f69f7bdc2cc4334b2d00f1e0ba450623ea36", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "symfony/translation": "2.6.*" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Carbon": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "http://nesbot.com" + } + ], + "description": "A simple API extension for DateTime.", + "homepage": "http://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "time": "2015-03-26 03:05:57" + }, + { + "name": "nikic/fast-route", + "version": "v0.4.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/FastRoute.git", + "reference": "f26a8f7788f25c0e3e9b1579d38d7ccab2755320" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/FastRoute/zipball/f26a8f7788f25c0e3e9b1579d38d7ccab2755320", + "reference": "f26a8f7788f25c0e3e9b1579d38d7ccab2755320", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "FastRoute\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov", + "email": "nikic@php.net" + } + ], + "description": "Fast request router for PHP", + "keywords": [ + "router", + "routing" + ], + "time": "2015-02-26 15:33:07" + }, + { + "name": "psr/log", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2012-12-21 11:40:51" + }, + { + "name": "symfony/debug", + "version": "v2.6.6", + "target-dir": "Symfony/Component/Debug", + "source": { + "type": "git", + "url": "https://github.com/symfony/Debug.git", + "reference": "d49a46a20a8f0544aedac54466750ad787d3d3e3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Debug/zipball/d49a46a20a8f0544aedac54466750ad787d3d3e3", + "reference": "d49a46a20a8f0544aedac54466750ad787d3d3e3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "psr/log": "~1.0" + }, + "conflict": { + "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + }, + "require-dev": { + "symfony/class-loader": "~2.2", + "symfony/http-foundation": "~2.1", + "symfony/http-kernel": "~2.3.24|~2.5.9|~2.6,>=2.6.2", + "symfony/phpunit-bridge": "~2.7" + }, + "suggest": { + "symfony/http-foundation": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Debug\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Debug Component", + "homepage": "http://symfony.com", + "time": "2015-03-22 16:55:57" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.6.6", + "target-dir": "Symfony/Component/EventDispatcher", + "source": { + "type": "git", + "url": "https://github.com/symfony/EventDispatcher.git", + "reference": "70f7c8478739ad21e3deef0d977b38c77f1fb284" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/70f7c8478739ad21e3deef0d977b38c77f1fb284", + "reference": "70f7c8478739ad21e3deef0d977b38c77f1fb284", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.0,>=2.0.5", + "symfony/dependency-injection": "~2.6", + "symfony/expression-language": "~2.6", + "symfony/phpunit-bridge": "~2.7", + "symfony/stopwatch": "~2.3" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "http://symfony.com", + "time": "2015-03-13 17:37:22" + }, + { + "name": "symfony/http-foundation", + "version": "v2.6.6", + "target-dir": "Symfony/Component/HttpFoundation", + "source": { + "type": "git", + "url": "https://github.com/symfony/HttpFoundation.git", + "reference": "8a6337233f08f7520de97f4ffd6f00e947d892f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/8a6337233f08f7520de97f4ffd6f00e947d892f9", + "reference": "8a6337233f08f7520de97f4ffd6f00e947d892f9", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/expression-language": "~2.4", + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "classmap": [ + "Symfony/Component/HttpFoundation/Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony HttpFoundation Component", + "homepage": "http://symfony.com", + "time": "2015-04-01 16:50:12" + }, + { + "name": "symfony/http-kernel", + "version": "v2.6.6", + "target-dir": "Symfony/Component/HttpKernel", + "source": { + "type": "git", + "url": "https://github.com/symfony/HttpKernel.git", + "reference": "3829cacfe21eaf3f73604a62d79183d1f6e792c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/HttpKernel/zipball/3829cacfe21eaf3f73604a62d79183d1f6e792c4", + "reference": "3829cacfe21eaf3f73604a62d79183d1f6e792c4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "psr/log": "~1.0", + "symfony/debug": "~2.6,>=2.6.2", + "symfony/event-dispatcher": "~2.5.9|~2.6,>=2.6.2", + "symfony/http-foundation": "~2.5,>=2.5.4" + }, + "require-dev": { + "symfony/browser-kit": "~2.3", + "symfony/class-loader": "~2.1", + "symfony/config": "~2.0,>=2.0.5", + "symfony/console": "~2.3", + "symfony/css-selector": "~2.0,>=2.0.5", + "symfony/dependency-injection": "~2.2", + "symfony/dom-crawler": "~2.0,>=2.0.5", + "symfony/expression-language": "~2.4", + "symfony/finder": "~2.0,>=2.0.5", + "symfony/phpunit-bridge": "~2.7", + "symfony/process": "~2.0,>=2.0.5", + "symfony/routing": "~2.2", + "symfony/stopwatch": "~2.3", + "symfony/templating": "~2.2", + "symfony/translation": "~2.0,>=2.0.5", + "symfony/var-dumper": "~2.6" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/class-loader": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "", + "symfony/finder": "", + "symfony/var-dumper": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\HttpKernel\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony HttpKernel Component", + "homepage": "http://symfony.com", + "time": "2015-04-01 16:55:26" + }, + { + "name": "symfony/translation", + "version": "v2.6.6", + "target-dir": "Symfony/Component/Translation", + "source": { + "type": "git", + "url": "https://github.com/symfony/Translation.git", + "reference": "bd939f05cdaca128f4ddbae1b447d6f0203b60af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Translation/zipball/bd939f05cdaca128f4ddbae1b447d6f0203b60af", + "reference": "bd939f05cdaca128f4ddbae1b447d6f0203b60af", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.3,>=2.3.12", + "symfony/intl": "~2.3", + "symfony/phpunit-bridge": "~2.7", + "symfony/yaml": "~2.2" + }, + "suggest": { + "psr/log": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Translation\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Translation Component", + "homepage": "http://symfony.com", + "time": "2015-03-30 15:54:10" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/examples/src/Repositories/AccessTokenRepository.php b/examples/src/Repositories/AccessTokenRepository.php new file mode 100644 index 00000000..71392d9d --- /dev/null +++ b/examples/src/Repositories/AccessTokenRepository.php @@ -0,0 +1,65 @@ + [ + 'secret' => password_hash('abc123', PASSWORD_BCRYPT), + 'name' => 'My Awesome App', + 'redirect_uri' => '' + ] + ]; + + // Check if client is registered + if (array_key_exists($clientIdentifier, $clients) === false) { + return null; + } + + // Check if client secret is valid + if ($clientSecret !== null && password_verify($clientSecret, $clients[$clientIdentifier]['secret']) === false) { + return null; + } + + // Check if redirect URI is valid + if ($redirectUri !== null && $redirectUri !== $clients[$clientIdentifier]['redirectUri']) { + return null; + } + + $client = new ClientEntity(); + $client->setIdentifier($clientIdentifier); + $client->setName($clients[$clientIdentifier]['name']); + $client->setSecret($clients[$clientIdentifier]['secret']); + + return $client; + } +} diff --git a/examples/src/Repositories/ScopeRepository.php b/examples/src/Repositories/ScopeRepository.php new file mode 100644 index 00000000..942f53c2 --- /dev/null +++ b/examples/src/Repositories/ScopeRepository.php @@ -0,0 +1,38 @@ + [ + 'description' => 'Basic details about you' + ], + 'email' => [ + 'description' => 'Your email address' + ] + ]; + + if (array_key_exists($scopeIdentifier, $scopes) === false) { + return null; + } + + $scope = new ScopeEntity(); + $scope->setIdentifier($scopeIdentifier); + + return $scope; + } +} From 0b66fd1948a4cb95e0b795ace898c9e372147890 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 17:03:06 +0100 Subject: [PATCH 018/444] First commit of new server class --- src/Server.php | 137 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 src/Server.php diff --git a/src/Server.php b/src/Server.php new file mode 100644 index 00000000..a560c72b --- /dev/null +++ b/src/Server.php @@ -0,0 +1,137 @@ +defaultResponseType = ($defaultResponseType instanceof ResponseTypeInterface) + ? $defaultResponseType + : new BearerTokenResponseType(); + + $this->defaultAccessTokenTTL = ($defaultAccessTokenTTL instanceof DateInterval) + ? $defaultAccessTokenTTL + : new DateInterval('PT01H'); // default of 1 hour + + parent::__construct(); + } + + /** + * @param string $grantType + * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType + * @param DateInterval $accessTokenTTL + * + * @throws \Exception + */ + public function enableGrantType( + $grantType, + ResponseTypeInterface $responseType = null, + DateInterval $accessTokenTTL = null + ) { + if ($this->getContainer()->isInServiceProvider($grantType)) { + $grant = $this->getContainer()->get($grantType); + $grantIdentifier = $grant->getIdentifier(); + $this->enabledGrantTypes[$grantIdentifier] = $grant; + } else { + throw new \Exception('Unregistered grant type'); + } + + // Set grant response type + if ($responseType instanceof ResponseTypeInterface) { + $this->grantTypeResponseTypes[$grantIdentifier] = $responseType; + } else { + $this->grantTypeResponseTypes[$grantIdentifier] = $this->defaultResponseType; + } + + // Set grant access token TTL + if ($accessTokenTTL instanceof DateInterval) { + $this->grantTypeAccessTokenTTL[$grantIdentifier] = $accessTokenTTL; + } else { + $this->grantTypeAccessTokenTTL[$grantIdentifier] = $this->defaultAccessTokenTTL; + } + } + + /** + * Return an access token response + * + * @param \Symfony\Component\HttpFoundation\Request $request + * + * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface + * @throws \Exception + */ + public function getAccessTokenResponse(Request $request = null) + { + if ($request === null) { + $request = Request::createFromGlobals(); + } + + // Run the requested grant type + $grantType = $request->request->get('grant_type', null); + + if ($grantType === null || !isset($this->enabledGrantTypes[$grantType])) { + throw new \Exception('Unknown grant type'); + } + + $responseType = $this->enabledGrantTypes[$grantType]->getAccessTokenAsType( + $request, + $this->grantTypeResponseTypes[$grantType], + $this->grantTypeAccessTokenTTL[$grantType], + $this->scopeDelimiter + ); + + return $responseType->generateHttpResponse(); + } + + /** + * Set the delimiter used to separate scopes in a request + * + * @param string $scopeDelimiter + */ + public function setScopeDelimiter($scopeDelimiter) + { + $this->scopeDelimiter = $scopeDelimiter; + } +} From 1e39f1d84aaf93bedcde2cd830450eba1f987405 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 17:03:13 +0100 Subject: [PATCH 019/444] Updated abstract server --- src/AbstractServer.php | 323 +++++------------------------------------ 1 file changed, 39 insertions(+), 284 deletions(-) diff --git a/src/AbstractServer.php b/src/AbstractServer.php index 7d4ba202..68685fe0 100644 --- a/src/AbstractServer.php +++ b/src/AbstractServer.php @@ -11,22 +11,24 @@ namespace League\OAuth2\Server; -use League\Event\Emitter; -use League\OAuth2\Server\Storage\AccessTokenInterface; -use League\OAuth2\Server\Storage\AuthCodeInterface; -use League\OAuth2\Server\Storage\ClientInterface; -use League\OAuth2\Server\Storage\MacTokenInterface; -use League\OAuth2\Server\Storage\RefreshTokenInterface; -use League\OAuth2\Server\Storage\ScopeInterface; -use League\OAuth2\Server\Storage\SessionInterface; -use League\OAuth2\Server\TokenType\TokenTypeInterface; +use League\Container\Container; +use League\Container\ContainerAwareInterface; +use League\Container\ContainerAwareTrait; +use League\Event\EmitterAwareInterface; +use League\Event\EmitterTrait; +use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use League\OAuth2\Server\Repositories\RepositoryInterface; +use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use Symfony\Component\HttpFoundation\Request; /** * OAuth 2.0 Resource Server */ -abstract class AbstractServer +abstract class AbstractServer implements ContainerAwareInterface, EmitterAwareInterface { + use EmitterTrait, ContainerAwareTrait; + /** * The request object * @@ -35,107 +37,13 @@ abstract class AbstractServer protected $request; /** - * Session storage - * - * @var \League\OAuth2\Server\Storage\SessionInterface - */ - protected $sessionStorage; - - /** - * Access token storage - * - * @var \League\OAuth2\Server\Storage\AccessTokenInterface - */ - protected $accessTokenStorage; - - /** - * Refresh token storage - * - * @var \League\OAuth2\Server\Storage\RefreshTokenInterface - */ - protected $refreshTokenStorage; - - /** - * Auth code storage - * - * @var \League\OAuth2\Server\Storage\AuthCodeInterface - */ - protected $authCodeStorage; - - /** - * Scope storage - * - * @var \League\OAuth2\Server\Storage\ScopeInterface - */ - protected $scopeStorage; - - /** - * Client storage - * - * @var \League\OAuth2\Server\Storage\ClientInterface - */ - protected $clientStorage; - - /** - * @var \League\OAuth2\Server\Storage\MacTokenInterface - */ - protected $macStorage; - - /** - * Token type - * - * @var \League\OAuth2\Server\TokenType\TokenTypeInterface - */ - protected $tokenType; - - /** - * Event emitter - * - * @var \League\Event\Emitter - */ - protected $eventEmitter; - - /** - * Abstract server constructor + * Setup the server */ public function __construct() { - $this->setEventEmitter(); - } - - /** - * Set an event emitter - * - * @param object $emitter Event emitter object - */ - public function setEventEmitter($emitter = null) - { - if ($emitter === null) { - $this->eventEmitter = new Emitter(); - } else { - $this->eventEmitter = $emitter; - } - } - - /** - * Add an event listener to the event emitter - * - * @param string $eventName Event name - * @param callable $listener Callable function or method - */ - public function addEventListener($eventName, callable $listener) - { - $this->eventEmitter->addListener($eventName, $listener); - } - - /** - * Returns the event emitter - * - * @return \League\Event\Emitter - */ - public function getEventEmitter() - { - return $this->eventEmitter; + $this->setContainer(new Container()); + $this->getContainer()->singleton('emitter', $this->getEmitter()); + $this->getContainer()->addServiceProvider('League\OAuth2\Server\ServiceProviders\ClientCredentialsGrantServerProvider'); } /** @@ -144,6 +52,7 @@ abstract class AbstractServer * @param \Symfony\Component\HttpFoundation\Request The Request Object * * @return self + * @deprecated */ public function setRequest($request) { @@ -156,6 +65,7 @@ abstract class AbstractServer * Gets the Request object. It will create one from the globals if one is not set. * * @return \Symfony\Component\HttpFoundation\Request + * @deprecated */ public function getRequest() { @@ -167,191 +77,36 @@ abstract class AbstractServer } /** - * Set the client storage + * Add a repository to the server * - * @param \League\OAuth2\Server\Storage\ClientInterface $storage - * - * @return self + * @param RepositoryInterface $repository */ - public function setClientStorage(ClientInterface $storage) + public function addRepository(RepositoryInterface $repository) { - $storage->setServer($this); - $this->clientStorage = $storage; - - return $this; + switch ($repository) { + case ($repository instanceof AccessTokenRepositoryInterface): + $this->getContainer()->add('AccessTokenRepository', $repository); + break; + case ($repository instanceof ClientRepositoryInterface): + $this->getContainer()->add('ClientRepository', $repository); + break; + case ($repository instanceof ScopeRepositoryInterface): + $this->getContainer()->add('ScopeRepository', $repository); + break; + } } /** - * Set the session storage + * Get a hydrated grant * - * @param \League\OAuth2\Server\Storage\SessionInterface $storage + * @param string $grant + * @param \DateInterval $tokenTTL * - * @return self + * @return \League\OAuth2\Server\Repositories\RepositoryInterface + * @deprecated */ - public function setSessionStorage(SessionInterface $storage) + public function getGrant($grant, \DateInterval $tokenTTL) { - $storage->setServer($this); - $this->sessionStorage = $storage; - - return $this; - } - - /** - * Set the access token storage - * - * @param \League\OAuth2\Server\Storage\AccessTokenInterface $storage - * - * @return self - */ - public function setAccessTokenStorage(AccessTokenInterface $storage) - { - $storage->setServer($this); - $this->accessTokenStorage = $storage; - - return $this; - } - - /** - * Set the refresh token storage - * - * @param \League\OAuth2\Server\Storage\RefreshTokenInterface $storage - * - * @return self - */ - public function setRefreshTokenStorage(RefreshTokenInterface $storage) - { - $storage->setServer($this); - $this->refreshTokenStorage = $storage; - - return $this; - } - - /** - * Set the auth code storage - * - * @param \League\OAuth2\Server\Storage\AuthCodeInterface $storage - * - * @return self - */ - public function setAuthCodeStorage(AuthCodeInterface $storage) - { - $storage->setServer($this); - $this->authCodeStorage = $storage; - - return $this; - } - - /** - * Set the scope storage - * - * @param \League\OAuth2\Server\Storage\ScopeInterface $storage - * - * @return self - */ - public function setScopeStorage(ScopeInterface $storage) - { - $storage->setServer($this); - $this->scopeStorage = $storage; - - return $this; - } - - /** - * Return the client storage - * - * @return \League\OAuth2\Server\Storage\ClientInterface - */ - public function getClientStorage() - { - return $this->clientStorage; - } - - /** - * Return the scope storage - * - * @return \League\OAuth2\Server\Storage\ScopeInterface - */ - public function getScopeStorage() - { - return $this->scopeStorage; - } - - /** - * Return the session storage - * - * @return \League\OAuth2\Server\Storage\SessionInterface - */ - public function getSessionStorage() - { - return $this->sessionStorage; - } - - /** - * Return the refresh token storage - * - * @return \League\OAuth2\Server\Storage\RefreshTokenInterface - */ - public function getRefreshTokenStorage() - { - return $this->refreshTokenStorage; - } - - /** - * Return the access token storage - * - * @return \League\OAuth2\Server\Storage\AccessTokenInterface - */ - public function getAccessTokenStorage() - { - return $this->accessTokenStorage; - } - - /** - * Return the auth code storage - * - * @return \League\OAuth2\Server\Storage\AuthCodeInterface - */ - public function getAuthCodeStorage() - { - return $this->authCodeStorage; - } - - /** - * Set the access token type - * - * @param TokenTypeInterface $tokenType The token type - * - * @return void - */ - public function setTokenType(TokenTypeInterface $tokenType) - { - $tokenType->setServer($this); - $this->tokenType = $tokenType; - } - - /** - * Get the access token type - * - * @return TokenTypeInterface - */ - public function getTokenType() - { - return $this->tokenType; - } - - /** - * @return MacTokenInterface - */ - public function getMacStorage() - { - return $this->macStorage; - } - - /** - * @param MacTokenInterface $macStorage - */ - public function setMacStorage(MacTokenInterface $macStorage) - { - $this->macStorage = $macStorage; + return $this->getContainer()->get($grant, [$this->responseType, $tokenTTL]); } } From 7a3670523dd2842787e17973d4ba9267aa9e5b2d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 17:05:49 +0100 Subject: [PATCH 020/444] First commit of Codeception files --- codeception.yml | 10 + tests/_bootstrap.php | 2 + tests/_output/.gitignore | 0 tests/_output/ClientCredentialsCept.fail.html | 1 + tests/_support/ApiHelper.php | 10 + tests/api.suite.yml | 8 + tests/api/ApiTester.php | 2389 +++++++++++++++++ tests/api/ClientCredentialsCept.php | 17 + tests/api/_bootstrap.php | 2 + 9 files changed, 2439 insertions(+) create mode 100644 codeception.yml create mode 100644 tests/_bootstrap.php create mode 100644 tests/_output/.gitignore create mode 100644 tests/_output/ClientCredentialsCept.fail.html create mode 100644 tests/_support/ApiHelper.php create mode 100644 tests/api.suite.yml create mode 100644 tests/api/ApiTester.php create mode 100644 tests/api/ClientCredentialsCept.php create mode 100644 tests/api/_bootstrap.php diff --git a/codeception.yml b/codeception.yml new file mode 100644 index 00000000..35fa7fde --- /dev/null +++ b/codeception.yml @@ -0,0 +1,10 @@ +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/tests/_bootstrap.php b/tests/_bootstrap.php new file mode 100644 index 00000000..243f9c85 --- /dev/null +++ b/tests/_bootstrap.php @@ -0,0 +1,2 @@ +validateScopes('basic', Object(League\\OAuth2\\Server\\Entities\\ClientEntity))","#1 \/Users\/alexbilbie\/Projects\/oauth2-server\/src\/Server.php(117): League\\OAuth2\\Server\\Grant\\ClientCredentialsGrant->getAccessTokenAsType(Object(Symfony\\Component\\HttpFoundation\\Request), Object(League\\OAuth2\\Server\\ResponseTypes\\BearerTokenResponseType), Object(DateInterval))","#2 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/client-credentials\/index.php(19): League\\OAuth2\\Server\\Server->getAccessTokenResponse(Object(Symfony\\Component\\HttpFoundation\\Request))","#3 [internal function]: {closure}(Object(Symfony\\Component\\HttpFoundation\\Request), Object(Symfony\\Component\\HttpFoundation\\Response), Array)","#4 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/vendor\/league\/route\/src\/Strategy\/AbstractStrategy.php(55): call_user_func_array(Object(Closure), Array)","#5 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/vendor\/league\/route\/src\/Strategy\/RequestResponseStrategy.php(19): League\\Route\\Strategy\\AbstractStrategy->invokeController(Object(Closure), Array)","#6 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/vendor\/league\/route\/src\/Dispatcher.php(112): League\\Route\\Strategy\\RequestResponseStrategy->dispatch(Object(Closure), Array)","#7 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/vendor\/league\/route\/src\/Dispatcher.php(73): League\\Route\\Dispatcher->handleFound(Object(Closure), Object(League\\Route\\Strategy\\RequestResponseStrategy), Array)","#8 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/vendor\/alexbilbie\/proton\/src\/Application.php(251): League\\Route\\Dispatcher->dispatch('POST', '\/access_token')","#9 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/vendor\/alexbilbie\/proton\/src\/Application.php(300): Proton\\Application->handle(Object(Symfony\\Component\\HttpFoundation\\Request))","#10 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/client-credentials\/index.php(23): Proton\\Application->run()","#11 {main}"]}} \ No newline at end of file diff --git a/tests/_support/ApiHelper.php b/tests/_support/ApiHelper.php new file mode 100644 index 00000000..5fcdbe2c --- /dev/null +++ b/tests/_support/ApiHelper.php @@ -0,0 +1,10 @@ +scenario->runStep(new \Codeception\Step\Action('setHeader', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Adds HTTP authentication via username/password. + * + * @param $username + * @param $password + * @see \Codeception\Module\REST::amHttpAuthenticated() + */ + public function amHttpAuthenticated($username, $password) { + return $this->scenario->runStep(new \Codeception\Step\Condition('amHttpAuthenticated', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Opens the page for the given relative URI. + * + * ``` php + * amOnPage('/'); + * // opens /register page + * $I->amOnPage('/register'); + * ?> + * ``` + * + * @param $page + * @see \Codeception\Module\PhpBrowser::amOnPage() + */ + public function amOnPage($page) { + return $this->scenario->runStep(new \Codeception\Step\Condition('amOnPage', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Open web page at the given absolute URL and sets its hostname as the base host. + * + * ``` php + * amOnUrl('http://codeception.com'); + * $I->amOnPage('/quickstart'); // moves to http://codeception.com/quickstart + * ?> + * ``` + * @see \Codeception\Module\PhpBrowser::amOnUrl() + */ + public function amOnUrl($url) { + return $this->scenario->runStep(new \Codeception\Step\Condition('amOnUrl', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Changes the subdomain for the 'url' configuration parameter. + * Does not open a page; use `amOnPage` for that. + * + * ``` php + * amOnSubdomain('user'); + * $I->amOnPage('/'); + * // moves to http://user.mysite.com/ + * ?> + * ``` + * + * @param $subdomain + * + * @return mixed + * @see \Codeception\Module\PhpBrowser::amOnSubdomain() + */ + public function amOnSubdomain($subdomain) { + return $this->scenario->runStep(new \Codeception\Step\Condition('amOnSubdomain', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Low-level API method. + * If Codeception commands are not enough, use [Guzzle HTTP Client](http://guzzlephp.org/) methods directly + * + * Example: + * + * ``` php + * executeInGuzzle(function (\GuzzleHttp\Client $client) { + * $client->get('/get', ['query' => ['foo' => 'bar']]); + * }); + * ?> + * ``` + * + * It is not recommended to use this command on a regular basis. + * If Codeception lacks important Guzzle Client methods, implement them and submit patches. + * + * @param callable $function + * @see \Codeception\Module\PhpBrowser::executeInGuzzle() + */ + public function executeInGuzzle($function) { + return $this->scenario->runStep(new \Codeception\Step\Action('executeInGuzzle', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Perform a click on a link or a button, given by a locator. + * If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string. + * For buttons, the "value" attribute, "name" attribute, and inner text are searched. + * For links, the link text is searched. + * For images, the "alt" attribute and inner text of any parent links are searched. + * + * The second parameter is a context (CSS or XPath locator) to narrow the search. + * + * Note that if the locator matches a button of type `submit`, the form will be submitted. + * + * ``` php + * click('Logout'); + * // button of form + * $I->click('Submit'); + * // CSS button + * $I->click('#form input[type=submit]'); + * // XPath + * $I->click('//form/*[@type=submit]'); + * // link in context + * $I->click('Logout', '#nav'); + * // using strict locator + * $I->click(['link' => 'Login']); + * ?> + * ``` + * + * @param $link + * @param $context + * @see \Codeception\Lib\InnerBrowser::click() + */ + public function click($link, $context = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('click', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the current page contains the given string. + * Specify a locator as the second parameter to match a specific region. + * + * ``` php + * see('Logout'); // I can suppose user is logged in + * $I->see('Sign Up','h1'); // I can suppose it's a signup page + * $I->see('Sign Up','//body/h1'); // with XPath + * ?> + * ``` + * + * @param $text + * @param null $selector + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::see() + */ + public function canSee($text, $selector = null) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('see', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the current page contains the given string. + * Specify a locator as the second parameter to match a specific region. + * + * ``` php + * see('Logout'); // I can suppose user is logged in + * $I->see('Sign Up','h1'); // I can suppose it's a signup page + * $I->see('Sign Up','//body/h1'); // with XPath + * ?> + * ``` + * + * @param $text + * @param null $selector + * @see \Codeception\Lib\InnerBrowser::see() + */ + public function see($text, $selector = null) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('see', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the current page doesn't contain the text specified. + * Give a locator as the second parameter to match a specific region. + * + * ```php + * dontSee('Login'); // I can suppose user is already logged in + * $I->dontSee('Sign Up','h1'); // I can suppose it's not a signup page + * $I->dontSee('Sign Up','//body/h1'); // with XPath + * ?> + * ``` + * + * @param $text + * @param null $selector + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::dontSee() + */ + public function cantSee($text, $selector = null) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSee', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the current page doesn't contain the text specified. + * Give a locator as the second parameter to match a specific region. + * + * ```php + * dontSee('Login'); // I can suppose user is already logged in + * $I->dontSee('Sign Up','h1'); // I can suppose it's not a signup page + * $I->dontSee('Sign Up','//body/h1'); // with XPath + * ?> + * ``` + * + * @param $text + * @param null $selector + * @see \Codeception\Lib\InnerBrowser::dontSee() + */ + public function dontSee($text, $selector = null) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSee', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that there's a link with the specified text. + * Give a full URL as the second parameter to match links with that exact URL. + * + * ``` php + * seeLink('Logout'); // matches Logout + * $I->seeLink('Logout','/logout'); // matches Logout + * ?> + * ``` + * + * @param $text + * @param null $url + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::seeLink() + */ + public function canSeeLink($text, $url = null) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeLink', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that there's a link with the specified text. + * Give a full URL as the second parameter to match links with that exact URL. + * + * ``` php + * seeLink('Logout'); // matches Logout + * $I->seeLink('Logout','/logout'); // matches Logout + * ?> + * ``` + * + * @param $text + * @param null $url + * @see \Codeception\Lib\InnerBrowser::seeLink() + */ + public function seeLink($text, $url = null) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeLink', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the page doesn't contain a link with the given string. + * If the second parameter is given, only links with a matching "href" attribute will be checked. + * + * ``` php + * dontSeeLink('Logout'); // I suppose user is not logged in + * $I->dontSeeLink('Checkout now', '/store/cart.php'); + * ?> + * ``` + * + * @param $text + * @param null $url + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::dontSeeLink() + */ + public function cantSeeLink($text, $url = null) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeLink', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the page doesn't contain a link with the given string. + * If the second parameter is given, only links with a matching "href" attribute will be checked. + * + * ``` php + * dontSeeLink('Logout'); // I suppose user is not logged in + * $I->dontSeeLink('Checkout now', '/store/cart.php'); + * ?> + * ``` + * + * @param $text + * @param null $url + * @see \Codeception\Lib\InnerBrowser::dontSeeLink() + */ + public function dontSeeLink($text, $url = null) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeLink', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that current URI contains the given string. + * + * ``` php + * seeInCurrentUrl('home'); + * // to match: /users/1 + * $I->seeInCurrentUrl('/users/'); + * ?> + * ``` + * + * @param $uri + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::seeInCurrentUrl() + */ + public function canSeeInCurrentUrl($uri) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeInCurrentUrl', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that current URI contains the given string. + * + * ``` php + * seeInCurrentUrl('home'); + * // to match: /users/1 + * $I->seeInCurrentUrl('/users/'); + * ?> + * ``` + * + * @param $uri + * @see \Codeception\Lib\InnerBrowser::seeInCurrentUrl() + */ + public function seeInCurrentUrl($uri) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeInCurrentUrl', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the current URI doesn't contain the given string. + * + * ``` php + * dontSeeInCurrentUrl('/users/'); + * ?> + * ``` + * + * @param $uri + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::dontSeeInCurrentUrl() + */ + public function cantSeeInCurrentUrl($uri) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInCurrentUrl', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the current URI doesn't contain the given string. + * + * ``` php + * dontSeeInCurrentUrl('/users/'); + * ?> + * ``` + * + * @param $uri + * @see \Codeception\Lib\InnerBrowser::dontSeeInCurrentUrl() + */ + public function dontSeeInCurrentUrl($uri) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeInCurrentUrl', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the current URL is equal to the given string. + * Unlike `seeInCurrentUrl`, this only matches the full URL. + * + * ``` php + * seeCurrentUrlEquals('/'); + * ?> + * ``` + * + * @param $uri + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlEquals() + */ + public function canSeeCurrentUrlEquals($uri) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeCurrentUrlEquals', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the current URL is equal to the given string. + * Unlike `seeInCurrentUrl`, this only matches the full URL. + * + * ``` php + * seeCurrentUrlEquals('/'); + * ?> + * ``` + * + * @param $uri + * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlEquals() + */ + public function seeCurrentUrlEquals($uri) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeCurrentUrlEquals', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the current URL doesn't equal the given string. + * Unlike `dontSeeInCurrentUrl`, this only matches the full URL. + * + * ``` php + * dontSeeCurrentUrlEquals('/'); + * ?> + * ``` + * + * @param $uri + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlEquals() + */ + public function cantSeeCurrentUrlEquals($uri) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCurrentUrlEquals', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the current URL doesn't equal the given string. + * Unlike `dontSeeInCurrentUrl`, this only matches the full URL. + * + * ``` php + * dontSeeCurrentUrlEquals('/'); + * ?> + * ``` + * + * @param $uri + * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlEquals() + */ + public function dontSeeCurrentUrlEquals($uri) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeCurrentUrlEquals', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the current URL matches the given regular expression. + * + * ``` php + * seeCurrentUrlMatches('~$/users/(\d+)~'); + * ?> + * ``` + * + * @param $uri + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlMatches() + */ + public function canSeeCurrentUrlMatches($uri) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeCurrentUrlMatches', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the current URL matches the given regular expression. + * + * ``` php + * seeCurrentUrlMatches('~$/users/(\d+)~'); + * ?> + * ``` + * + * @param $uri + * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlMatches() + */ + public function seeCurrentUrlMatches($uri) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeCurrentUrlMatches', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that current url doesn't match the given regular expression. + * + * ``` php + * dontSeeCurrentUrlMatches('~$/users/(\d+)~'); + * ?> + * ``` + * + * @param $uri + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlMatches() + */ + public function cantSeeCurrentUrlMatches($uri) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCurrentUrlMatches', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that current url doesn't match the given regular expression. + * + * ``` php + * dontSeeCurrentUrlMatches('~$/users/(\d+)~'); + * ?> + * ``` + * + * @param $uri + * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlMatches() + */ + public function dontSeeCurrentUrlMatches($uri) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeCurrentUrlMatches', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Executes the given regular expression against the current URI and returns the first match. + * If no parameters are provided, the full URI is returned. + * + * ``` php + * grabFromCurrentUrl('~$/user/(\d+)/~'); + * $uri = $I->grabFromCurrentUrl(); + * ?> + * ``` + * + * @param null $uri + * + * @internal param $url + * @return mixed + * @see \Codeception\Lib\InnerBrowser::grabFromCurrentUrl() + */ + public function grabFromCurrentUrl($uri = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('grabFromCurrentUrl', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the specified checkbox is checked. + * + * ``` php + * seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms + * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user agreed to terms, If there is only one checkbox in form. + * $I->seeCheckboxIsChecked('//form/input[@type=checkbox and @name=agree]'); + * ?> + * ``` + * + * @param $checkbox + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::seeCheckboxIsChecked() + */ + public function canSeeCheckboxIsChecked($checkbox) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeCheckboxIsChecked', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the specified checkbox is checked. + * + * ``` php + * seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms + * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user agreed to terms, If there is only one checkbox in form. + * $I->seeCheckboxIsChecked('//form/input[@type=checkbox and @name=agree]'); + * ?> + * ``` + * + * @param $checkbox + * @see \Codeception\Lib\InnerBrowser::seeCheckboxIsChecked() + */ + public function seeCheckboxIsChecked($checkbox) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeCheckboxIsChecked', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Check that the specified checkbox is unchecked. + * + * ``` php + * dontSeeCheckboxIsChecked('#agree'); // I suppose user didn't agree to terms + * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user didn't check the first checkbox in form. + * ?> + * ``` + * + * @param $checkbox + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::dontSeeCheckboxIsChecked() + */ + public function cantSeeCheckboxIsChecked($checkbox) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCheckboxIsChecked', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Check that the specified checkbox is unchecked. + * + * ``` php + * dontSeeCheckboxIsChecked('#agree'); // I suppose user didn't agree to terms + * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user didn't check the first checkbox in form. + * ?> + * ``` + * + * @param $checkbox + * @see \Codeception\Lib\InnerBrowser::dontSeeCheckboxIsChecked() + */ + public function dontSeeCheckboxIsChecked($checkbox) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeCheckboxIsChecked', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the given input field or textarea contains the given value. + * For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath. + * + * ``` php + * seeInField('Body','Type your comment here'); + * $I->seeInField('form textarea[name=body]','Type your comment here'); + * $I->seeInField('form input[type=hidden]','hidden_value'); + * $I->seeInField('#searchform input','Search'); + * $I->seeInField('//form/*[@name=search]','Search'); + * $I->seeInField(['name' => 'search'], 'Search'); + * ?> + * ``` + * + * @param $field + * @param $value + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::seeInField() + */ + public function canSeeInField($field, $value) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeInField', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the given input field or textarea contains the given value. + * For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath. + * + * ``` php + * seeInField('Body','Type your comment here'); + * $I->seeInField('form textarea[name=body]','Type your comment here'); + * $I->seeInField('form input[type=hidden]','hidden_value'); + * $I->seeInField('#searchform input','Search'); + * $I->seeInField('//form/*[@name=search]','Search'); + * $I->seeInField(['name' => 'search'], 'Search'); + * ?> + * ``` + * + * @param $field + * @param $value + * @see \Codeception\Lib\InnerBrowser::seeInField() + */ + public function seeInField($field, $value) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeInField', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that an input field or textarea doesn't contain the given value. + * For fuzzy locators, the field is matched by label text, CSS and XPath. + * + * ``` php + * dontSeeInField('Body','Type your comment here'); + * $I->dontSeeInField('form textarea[name=body]','Type your comment here'); + * $I->dontSeeInField('form input[type=hidden]','hidden_value'); + * $I->dontSeeInField('#searchform input','Search'); + * $I->dontSeeInField('//form/*[@name=search]','Search'); + * $I->dontSeeInField(['name' => 'search'], 'Search'); + * ?> + * ``` + * + * @param $field + * @param $value + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::dontSeeInField() + */ + public function cantSeeInField($field, $value) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInField', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that an input field or textarea doesn't contain the given value. + * For fuzzy locators, the field is matched by label text, CSS and XPath. + * + * ``` php + * dontSeeInField('Body','Type your comment here'); + * $I->dontSeeInField('form textarea[name=body]','Type your comment here'); + * $I->dontSeeInField('form input[type=hidden]','hidden_value'); + * $I->dontSeeInField('#searchform input','Search'); + * $I->dontSeeInField('//form/*[@name=search]','Search'); + * $I->dontSeeInField(['name' => 'search'], 'Search'); + * ?> + * ``` + * + * @param $field + * @param $value + * @see \Codeception\Lib\InnerBrowser::dontSeeInField() + */ + public function dontSeeInField($field, $value) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeInField', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Submits the given form on the page, optionally with the given form values. + * Give the form fields values as an array. + * + * Skipped fields will be filled by their values from the page. + * You don't need to click the 'Submit' button afterwards. + * This command itself triggers the request to form's action. + * + * You can optionally specify what button's value to include + * in the request with the last parameter as an alternative to + * explicitly setting its value in the second parameter, as + * button values are not otherwise included in the request. + * + * Examples: + * + * ``` php + * submitForm('#login', array('login' => 'davert', 'password' => '123456')); + * // or + * $I->submitForm('#login', array('login' => 'davert', 'password' => '123456'), 'submitButtonName'); + * + * ``` + * + * For example, given this sample "Sign Up" form: + * + * ``` html + *
+ * Login:
+ * Password:
+ * Do you agree to out terms?
+ * Select pricing plan + * + *
+ * ``` + * + * You could write the following to submit it: + * + * ``` php + * submitForm('#userForm', array('user' => array('login' => 'Davert', 'password' => '123456', 'agree' => true)), 'submitButton'); + * + * ``` + * Note that "2" will be the submitted value for the "plan" field, as it is the selected option. + * + * You can also emulate a JavaScript submission by not specifying any buttons in the third parameter to submitForm. + * + * ```php + * submitForm('#userForm', array('user' => array('login' => 'Davert', 'password' => '123456', 'agree' => true))); + * + * ``` + * + * @param $selector + * @param $params + * @param $button + * @see \Codeception\Lib\InnerBrowser::submitForm() + */ + public function submitForm($selector, $params, $button = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('submitForm', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Fills a text field or textarea with the given string. + * + * ``` php + * fillField("//input[@type='text']", "Hello World!"); + * $I->fillField(['name' => 'email'], 'jon@mail.com'); + * ?> + * ``` + * + * @param $field + * @param $value + * @see \Codeception\Lib\InnerBrowser::fillField() + */ + public function fillField($field, $value) { + return $this->scenario->runStep(new \Codeception\Step\Action('fillField', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Selects an option in a select tag or in radio button group. + * + * ``` php + * selectOption('form select[name=account]', 'Premium'); + * $I->selectOption('form input[name=payment]', 'Monthly'); + * $I->selectOption('//form/select[@name=account]', 'Monthly'); + * ?> + * ``` + * + * Provide an array for the second argument to select multiple options: + * + * ``` php + * selectOption('Which OS do you use?', array('Windows','Linux')); + * ?> + * ``` + * + * @param $select + * @param $option + * @see \Codeception\Lib\InnerBrowser::selectOption() + */ + public function selectOption($select, $option) { + return $this->scenario->runStep(new \Codeception\Step\Action('selectOption', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Ticks a checkbox. For radio buttons, use the `selectOption` method instead. + * + * ``` php + * checkOption('#agree'); + * ?> + * ``` + * + * @param $option + * @see \Codeception\Lib\InnerBrowser::checkOption() + */ + public function checkOption($option) { + return $this->scenario->runStep(new \Codeception\Step\Action('checkOption', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Unticks a checkbox. + * + * ``` php + * uncheckOption('#notify'); + * ?> + * ``` + * + * @param $option + * @see \Codeception\Lib\InnerBrowser::uncheckOption() + */ + public function uncheckOption($option) { + return $this->scenario->runStep(new \Codeception\Step\Action('uncheckOption', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Attaches a file relative to the Codeception data directory to the given file upload field. + * + * ``` php + * attachFile('input[@type="file"]', 'prices.xls'); + * ?> + * ``` + * + * @param $field + * @param $filename + * @see \Codeception\Lib\InnerBrowser::attachFile() + */ + public function attachFile($field, $filename) { + return $this->scenario->runStep(new \Codeception\Step\Action('attachFile', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * If your page triggers an ajax request, you can perform it manually. + * This action sends a GET ajax request with specified params. + * + * See ->sendAjaxPostRequest for examples. + * + * @param $uri + * @param $params + * @see \Codeception\Lib\InnerBrowser::sendAjaxGetRequest() + */ + public function sendAjaxGetRequest($uri, $params = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('sendAjaxGetRequest', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * If your page triggers an ajax request, you can perform it manually. + * This action sends a POST ajax request with specified params. + * Additional params can be passed as array. + * + * Example: + * + * Imagine that by clicking checkbox you trigger ajax request which updates user settings. + * We emulate that click by running this ajax request manually. + * + * ``` php + * sendAjaxPostRequest('/updateSettings', array('notifications' => true)); // POST + * $I->sendAjaxGetRequest('/updateSettings', array('notifications' => true)); // GET + * + * ``` + * + * @param $uri + * @param $params + * @see \Codeception\Lib\InnerBrowser::sendAjaxPostRequest() + */ + public function sendAjaxPostRequest($uri, $params = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('sendAjaxPostRequest', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * If your page triggers an ajax request, you can perform it manually. + * This action sends an ajax request with specified method and params. + * + * Example: + * + * You need to perform an ajax request specifying the HTTP method. + * + * ``` php + * sendAjaxRequest('PUT', '/posts/7', array('title' => 'new title')); + * + * ``` + * + * @param $method + * @param $uri + * @param $params + * @see \Codeception\Lib\InnerBrowser::sendAjaxRequest() + */ + public function sendAjaxRequest($method, $uri, $params = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('sendAjaxRequest', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Finds and returns the text contents of the given element. + * If a fuzzy locator is used, the element is found using CSS, XPath, and by matching the full page source by regular expression. + * + * ``` php + * grabTextFrom('h1'); + * $heading = $I->grabTextFrom('descendant-or-self::h1'); + * $value = $I->grabTextFrom('~ + * ``` + * + * @param $cssOrXPathOrRegex + * + * @return mixed + * @see \Codeception\Lib\InnerBrowser::grabTextFrom() + */ + public function grabTextFrom($cssOrXPathOrRegex) { + return $this->scenario->runStep(new \Codeception\Step\Action('grabTextFrom', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Grabs the value of the given attribute value from the given element. + * Fails if element is not found. + * + * ``` php + * grabAttributeFrom('#tooltip', 'title'); + * ?> + * ``` + * + * + * @param $cssOrXpath + * @param $attribute + * @internal param $element + * @return mixed + * @see \Codeception\Lib\InnerBrowser::grabAttributeFrom() + */ + public function grabAttributeFrom($cssOrXpath, $attribute) { + return $this->scenario->runStep(new \Codeception\Step\Action('grabAttributeFrom', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * @param $field + * + * @return array|mixed|null|string + * @see \Codeception\Lib\InnerBrowser::grabValueFrom() + */ + public function grabValueFrom($field) { + return $this->scenario->runStep(new \Codeception\Step\Action('grabValueFrom', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Sets a cookie with the given name and value. + * + * ``` php + * setCookie('PHPSESSID', 'el4ukv0kqbvoirg7nkp4dncpk3'); + * ?> + * ``` + * + * @param $cookie + * @param $value + * + * @return mixed + * @see \Codeception\Lib\InnerBrowser::setCookie() + */ + public function setCookie($name, $val) { + return $this->scenario->runStep(new \Codeception\Step\Action('setCookie', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Grabs a cookie value. + * + * @param $cookie + * + * @return mixed + * @see \Codeception\Lib\InnerBrowser::grabCookie() + */ + public function grabCookie($name) { + return $this->scenario->runStep(new \Codeception\Step\Action('grabCookie', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that a cookie with the given name is set. + * + * ``` php + * seeCookie('PHPSESSID'); + * ?> + * ``` + * + * @param $cookie + * + * @return mixed + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::seeCookie() + */ + public function canSeeCookie($name) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeCookie', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that a cookie with the given name is set. + * + * ``` php + * seeCookie('PHPSESSID'); + * ?> + * ``` + * + * @param $cookie + * + * @return mixed + * @see \Codeception\Lib\InnerBrowser::seeCookie() + */ + public function seeCookie($name) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeCookie', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that there isn't a cookie with the given name. + * + * @param $cookie + * + * @return mixed + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::dontSeeCookie() + */ + public function cantSeeCookie($name) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCookie', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that there isn't a cookie with the given name. + * + * @param $cookie + * + * @return mixed + * @see \Codeception\Lib\InnerBrowser::dontSeeCookie() + */ + public function dontSeeCookie($name) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeCookie', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Unsets cookie with the given name. + * + * @param $cookie + * + * @return mixed + * @see \Codeception\Lib\InnerBrowser::resetCookie() + */ + public function resetCookie($name) { + return $this->scenario->runStep(new \Codeception\Step\Action('resetCookie', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the given element exists on the page and is visible. + * You can also specify expected attributes of this element. + * + * ``` php + * seeElement('.error'); + * $I->seeElement('//form/input[1]'); + * $I->seeElement('input', ['name' => 'login']); + * $I->seeElement('input', ['value' => '123456']); + * + * // strict locator in first arg, attributes in second + * $I->seeElement(['css' => 'form input'], ['name' => 'login']); + * ?> + * ``` + * + * @param $selector + * @param array $attributes + * @return + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::seeElement() + */ + public function canSeeElement($selector, $attributes = null) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeElement', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the given element exists on the page and is visible. + * You can also specify expected attributes of this element. + * + * ``` php + * seeElement('.error'); + * $I->seeElement('//form/input[1]'); + * $I->seeElement('input', ['name' => 'login']); + * $I->seeElement('input', ['value' => '123456']); + * + * // strict locator in first arg, attributes in second + * $I->seeElement(['css' => 'form input'], ['name' => 'login']); + * ?> + * ``` + * + * @param $selector + * @param array $attributes + * @return + * @see \Codeception\Lib\InnerBrowser::seeElement() + */ + public function seeElement($selector, $attributes = null) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeElement', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the given element is invisible or not present on the page. + * You can also specify expected attributes of this element. + * + * ``` php + * dontSeeElement('.error'); + * $I->dontSeeElement('//form/input[1]'); + * $I->dontSeeElement('input', ['name' => 'login']); + * $I->dontSeeElement('input', ['value' => '123456']); + * ?> + * ``` + * + * @param $selector + * @param array $attributes + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::dontSeeElement() + */ + public function cantSeeElement($selector, $attributes = null) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeElement', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the given element is invisible or not present on the page. + * You can also specify expected attributes of this element. + * + * ``` php + * dontSeeElement('.error'); + * $I->dontSeeElement('//form/input[1]'); + * $I->dontSeeElement('input', ['name' => 'login']); + * $I->dontSeeElement('input', ['value' => '123456']); + * ?> + * ``` + * + * @param $selector + * @param array $attributes + * @see \Codeception\Lib\InnerBrowser::dontSeeElement() + */ + public function dontSeeElement($selector, $attributes = null) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeElement', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that there are a certain number of elements matched by the given locator on the page. + * + * ``` php + * seeNumberOfElements('tr', 10); + * $I->seeNumberOfElements('tr', [0,10]); //between 0 and 10 elements + * ?> + * ``` + * @param $selector + * @param mixed $expected: + * - string: strict number + * - array: range of numbers [0,10] + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::seeNumberOfElements() + */ + public function canSeeNumberOfElements($selector, $expected) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeNumberOfElements', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that there are a certain number of elements matched by the given locator on the page. + * + * ``` php + * seeNumberOfElements('tr', 10); + * $I->seeNumberOfElements('tr', [0,10]); //between 0 and 10 elements + * ?> + * ``` + * @param $selector + * @param mixed $expected: + * - string: strict number + * - array: range of numbers [0,10] + * @see \Codeception\Lib\InnerBrowser::seeNumberOfElements() + */ + public function seeNumberOfElements($selector, $expected) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeNumberOfElements', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the given option is selected. + * + * ``` php + * seeOptionIsSelected('#form input[name=payment]', 'Visa'); + * ?> + * ``` + * + * @param $selector + * @param $optionText + * + * @return mixed + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::seeOptionIsSelected() + */ + public function canSeeOptionIsSelected($select, $optionText) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeOptionIsSelected', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the given option is selected. + * + * ``` php + * seeOptionIsSelected('#form input[name=payment]', 'Visa'); + * ?> + * ``` + * + * @param $selector + * @param $optionText + * + * @return mixed + * @see \Codeception\Lib\InnerBrowser::seeOptionIsSelected() + */ + public function seeOptionIsSelected($select, $optionText) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeOptionIsSelected', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the given option is not selected. + * + * ``` php + * dontSeeOptionIsSelected('#form input[name=payment]', 'Visa'); + * ?> + * ``` + * + * @param $selector + * @param $optionText + * + * @return mixed + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::dontSeeOptionIsSelected() + */ + public function cantSeeOptionIsSelected($select, $optionText) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeOptionIsSelected', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the given option is not selected. + * + * ``` php + * dontSeeOptionIsSelected('#form input[name=payment]', 'Visa'); + * ?> + * ``` + * + * @param $selector + * @param $optionText + * + * @return mixed + * @see \Codeception\Lib\InnerBrowser::dontSeeOptionIsSelected() + */ + public function dontSeeOptionIsSelected($select, $optionText) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeOptionIsSelected', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Asserts that current page has 404 response status code. + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::seePageNotFound() + */ + public function canSeePageNotFound() { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seePageNotFound', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Asserts that current page has 404 response status code. + * @see \Codeception\Lib\InnerBrowser::seePageNotFound() + */ + public function seePageNotFound() { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seePageNotFound', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks response code equals to provided value. + * + * @param $code + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Module\REST::seeResponseCodeIs() + */ + public function canSeeResponseCodeIs($code) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseCodeIs', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks response code equals to provided value. + * + * @param $code + * @see \Codeception\Module\REST::seeResponseCodeIs() + */ + public function seeResponseCodeIs($code) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseCodeIs', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the page title contains the given string. + * + * ``` php + * seeInTitle('Blog - Post #1'); + * ?> + * ``` + * + * @param $title + * + * @return mixed + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::seeInTitle() + */ + public function canSeeInTitle($title) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeInTitle', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the page title contains the given string. + * + * ``` php + * seeInTitle('Blog - Post #1'); + * ?> + * ``` + * + * @param $title + * + * @return mixed + * @see \Codeception\Lib\InnerBrowser::seeInTitle() + */ + public function seeInTitle($title) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeInTitle', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the page title does not contain the given string. + * + * @param $title + * + * @return mixed + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Lib\InnerBrowser::dontSeeInTitle() + */ + public function cantSeeInTitle($title) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInTitle', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that the page title does not contain the given string. + * + * @param $title + * + * @return mixed + * @see \Codeception\Lib\InnerBrowser::dontSeeInTitle() + */ + public function dontSeeInTitle($title) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeInTitle', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Sets HTTP header + * + * @param $name + * @param $value + * @see \Codeception\Module\REST::haveHttpHeader() + */ + public function haveHttpHeader($name, $value) { + return $this->scenario->runStep(new \Codeception\Step\Action('haveHttpHeader', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks over the given HTTP header and (optionally) + * its value, asserting that are there + * + * @param $name + * @param $value + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Module\REST::seeHttpHeader() + */ + public function canSeeHttpHeader($name, $value = null) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeHttpHeader', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks over the given HTTP header and (optionally) + * its value, asserting that are there + * + * @param $name + * @param $value + * @see \Codeception\Module\REST::seeHttpHeader() + */ + public function seeHttpHeader($name, $value = null) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeHttpHeader', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks over the given HTTP header and (optionally) + * its value, asserting that are not there + * + * @param $name + * @param $value + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Module\REST::dontSeeHttpHeader() + */ + public function cantSeeHttpHeader($name, $value = null) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeHttpHeader', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks over the given HTTP header and (optionally) + * its value, asserting that are not there + * + * @param $name + * @param $value + * @see \Codeception\Module\REST::dontSeeHttpHeader() + */ + public function dontSeeHttpHeader($name, $value = null) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeHttpHeader', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that http response header is received only once. + * HTTP RFC2616 allows multiple response headers with the same name. + * You can check that you didn't accidentally sent the same header twice. + * + * ``` php + * seeHttpHeaderOnce('Cache-Control'); + * ?>> + * ``` + * + * @param $name + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Module\REST::seeHttpHeaderOnce() + */ + public function canSeeHttpHeaderOnce($name) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeHttpHeaderOnce', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that http response header is received only once. + * HTTP RFC2616 allows multiple response headers with the same name. + * You can check that you didn't accidentally sent the same header twice. + * + * ``` php + * seeHttpHeaderOnce('Cache-Control'); + * ?>> + * ``` + * + * @param $name + * @see \Codeception\Module\REST::seeHttpHeaderOnce() + */ + public function seeHttpHeaderOnce($name) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeHttpHeaderOnce', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Returns the value of the specified header name + * + * @param $name + * @param Boolean $first Whether to return the first value or all header values + * + * @return string|array The first header value if $first is true, an array of values otherwise + * @see \Codeception\Module\REST::grabHttpHeader() + */ + public function grabHttpHeader($name, $first = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('grabHttpHeader', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Adds Digest authentication via username/password. + * + * @param $username + * @param $password + * @see \Codeception\Module\REST::amDigestAuthenticated() + */ + public function amDigestAuthenticated($username, $password) { + return $this->scenario->runStep(new \Codeception\Step\Condition('amDigestAuthenticated', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Adds Bearer authentication via access token. + * + * @param $accessToken + * @see \Codeception\Module\REST::amBearerAuthenticated() + */ + public function amBearerAuthenticated($accessToken) { + return $this->scenario->runStep(new \Codeception\Step\Condition('amBearerAuthenticated', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Sends a POST request to given uri. + * + * Parameters and files (as array of filenames) can be provided. + * + * @param $url + * @param array|\JsonSerializable $params + * @param array $files + * @see \Codeception\Module\REST::sendPOST() + */ + public function sendPOST($url, $params = null, $files = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('sendPOST', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Sends a HEAD request to given uri. + * + * @param $url + * @param array $params + * @see \Codeception\Module\REST::sendHEAD() + */ + public function sendHEAD($url, $params = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('sendHEAD', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Sends an OPTIONS request to given uri. + * + * @param $url + * @param array $params + * @see \Codeception\Module\REST::sendOPTIONS() + */ + public function sendOPTIONS($url, $params = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('sendOPTIONS', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Sends a GET request to given uri. + * + * @param $url + * @param array $params + * @see \Codeception\Module\REST::sendGET() + */ + public function sendGET($url, $params = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('sendGET', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Sends PUT request to given uri. + * + * @param $url + * @param array $params + * @param array $files + * @see \Codeception\Module\REST::sendPUT() + */ + public function sendPUT($url, $params = null, $files = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('sendPUT', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Sends PATCH request to given uri. + * + * @param $url + * @param array $params + * @param array $files + * @see \Codeception\Module\REST::sendPATCH() + */ + public function sendPATCH($url, $params = null, $files = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('sendPATCH', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Sends DELETE request to given uri. + * + * @param $url + * @param array $params + * @param array $files + * @see \Codeception\Module\REST::sendDELETE() + */ + public function sendDELETE($url, $params = null, $files = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('sendDELETE', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Sends LINK request to given uri. + * + * @param $url + * @param array $linkEntries (entry is array with keys "uri" and "link-param") + * + * @link http://tools.ietf.org/html/rfc2068#section-19.6.2.4 + * + * @author samva.ua@gmail.com + * @see \Codeception\Module\REST::sendLINK() + */ + public function sendLINK($url, $linkEntries) { + return $this->scenario->runStep(new \Codeception\Step\Action('sendLINK', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Sends UNLINK request to given uri. + * + * @param $url + * @param array $linkEntries (entry is array with keys "uri" and "link-param") + * @link http://tools.ietf.org/html/rfc2068#section-19.6.2.4 + * @author samva.ua@gmail.com + * @see \Codeception\Module\REST::sendUNLINK() + */ + public function sendUNLINK($url, $linkEntries) { + return $this->scenario->runStep(new \Codeception\Step\Action('sendUNLINK', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks whether last response was valid JSON. + * This is done with json_last_error function. + * + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Module\REST::seeResponseIsJson() + */ + public function canSeeResponseIsJson() { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseIsJson', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks whether last response was valid JSON. + * This is done with json_last_error function. + * + * @see \Codeception\Module\REST::seeResponseIsJson() + */ + public function seeResponseIsJson() { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseIsJson', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks whether last response was valid XML. + * This is done with libxml_get_last_error function. + * + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Module\REST::seeResponseIsXml() + */ + public function canSeeResponseIsXml() { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseIsXml', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks whether last response was valid XML. + * This is done with libxml_get_last_error function. + * + * @see \Codeception\Module\REST::seeResponseIsXml() + */ + public function seeResponseIsXml() { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseIsXml', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks whether the last response contains text. + * + * @param $text + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Module\REST::seeResponseContains() + */ + public function canSeeResponseContains($text) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseContains', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks whether the last response contains text. + * + * @param $text + * @see \Codeception\Module\REST::seeResponseContains() + */ + public function seeResponseContains($text) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseContains', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks whether last response do not contain text. + * + * @param $text + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Module\REST::dontSeeResponseContains() + */ + public function cantSeeResponseContains($text) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeResponseContains', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks whether last response do not contain text. + * + * @param $text + * @see \Codeception\Module\REST::dontSeeResponseContains() + */ + public function dontSeeResponseContains($text) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeResponseContains', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks whether the last JSON response contains provided array. + * The response is converted to array with json_decode($response, true) + * Thus, JSON is represented by associative array. + * This method matches that response array contains provided array. + * + * Examples: + * + * ``` php + * seeResponseContainsJson(array('name' => 'john')); + * + * // response {user: john, profile: { email: john@gmail.com }} + * $I->seeResponseContainsJson(array('email' => 'john@gmail.com')); + * + * ?> + * ``` + * + * This method recursively checks if one array can be found inside of another. + * + * @param array $json + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Module\REST::seeResponseContainsJson() + */ + public function canSeeResponseContainsJson($json = null) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseContainsJson', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks whether the last JSON response contains provided array. + * The response is converted to array with json_decode($response, true) + * Thus, JSON is represented by associative array. + * This method matches that response array contains provided array. + * + * Examples: + * + * ``` php + * seeResponseContainsJson(array('name' => 'john')); + * + * // response {user: john, profile: { email: john@gmail.com }} + * $I->seeResponseContainsJson(array('email' => 'john@gmail.com')); + * + * ?> + * ``` + * + * This method recursively checks if one array can be found inside of another. + * + * @param array $json + * @see \Codeception\Module\REST::seeResponseContainsJson() + */ + public function seeResponseContainsJson($json = null) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseContainsJson', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Returns current response so that it can be used in next scenario steps. + * + * Example: + * + * ``` php + * grabResponse(); + * $I->sendPUT('/user', array('id' => $user_id, 'name' => 'davert')); + * ?> + * ``` + * + * @version 1.1 + * @return string + * @see \Codeception\Module\REST::grabResponse() + */ + public function grabResponse() { + return $this->scenario->runStep(new \Codeception\Step\Action('grabResponse', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Returns data from the current JSON response using specified path + * so that it can be used in next scenario steps. + * + * **this method is deprecated in favor of `grabDataFromResponseByJsonPath`** + * + * Example: + * + * ``` php + * grabDataFromJsonResponse('user.user_id'); + * $I->sendPUT('/user', array('id' => $user_id, 'name' => 'davert')); + * ?> + * ``` + * + * @deprecated please use `grabDataFromResponseByJsonPath` + * @param string $path + * @return string + * @see \Codeception\Module\REST::grabDataFromJsonResponse() + */ + public function grabDataFromJsonResponse($path = null) { + return $this->scenario->runStep(new \Codeception\Step\Action('grabDataFromJsonResponse', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Returns data from the current JSON response using [JSONPath](http://goessner.net/articles/JsonPath/) as selector. + * JsonPath is XPath equivalent for querying Json structures. Try your JsonPath expressions [online](http://jsonpath.curiousconcept.com/). + * Even for a single value an array is returned. + * + * This method **require [`flow/jsonpath`](https://github.com/FlowCommunications/JSONPath/) library to be installed**. + * + * Example: + * + * ``` php + * grabDataFromJsonResponse('$..users[0].id'); + * $I->sendPUT('/user', array('id' => $firstUser[0], 'name' => 'davert')); + * ?> + * ``` + * + * @param $jsonPath + * @return array + * @version 2.0.9 + * @throws \Exception + * @see \Codeception\Module\REST::grabDataFromResponseByJsonPath() + */ + public function grabDataFromResponseByJsonPath($jsonPath) { + return $this->scenario->runStep(new \Codeception\Step\Action('grabDataFromResponseByJsonPath', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks if json structure in response matches the xpath provided. + * JSON is not supposed to be checked against XPath, yet it can be converted to xml and used with XPath. + * This assertion allows you to check the structure of response json. + * * + * ```json + * ```json + * { "store": { + * "book": [ + * { "category": "reference", + * "author": "Nigel Rees", + * "title": "Sayings of the Century", + * "price": 8.95 + * }, + * { "category": "fiction", + * "author": "Evelyn Waugh", + * "title": "Sword of Honour", + * "price": 12.99 + * } + * ], + * "bicycle": { + * "color": "red", + * "price": 19.95 + * } + * } + * } + * ``` + * + * ```php + * seeResponseJsonMatchesXpath('//store/book/author'); + * // first book in store has author + * $I->seeResponseJsonMatchesXpath('//store/book[1]/author'); + * // at least one item in store has price + * $I->seeResponseJsonMatchesXpath('/store//price'); + * ?> + * ``` + * + * @version 2.0.9 + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Module\REST::seeResponseJsonMatchesXpath() + */ + public function canSeeResponseJsonMatchesXpath($xpath) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseJsonMatchesXpath', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks if json structure in response matches the xpath provided. + * JSON is not supposed to be checked against XPath, yet it can be converted to xml and used with XPath. + * This assertion allows you to check the structure of response json. + * * + * ```json + * ```json + * { "store": { + * "book": [ + * { "category": "reference", + * "author": "Nigel Rees", + * "title": "Sayings of the Century", + * "price": 8.95 + * }, + * { "category": "fiction", + * "author": "Evelyn Waugh", + * "title": "Sword of Honour", + * "price": 12.99 + * } + * ], + * "bicycle": { + * "color": "red", + * "price": 19.95 + * } + * } + * } + * ``` + * + * ```php + * seeResponseJsonMatchesXpath('//store/book/author'); + * // first book in store has author + * $I->seeResponseJsonMatchesXpath('//store/book[1]/author'); + * // at least one item in store has price + * $I->seeResponseJsonMatchesXpath('/store//price'); + * ?> + * ``` + * + * @version 2.0.9 + * @see \Codeception\Module\REST::seeResponseJsonMatchesXpath() + */ + public function seeResponseJsonMatchesXpath($xpath) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseJsonMatchesXpath', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks if json structure in response matches [JsonPath](http://goessner.net/articles/JsonPath/). + * JsonPath is XPath equivalent for querying Json structures. Try your JsonPath expressions [online](http://jsonpath.curiousconcept.com/). + * This assertion allows you to check the structure of response json. + * + * This method **require [`flow/jsonpath`](https://github.com/FlowCommunications/JSONPath/) library to be installed**. + * + * ```json + * { "store": { + * "book": [ + * { "category": "reference", + * "author": "Nigel Rees", + * "title": "Sayings of the Century", + * "price": 8.95 + * }, + * { "category": "fiction", + * "author": "Evelyn Waugh", + * "title": "Sword of Honour", + * "price": 12.99 + * } + * ], + * "bicycle": { + * "color": "red", + * "price": 19.95 + * } + * } + * } + * ``` + * + * ```php + * seeResponseJsonMatchesJsonPath('$.store.book[*].author'); + * // first book in store has author + * $I->seeResponseJsonMatchesJsonPath('$.store.book[0].author'); + * // at least one item in store has price + * $I->seeResponseJsonMatchesJsonPath('$.store..price'); + * ?> + * ``` + * + * @version 2.0.9 + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Module\REST::seeResponseJsonMatchesJsonPath() + */ + public function canSeeResponseJsonMatchesJsonPath($jsonPath) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseJsonMatchesJsonPath', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks if json structure in response matches [JsonPath](http://goessner.net/articles/JsonPath/). + * JsonPath is XPath equivalent for querying Json structures. Try your JsonPath expressions [online](http://jsonpath.curiousconcept.com/). + * This assertion allows you to check the structure of response json. + * + * This method **require [`flow/jsonpath`](https://github.com/FlowCommunications/JSONPath/) library to be installed**. + * + * ```json + * { "store": { + * "book": [ + * { "category": "reference", + * "author": "Nigel Rees", + * "title": "Sayings of the Century", + * "price": 8.95 + * }, + * { "category": "fiction", + * "author": "Evelyn Waugh", + * "title": "Sword of Honour", + * "price": 12.99 + * } + * ], + * "bicycle": { + * "color": "red", + * "price": 19.95 + * } + * } + * } + * ``` + * + * ```php + * seeResponseJsonMatchesJsonPath('$.store.book[*].author'); + * // first book in store has author + * $I->seeResponseJsonMatchesJsonPath('$.store.book[0].author'); + * // at least one item in store has price + * $I->seeResponseJsonMatchesJsonPath('$.store..price'); + * ?> + * ``` + * + * @version 2.0.9 + * @see \Codeception\Module\REST::seeResponseJsonMatchesJsonPath() + */ + public function seeResponseJsonMatchesJsonPath($jsonPath) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseJsonMatchesJsonPath', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Opposite to seeResponseContainsJson + * + * @param array $json + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Module\REST::dontSeeResponseContainsJson() + */ + public function cantSeeResponseContainsJson($json = null) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeResponseContainsJson', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Opposite to seeResponseContainsJson + * + * @param array $json + * @see \Codeception\Module\REST::dontSeeResponseContainsJson() + */ + public function dontSeeResponseContainsJson($json = null) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeResponseContainsJson', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks if response is exactly the same as provided. + * + * @param $response + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Module\REST::seeResponseEquals() + */ + public function canSeeResponseEquals($response) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseEquals', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks if response is exactly the same as provided. + * + * @param $response + * @see \Codeception\Module\REST::seeResponseEquals() + */ + public function seeResponseEquals($response) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseEquals', func_get_args())); + } + + + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that response code is not equal to provided value. + * + * @param $code + * Conditional Assertion: Test won't be stopped on fail + * @see \Codeception\Module\REST::dontSeeResponseCodeIs() + */ + public function cantSeeResponseCodeIs($code) { + return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeResponseCodeIs', func_get_args())); + } + /** + * [!] Method is generated. Documentation taken from corresponding module. + * + * Checks that response code is not equal to provided value. + * + * @param $code + * @see \Codeception\Module\REST::dontSeeResponseCodeIs() + */ + public function dontSeeResponseCodeIs($code) { + return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeResponseCodeIs', func_get_args())); + } +} diff --git a/tests/api/ClientCredentialsCept.php b/tests/api/ClientCredentialsCept.php new file mode 100644 index 00000000..f1a3ad20 --- /dev/null +++ b/tests/api/ClientCredentialsCept.php @@ -0,0 +1,17 @@ +wantTo('get an access token using the client credentials grant'); +$I->sendPOST( + '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/_bootstrap.php b/tests/api/_bootstrap.php new file mode 100644 index 00000000..8a885558 --- /dev/null +++ b/tests/api/_bootstrap.php @@ -0,0 +1,2 @@ + Date: Sun, 5 Apr 2015 17:05:57 +0100 Subject: [PATCH 021/444] Updated grant type interface --- src/Grant/GrantTypeInterface.php | 40 ++++++++++++++------------------ 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index a9468655..5b34dd8b 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -11,7 +11,9 @@ namespace League\OAuth2\Server\Grant; -use League\OAuth2\Server\AuthorizationServer; +use DateInterval; +use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; +use Symfony\Component\HttpFoundation\Request; /** * Grant type interface @@ -26,34 +28,26 @@ interface GrantTypeInterface public function getIdentifier(); /** - * Return the identifier - * - * @param string $identifier - * - * @return self - */ - public function setIdentifier($identifier); - - /** - * Return the response type + * Details what the grant responds with * * @return string */ - public function getResponseType(); + public function respondsWith(); /** - * Inject the authorization server into the grant + * Return an access token * - * @param \League\OAuth2\Server\AuthorizationServer $server The authorization server instance + * @param \Symfony\Component\HttpFoundation\Request $request + * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType + * @param \DateInterval $accessTokenTTL + * @param string $scopeDelimiter * - * @return self + * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface */ - public function setAuthorizationServer(AuthorizationServer $server); - - /** - * Complete the grant flow - * - * @return array - */ - public function completeFlow(); + public function getAccessTokenAsType( + Request $request, + ResponseTypeInterface $responseType, + DateInterval $accessTokenTTL, + $scopeDelimiter = ' ' + ); } From 997d4f2eb7fc459366978f1ac8d01d84a9872c4a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 17:06:05 +0100 Subject: [PATCH 022/444] Updated .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3d7227d0..541d481f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /vendor /composer.lock -.idea \ No newline at end of file +.idea +/examples/vendor \ No newline at end of file From 56f6df11a8d2fbead1c722ef88de977e3e29f365 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 17:07:10 +0100 Subject: [PATCH 023/444] Updated .gitignore --- .travis.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fe0efb10..fbe22965 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,22 @@ language: php +sudo: false + +cache: + directories: + - vendor + php: - 5.4 - 5.5 - 5.6 + - 7.0 - hhvm + +matrix: + allow_failures: + - php: 7.0 + fast_finish: true install: - travis_retry composer install --no-interaction --prefer-source @@ -41,4 +53,4 @@ notifications: - https://webhooks.gitter.im/e/7de0ca12596cd5268f30 on_success: always # options: [always|never|change] default: always on_failure: always # options: [always|never|change] default: always - on_start: false # default: false + on_start: false # default: false \ No newline at end of file From 26c1abdd3cacbcd489a357224487fa7e4bd09a96 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 17:13:55 +0100 Subject: [PATCH 024/444] Remove client secret propety on entity --- .../src/Repositories/ClientRepository.php | 1 - .../Interfaces/ClientEntityInterface.php | 13 ---------- src/Entities/Traits/ClientEntityTrait.php | 24 ------------------- 3 files changed, 38 deletions(-) diff --git a/examples/src/Repositories/ClientRepository.php b/examples/src/Repositories/ClientRepository.php index af69cc2f..286964ac 100644 --- a/examples/src/Repositories/ClientRepository.php +++ b/examples/src/Repositories/ClientRepository.php @@ -44,7 +44,6 @@ class ClientRepository implements ClientRepositoryInterface $client = new ClientEntity(); $client->setIdentifier($clientIdentifier); $client->setName($clients[$clientIdentifier]['name']); - $client->setSecret($clients[$clientIdentifier]['secret']); return $client; } diff --git a/src/Entities/Interfaces/ClientEntityInterface.php b/src/Entities/Interfaces/ClientEntityInterface.php index c32d1e78..c0d0e812 100644 --- a/src/Entities/Interfaces/ClientEntityInterface.php +++ b/src/Entities/Interfaces/ClientEntityInterface.php @@ -15,19 +15,6 @@ interface ClientEntityInterface */ public function setIdentifier($identifier); - /** - * Get the client's secret - * @return string - */ - public function getSecret(); - - /** - * Set the client's secret - * @param string $secret - * @return string - */ - public function setSecret($secret); - /** * Get the client's name * @return string diff --git a/src/Entities/Traits/ClientEntityTrait.php b/src/Entities/Traits/ClientEntityTrait.php index 46528f21..fee28e0e 100644 --- a/src/Entities/Traits/ClientEntityTrait.php +++ b/src/Entities/Traits/ClientEntityTrait.php @@ -3,35 +3,11 @@ namespace League\OAuth2\Server\Entities\Traits; trait ClientEntityTrait { - /** - * @var string - */ - protected $secret; - /** * @var string */ protected $name; - /** - * Get the client's secret - * @return string - */ - public function getSecret() - { - return $this->secret; - } - - /** - * Set the client's secret - * @param string $secret - * @return string - */ - public function setSecret($secret) - { - $this->secret = $secret; - } - /** * Get the client's name * @return string From 72b741d7c91a0dc17ab0d73ed43ae1ccf47f3313 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 18:16:21 +0100 Subject: [PATCH 025/444] Added generateHttpResponse method to exception --- src/Exception/OAuthException.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Exception/OAuthException.php b/src/Exception/OAuthException.php index e8e5e723..653ee65b 100644 --- a/src/Exception/OAuthException.php +++ b/src/Exception/OAuthException.php @@ -127,4 +127,22 @@ class OAuthException extends \Exception // @codeCoverageIgnoreEnd return $headers; } + + /** + * Generate a HTTP response + * @return \Symfony\Component\HttpFoundation\Response + */ + public function generateHttpResponse() + { + return new Response( + json_encode( + [ + 'error' => $this->errorType, + 'message' => $this->getMessage() + ] + ), + $this->httpStatusCode, + $this->getHttpHeaders() + ); + } } From 15cef6ba16ac9ed65eb60e0e172a8723c44fa28f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 18:16:26 +0100 Subject: [PATCH 026/444] Code tidy --- src/Exception/OAuthException.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Exception/OAuthException.php b/src/Exception/OAuthException.php index 653ee65b..fa8b465b 100644 --- a/src/Exception/OAuthException.php +++ b/src/Exception/OAuthException.php @@ -13,6 +13,7 @@ namespace League\OAuth2\Server\Exception; use League\OAuth2\Server\Util\RedirectUri; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; /** * Exception class @@ -66,8 +67,8 @@ class OAuthException extends \Exception return RedirectUri::make( $this->redirectUri, [ - 'error' => $this->errorType, - 'message' => $this->getMessage(), + 'error' => $this->errorType, + 'message' => $this->getMessage(), ] ); } @@ -121,7 +122,7 @@ class OAuthException extends \Exception } } if ($authScheme !== null) { - $headers[] = 'WWW-Authenticate: '.$authScheme.' realm=""'; + $headers[] = 'WWW-Authenticate: ' . $authScheme . ' realm=""'; } } // @codeCoverageIgnoreEnd From f3705865a3c49428db7c3ec6e908a2ac3f737ff2 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 18:17:36 +0100 Subject: [PATCH 027/444] Ignore codeception output --- .gitignore | 3 ++- tests/_output/ClientCredentialsCept.fail.html | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 tests/_output/ClientCredentialsCept.fail.html diff --git a/.gitignore b/.gitignore index 541d481f..dd33e3eb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /vendor /composer.lock .idea -/examples/vendor \ No newline at end of file +/examples/vendor +/tests/_output \ No newline at end of file diff --git a/tests/_output/ClientCredentialsCept.fail.html b/tests/_output/ClientCredentialsCept.fail.html deleted file mode 100644 index d50bc270..00000000 --- a/tests/_output/ClientCredentialsCept.fail.html +++ /dev/null @@ -1 +0,0 @@ -{"error":{"message":"The requested scope is invalid, unknown, or malformed. Check the \"basic\" scope.","trace":["#0 \/Users\/alexbilbie\/Projects\/oauth2-server\/src\/Grant\/ClientCredentialsGrant.php(77): League\\OAuth2\\Server\\Grant\\AbstractGrant->validateScopes('basic', Object(League\\OAuth2\\Server\\Entities\\ClientEntity))","#1 \/Users\/alexbilbie\/Projects\/oauth2-server\/src\/Server.php(117): League\\OAuth2\\Server\\Grant\\ClientCredentialsGrant->getAccessTokenAsType(Object(Symfony\\Component\\HttpFoundation\\Request), Object(League\\OAuth2\\Server\\ResponseTypes\\BearerTokenResponseType), Object(DateInterval))","#2 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/client-credentials\/index.php(19): League\\OAuth2\\Server\\Server->getAccessTokenResponse(Object(Symfony\\Component\\HttpFoundation\\Request))","#3 [internal function]: {closure}(Object(Symfony\\Component\\HttpFoundation\\Request), Object(Symfony\\Component\\HttpFoundation\\Response), Array)","#4 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/vendor\/league\/route\/src\/Strategy\/AbstractStrategy.php(55): call_user_func_array(Object(Closure), Array)","#5 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/vendor\/league\/route\/src\/Strategy\/RequestResponseStrategy.php(19): League\\Route\\Strategy\\AbstractStrategy->invokeController(Object(Closure), Array)","#6 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/vendor\/league\/route\/src\/Dispatcher.php(112): League\\Route\\Strategy\\RequestResponseStrategy->dispatch(Object(Closure), Array)","#7 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/vendor\/league\/route\/src\/Dispatcher.php(73): League\\Route\\Dispatcher->handleFound(Object(Closure), Object(League\\Route\\Strategy\\RequestResponseStrategy), Array)","#8 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/vendor\/alexbilbie\/proton\/src\/Application.php(251): League\\Route\\Dispatcher->dispatch('POST', '\/access_token')","#9 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/vendor\/alexbilbie\/proton\/src\/Application.php(300): Proton\\Application->handle(Object(Symfony\\Component\\HttpFoundation\\Request))","#10 \/Users\/alexbilbie\/Projects\/oauth2-server\/examples\/client-credentials\/index.php(23): Proton\\Application->run()","#11 {main}"]}} \ No newline at end of file From 775d42115a96e294d0b1aa864810776726ef7b05 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 18:18:09 +0100 Subject: [PATCH 028/444] More client credentials test --- tests/api/ClientCredentialsCept.php | 2 +- .../ClientCredentialsInvalidClientIdCept.php | 17 +++++++++++++++++ ...ClientCredentialsInvalidClientSecretCept.php | 17 +++++++++++++++++ .../ClientCredentialsMissingClientIdCept.php | 15 +++++++++++++++ ...ClientCredentialsMissingClientSecretCept.php | 16 ++++++++++++++++ 5 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 tests/api/ClientCredentialsInvalidClientIdCept.php create mode 100644 tests/api/ClientCredentialsInvalidClientSecretCept.php create mode 100644 tests/api/ClientCredentialsMissingClientIdCept.php create mode 100644 tests/api/ClientCredentialsMissingClientSecretCept.php diff --git a/tests/api/ClientCredentialsCept.php b/tests/api/ClientCredentialsCept.php index f1a3ad20..f0eff536 100644 --- a/tests/api/ClientCredentialsCept.php +++ b/tests/api/ClientCredentialsCept.php @@ -2,7 +2,7 @@ $I = new ApiTester($scenario); $I->wantTo('get an access token using the client credentials grant'); $I->sendPOST( - 'access_token', + 'client_credentials.php/access_token', [ 'grant_type' => 'client_credentials', 'client_id' => 'myawesomeapp', diff --git a/tests/api/ClientCredentialsInvalidClientIdCept.php b/tests/api/ClientCredentialsInvalidClientIdCept.php new file mode 100644 index 00000000..97f9fce4 --- /dev/null +++ b/tests/api/ClientCredentialsInvalidClientIdCept.php @@ -0,0 +1,17 @@ +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 new file mode 100644 index 00000000..fe4f88fc --- /dev/null +++ b/tests/api/ClientCredentialsInvalidClientSecretCept.php @@ -0,0 +1,17 @@ +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 new file mode 100644 index 00000000..68135cdb --- /dev/null +++ b/tests/api/ClientCredentialsMissingClientIdCept.php @@ -0,0 +1,15 @@ +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 new file mode 100644 index 00000000..369e22d6 --- /dev/null +++ b/tests/api/ClientCredentialsMissingClientSecretCept.php @@ -0,0 +1,16 @@ +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.' +]); From 9048617e355ea0768fca3b9e5d64001851730c0f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 18:18:28 +0100 Subject: [PATCH 029/444] Updated client credentials example --- examples/client-credentials/index.php | 23 ----------------- examples/public/client_credentials.php | 34 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 23 deletions(-) delete mode 100644 examples/client-credentials/index.php create mode 100644 examples/public/client_credentials.php diff --git a/examples/client-credentials/index.php b/examples/client-credentials/index.php deleted file mode 100644 index de29ebe8..00000000 --- a/examples/client-credentials/index.php +++ /dev/null @@ -1,23 +0,0 @@ -addRepository(new \OAuth2ServerExamples\Repositories\ClientRepository()); -$server->addRepository(new \OAuth2ServerExamples\Repositories\ScopeRepository()); -$server->addRepository(new \OAuth2ServerExamples\Repositories\AccessTokenRepository()); - -// Enable the client credentials grant which will return access tokens that last for 24 hours -$server->enableGrantType('ClientCredentialsGrant', null, new \DateInterval('PT24H')); - -// Setup the routing -$application = new \Proton\Application(); -$application->post('/access_token', function (Request $request) use ($server) { - return $server->getAccessTokenResponse($request); -}); - -// Run the app -$application->run(); diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php new file mode 100644 index 00000000..e129ac2b --- /dev/null +++ b/examples/public/client_credentials.php @@ -0,0 +1,34 @@ +addRepository(new ClientRepository()); +$server->addRepository(new ScopeRepository()); +$server->addRepository(new AccessTokenRepository()); + +// Enable the client credentials grant which will return access tokens that last for 24 hours +$server->enableGrantType('ClientCredentialsGrant', null, new \DateInterval('PT24H')); + +// Setup routing +$application = new \Proton\Application(); +$application->post('/access_token', function (Request $request) use ($server) { + + try { + return $server->getAccessTokenResponse($request); + } catch (OAuthException $e) { + return $e->generateHttpResponse(); + } + +}); + +// Run the app +$application->run(); From 2b2067e162b3a1c94610229b48e1026598822b03 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 18:19:37 +0100 Subject: [PATCH 030/444] Updated .travis.yml --- .travis.yml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index fbe22965..7db1a5d6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ install: script: - mkdir -p build/logs - - phpunit --coverage-text --verbose --coverage-clover=coverage.clover --coverage-html coverage + - vendor/bin/codecept run after_script: - wget https://scrutinizer-ci.com/ocular.phar @@ -43,14 +43,7 @@ after_script: branches: only: - master + env: global: - secure: "C4wD/BQefKSu9W594iyLp+IBCjlM8kKlmp+nXKXnZGi0L8IkV3m4mmNOb8PExxGMhZ3mlev5DnU4Uoh4oJaUxnkR1FpX4dSEpyzU3VknUzSE2yZOlL+bdCw3o85TGoCcp/+ReJCOw5sncxTskJKHlW1YMa33FznaXwLNoImpjTg=" - -notifications: - webhooks: - urls: - - https://webhooks.gitter.im/e/7de0ca12596cd5268f30 - on_success: always # options: [always|never|change] default: always - on_failure: always # options: [always|never|change] default: always - on_start: false # default: false \ No newline at end of file + secure: "C4wD/BQefKSu9W594iyLp+IBCjlM8kKlmp+nXKXnZGi0L8IkV3m4mmNOb8PExxGMhZ3mlev5DnU4Uoh4oJaUxnkR1FpX4dSEpyzU3VknUzSE2yZOlL+bdCw3o85TGoCcp/+ReJCOw5sncxTskJKHlW1YMa33FznaXwLNoImpjTg=" \ No newline at end of file From 476b8d81c189f5d5bc03a99d4b3409509138455c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 18:21:57 +0100 Subject: [PATCH 031/444] Build v5 branch --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 7db1a5d6..63241767 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,9 +40,11 @@ after_script: - 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 + branches: only: - master + - v5 env: global: From f912f60a59eef0e72fa391c17b5eb5976560efd1 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 18:26:09 +0100 Subject: [PATCH 032/444] Added .travis.yml before_script --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index 63241767..f1eab18e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,12 @@ matrix: install: - travis_retry composer install --no-interaction --prefer-source +before_script: + - cd examples/ + - composer install + - cd public/ + - php -S localhost:7777 index.php & + script: - mkdir -p build/logs - vendor/bin/codecept run From ffc8823e4f50f57104d47b0f4a935e8857f74da8 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 18:28:07 +0100 Subject: [PATCH 033/444] Move out of directory --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f1eab18e..ab907944 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,9 +26,9 @@ before_script: - composer install - cd public/ - php -S localhost:7777 index.php & + - cd ../.. script: - - mkdir -p build/logs - vendor/bin/codecept run after_script: From 5211d1902cd78cde11450f6234a143e1608f597b Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 18:35:26 +0100 Subject: [PATCH 034/444] Fixed .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ab907944..1a3e568f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ before_script: - cd examples/ - composer install - cd public/ - - php -S localhost:7777 index.php & + - php -S localhost:7777 & - cd ../.. script: From 4f053bb63a0c7ca8649e9e674d723ec59485173c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 18:42:18 +0100 Subject: [PATCH 035/444] Added ircmaxell/password-compat so tests pass on < PHP 5.5 --- examples/composer.json | 3 ++- examples/composer.lock | 44 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/examples/composer.json b/examples/composer.json index 6485183e..572002da 100644 --- a/examples/composer.json +++ b/examples/composer.json @@ -2,7 +2,8 @@ "name": "", "require": { "alexbilbie/proton": "~1.4", - "illuminate/database": "~5.0" + "illuminate/database": "~5.0", + "ircmaxell/password-compat": "~1.0" }, "autoload": { "psr-4": { diff --git a/examples/composer.lock b/examples/composer.lock index 30e6f2f6..8bc48e8e 100644 --- a/examples/composer.lock +++ b/examples/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "1b6c8d343ed4a6d2ff7b178d989d7516", + "hash": "8d3e15426ebda5d273b960d5c9f373b5", "packages": [ { "name": "alexbilbie/proton", @@ -381,6 +381,48 @@ "homepage": "http://laravel.com", "time": "2015-03-27 14:49:11" }, + { + "name": "ircmaxell/password-compat", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/ircmaxell/password_compat.git", + "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ircmaxell/password_compat/zipball/5c5cde8822a69545767f7c7f3058cb15ff84614c", + "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "autoload": { + "files": [ + "lib/password.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anthony Ferrara", + "email": "ircmaxell@php.net", + "homepage": "http://blog.ircmaxell.com" + } + ], + "description": "A compatibility library for the proposed simplified password hashing algorithm: https://wiki.php.net/rfc/password_hash", + "homepage": "https://github.com/ircmaxell/password_compat", + "keywords": [ + "hashing", + "password" + ], + "time": "2014-11-20 16:49:30" + }, { "name": "league/container", "version": "1.3.1", From 784af673677cde3b353530cda90d693f57dacc26 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 18:42:24 +0100 Subject: [PATCH 036/444] Code tidy --- examples/public/client_credentials.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index e129ac2b..1075fe14 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -18,16 +18,14 @@ $server->addRepository(new AccessTokenRepository()); // Enable the client credentials grant which will return access tokens that last for 24 hours $server->enableGrantType('ClientCredentialsGrant', null, new \DateInterval('PT24H')); -// Setup routing +// Setup app + routing $application = new \Proton\Application(); $application->post('/access_token', function (Request $request) use ($server) { - try { return $server->getAccessTokenResponse($request); } catch (OAuthException $e) { return $e->generateHttpResponse(); } - }); // Run the app From 6e73099d8c2e366a5d32a46a7cb30558251379f4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 18:51:46 +0100 Subject: [PATCH 037/444] Ignore hhvm failures for now --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 1a3e568f..9bce3e7a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,7 @@ php: matrix: allow_failures: - php: 7.0 + - php: hhvm fast_finish: true install: From 721e52c5d97c3e5766554115402227cf9be2edbf Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:10:06 +0100 Subject: [PATCH 038/444] Renamed response types to token types --- ...Interface.php => RefreshTokenRepositoryInterface.php} | 0 ...erProvider.php => ClientCredentialsGrantProvider.php} | 0 .../AbstractTokenType.php} | 6 +++--- .../BearerTokenType.php} | 4 ++-- src/{ResponseTypes => TokenTypes}/MAC.php | 0 .../TokenTypeInterface.php} | 9 +++------ 6 files changed, 8 insertions(+), 11 deletions(-) rename src/Repositories/{RefreshTokenInterface.php => RefreshTokenRepositoryInterface.php} (100%) rename src/ServiceProviders/{ClientCredentialsGrantServerProvider.php => ClientCredentialsGrantProvider.php} (100%) rename src/{ResponseTypes/AbstractResponseType.php => TokenTypes/AbstractTokenType.php} (87%) rename src/{ResponseTypes/BearerTokenResponseType.php => TokenTypes/BearerTokenType.php} (92%) rename src/{ResponseTypes => TokenTypes}/MAC.php (100%) rename src/{ResponseTypes/ResponseTypeInterface.php => TokenTypes/TokenTypeInterface.php} (84%) diff --git a/src/Repositories/RefreshTokenInterface.php b/src/Repositories/RefreshTokenRepositoryInterface.php similarity index 100% rename from src/Repositories/RefreshTokenInterface.php rename to src/Repositories/RefreshTokenRepositoryInterface.php diff --git a/src/ServiceProviders/ClientCredentialsGrantServerProvider.php b/src/ServiceProviders/ClientCredentialsGrantProvider.php similarity index 100% rename from src/ServiceProviders/ClientCredentialsGrantServerProvider.php rename to src/ServiceProviders/ClientCredentialsGrantProvider.php diff --git a/src/ResponseTypes/AbstractResponseType.php b/src/TokenTypes/AbstractTokenType.php similarity index 87% rename from src/ResponseTypes/AbstractResponseType.php rename to src/TokenTypes/AbstractTokenType.php index 5b874c08..47900ca8 100644 --- a/src/ResponseTypes/AbstractResponseType.php +++ b/src/TokenTypes/AbstractTokenType.php @@ -9,12 +9,12 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\ResponseTypes; +namespace League\OAuth2\Server\TokenTypes; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use Symfony\Component\HttpFoundation\Response; -abstract class AbstractResponseType implements ResponseTypeInterface +abstract class AbstractTokenType implements TokenTypeInterface { /** * Response array @@ -45,7 +45,7 @@ abstract class AbstractResponseType implements ResponseTypeInterface } /** - * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken + * {@inheritdoc} */ public function setAccessToken(AccessTokenEntityInterface $accessToken) { diff --git a/src/ResponseTypes/BearerTokenResponseType.php b/src/TokenTypes/BearerTokenType.php similarity index 92% rename from src/ResponseTypes/BearerTokenResponseType.php rename to src/TokenTypes/BearerTokenType.php index b3b61b52..2fb932bf 100644 --- a/src/ResponseTypes/BearerTokenResponseType.php +++ b/src/TokenTypes/BearerTokenType.php @@ -9,11 +9,11 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\ResponseTypes; +namespace League\OAuth2\Server\TokenTypes; use Symfony\Component\HttpFoundation\Request; -class BearerTokenResponseType extends AbstractResponseType +class BearerTokenType extends AbstractTokenType { /** * {@inheritdoc} diff --git a/src/ResponseTypes/MAC.php b/src/TokenTypes/MAC.php similarity index 100% rename from src/ResponseTypes/MAC.php rename to src/TokenTypes/MAC.php diff --git a/src/ResponseTypes/ResponseTypeInterface.php b/src/TokenTypes/TokenTypeInterface.php similarity index 84% rename from src/ResponseTypes/ResponseTypeInterface.php rename to src/TokenTypes/TokenTypeInterface.php index 2bd83dd9..e3e4db22 100644 --- a/src/ResponseTypes/ResponseTypeInterface.php +++ b/src/TokenTypes/TokenTypeInterface.php @@ -9,15 +9,12 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\ResponseTypes; +namespace League\OAuth2\Server\TokenTypes; -use League\OAuth2\Server\AbstractServer; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use League\OAuth2\Server\Entity\SessionEntity; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -interface ResponseTypeInterface +interface ResponseTokenInterface { /** * Generate a response @@ -58,7 +55,7 @@ interface ResponseTypeInterface public function determineAccessTokenInHeader(Request $request); /** - * @return Response + * @return \Symfony\Component\HttpFoundation\Response */ public function generateHttpResponse(); } From b831d19f8d8e70e57075b2d89450c2218d6c6bf7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:10:18 +0100 Subject: [PATCH 039/444] Renamed interface --- src/TokenTypes/TokenTypeInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TokenTypes/TokenTypeInterface.php b/src/TokenTypes/TokenTypeInterface.php index e3e4db22..04fd0610 100644 --- a/src/TokenTypes/TokenTypeInterface.php +++ b/src/TokenTypes/TokenTypeInterface.php @@ -14,7 +14,7 @@ namespace League\OAuth2\Server\TokenTypes; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use Symfony\Component\HttpFoundation\Request; -interface ResponseTokenInterface +interface TokenTypeInterface { /** * Generate a response From 6a78d53d030780dc362cbe00287e64ba3748bb6f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:10:41 +0100 Subject: [PATCH 040/444] Updated grants --- src/Grant/ClientCredentialsGrant.php | 18 +-- src/Grant/GrantTypeInterface.php | 14 +-- src/Grant/PasswordGrant.php | 177 +++++++++++++-------------- 3 files changed, 103 insertions(+), 106 deletions(-) diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index f875143d..39cab779 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -16,7 +16,7 @@ use League\Event\Event; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Exception; -use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; +use League\OAuth2\Server\TokenTypes\TokenTypeInterface; use League\OAuth2\Server\Utils\SecureKey; use Symfony\Component\HttpFoundation\Request; @@ -35,19 +35,19 @@ class ClientCredentialsGrant extends AbstractGrant /** * Return an access token * - * @param \Symfony\Component\HttpFoundation\Request $request - * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType - * @param \DateInterval $accessTokenTTL - * @param string $scopeDelimiter + * @param \Symfony\Component\HttpFoundation\Request $request + * @param \League\OAuth2\Server\TokenTypes\TokenTypeInterface $tokenType + * @param \DateInterval $accessTokenTTL + * @param string $scopeDelimiter * - * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface + * @return \League\OAuth2\Server\TokenTypes\TokenTypeInterface * @throws \League\OAuth2\Server\Exception\InvalidClientException * @throws \League\OAuth2\Server\Exception\InvalidRequestException * @throws \League\OAuth2\Server\Exception\InvalidScopeException */ public function getAccessTokenAsType( Request $request, - ResponseTypeInterface $responseType, + TokenTypeInterface $tokenType, DateInterval $accessTokenTTL, $scopeDelimiter = ' ' ) { @@ -95,8 +95,8 @@ class ClientCredentialsGrant extends AbstractGrant $this->accessTokenRepository->create($accessToken); // Inject access token into token type - $responseType->setAccessToken($accessToken); + $tokenType->setAccessToken($accessToken); - return $responseType; + return $tokenType; } } diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 5b34dd8b..739b2a20 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -12,7 +12,7 @@ namespace League\OAuth2\Server\Grant; use DateInterval; -use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; +use League\OAuth2\Server\TokenTypes\TokenTypeInterface; use Symfony\Component\HttpFoundation\Request; /** @@ -37,16 +37,16 @@ interface GrantTypeInterface /** * Return an access token * - * @param \Symfony\Component\HttpFoundation\Request $request - * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType - * @param \DateInterval $accessTokenTTL - * @param string $scopeDelimiter + * @param \Symfony\Component\HttpFoundation\Request $request + * @param \League\OAuth2\Server\TokenTypes\TokenTypeInterface $tokenType + * @param \DateInterval $accessTokenTTL + * @param string $scopeDelimiter * - * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface + * @return \League\OAuth2\Server\TokenTypes\TokenTypeInterface */ public function getAccessTokenAsType( Request $request, - ResponseTypeInterface $responseType, + TokenTypeInterface $tokenType, DateInterval $accessTokenTTL, $scopeDelimiter = ' ' ); diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 71921085..c29c867c 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -11,13 +11,21 @@ namespace League\OAuth2\Server\Grant; -use League\OAuth2\Server\Entity\AccessTokenEntity; -use League\OAuth2\Server\Entity\ClientEntity; -use League\OAuth2\Server\Entity\RefreshTokenEntity; -use League\OAuth2\Server\Entity\SessionEntity; -use League\OAuth2\Server\Event; +use DateInterval; +use League\Event\Emitter; +use League\Event\Event; +use League\OAuth2\Server\Entities\AccessTokenEntity; +use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception; -use League\OAuth2\Server\Util\SecureKey; +use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\TokenTypes\TokenTypeInterface; +use League\OAuth2\Server\Utils\SecureKey; +use Symfony\Component\HttpFoundation\Request; /** * Password grant class @@ -31,13 +39,6 @@ class PasswordGrant extends AbstractGrant */ protected $identifier = 'password'; - /** - * Response type - * - * @var string - */ - protected $responseType; - /** * Callback to authenticate a user's name and password * @@ -46,137 +47,133 @@ class PasswordGrant extends AbstractGrant protected $callback; /** - * Access token expires in override - * - * @var int + * @var \League\OAuth2\Server\Repositories\UserRepositoryInterface */ - protected $accessTokenTTL; + protected $userRepository; /** - * Set the callback to verify a user's username and password - * - * @param callable $callback The callback function - * - * @return void + * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface */ - public function setVerifyCredentialsCallback(callable $callback) - { - $this->callback = $callback; + protected $refreshTokenRepository; + + /** + * @param \League\Event\Emitter $emitter + * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository + * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository + * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository + * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository + * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository + */ + public function __construct( + Emitter $emitter, + ClientRepositoryInterface $clientRepository, + ScopeRepositoryInterface $scopeRepository, + AccessTokenRepositoryInterface $accessTokenRepository, + UserRepositoryInterface $userRepository, + RefreshTokenRepositoryInterface $refreshTokenRepository = null + ) { + $this->userRepository = $userRepository; + $this->refreshTokenRepository = $refreshTokenRepository; + parent::__construct($emitter, $clientRepository, $scopeRepository, $accessTokenRepository); } /** - * Return the callback function + * Return an access token * - * @return callable + * @param \Symfony\Component\HttpFoundation\Request $request + * @param \League\OAuth2\Server\TokenTypes\TokenTypeInterface $tokenType + * @param \DateInterval $accessTokenTTL + * @param string $scopeDelimiter * - * @throws + * @return \League\OAuth2\Server\TokenTypes\TokenTypeInterface + * @throws \League\OAuth2\Server\Exception\InvalidClientException + * @throws \League\OAuth2\Server\Exception\InvalidCredentialsException + * @throws \League\OAuth2\Server\Exception\InvalidRequestException + * @throws \League\OAuth2\Server\Exception\InvalidScopeException */ - protected function getVerifyCredentialsCallback() - { - if (is_null($this->callback) || !is_callable($this->callback)) { - throw new Exception\ServerErrorException('Null or non-callable callback set on Password grant'); - } - - return $this->callback; - } - - /** - * Complete the password grant - * - * @return array - * - * @throws - */ - public function completeFlow() - { + public function getAccessTokenAsType( + Request $request, + TokenTypeInterface $tokenType, + DateInterval $accessTokenTTL, + $scopeDelimiter = ' ' + ) { // Get the required params - $clientId = $this->server->getRequest()->request->get('client_id', $this->server->getRequest()->getUser()); + $clientId = $request->request->get('client_id', $request->getUser()); if (is_null($clientId)) { throw new Exception\InvalidRequestException('client_id'); } - $clientSecret = $this->server->getRequest()->request->get('client_secret', - $this->server->getRequest()->getPassword()); + $clientSecret = $request->request->get('client_secret', + $request->getPassword()); if (is_null($clientSecret)) { throw new Exception\InvalidRequestException('client_secret'); } // Validate client ID and client secret - $client = $this->server->getClientStorage()->get( + $client = $this->clientRepository->get( $clientId, $clientSecret, null, $this->getIdentifier() ); - if (($client instanceof ClientEntity) === false) { - $this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($this->server->getRequest())); + if (($client instanceof ClientEntityInterface) === false) { + $this->emitter->emit(new Event('client.authentication.failed', $request)); throw new Exception\InvalidClientException(); } - $username = $this->server->getRequest()->request->get('username', null); + $username = $request->request->get('username', null); if (is_null($username)) { throw new Exception\InvalidRequestException('username'); } - $password = $this->server->getRequest()->request->get('password', null); + $password = $request->request->get('password', null); if (is_null($password)) { throw new Exception\InvalidRequestException('password'); } // Check if user's username and password are correct - $userId = call_user_func($this->getVerifyCredentialsCallback(), $username, $password); + $user = $this->userRepository->getByCredentials($username, $password); - if ($userId === false) { - $this->server->getEventEmitter()->emit(new Event\UserAuthenticationFailedEvent($this->server->getRequest())); + if (($user instanceof UserEntityInterface) === false) { + $this->emitter->emit(new Event('user.authentication.failed', $request)); throw new Exception\InvalidCredentialsException(); } // Validate any scopes that are in the request - $scopeParam = $this->server->getRequest()->request->get('scope', ''); - $scopes = $this->validateScopes($scopeParam, $client); - - // Create a new session - $session = new SessionEntity($this->server); - $session->setOwner('user', $userId); - $session->associateClient($client); + $scopeParamValue = $request->request->get('scope', ''); + $scopes = $this->validateScopes($scopeParamValue, $scopeDelimiter, $client); // Generate an access token - $accessToken = new AccessTokenEntity($this->server); - $accessToken->setId(SecureKey::generate()); - $accessToken->setExpireTime($this->getAccessTokenTTL() + time()); + $accessToken = new AccessTokenEntity(); + $accessToken->setIdentifier(SecureKey::generate()); + $accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL)); + $accessToken->setOwner('user', $user->getIdentifier()); + $accessToken->setClient($client); - // Associate scopes with the session and access token + // Associate scopes with the access token foreach ($scopes as $scope) { - $session->associateScope($scope); + $accessToken->addScope($scope); } - foreach ($session->getScopes() as $scope) { - $accessToken->associateScope($scope); - } - - $this->server->getTokenType()->setSession($session); - $this->server->getTokenType()->setParam('access_token', $accessToken->getId()); - $this->server->getTokenType()->setParam('expires_in', $this->getAccessTokenTTL()); + $tokenType->setAccessToken($accessToken); // Associate a refresh token if set - if ($this->server->hasGrantType('refresh_token')) { - $refreshToken = new RefreshTokenEntity($this->server); - $refreshToken->setId(SecureKey::generate()); - $refreshToken->setExpireTime($this->server->getGrantType('refresh_token')->getRefreshTokenTTL() + time()); - $this->server->getTokenType()->setParam('refresh_token', $refreshToken->getId()); + if ($this->refreshTokenRepository instanceof RefreshTokenRepositoryInterface) { +// $refreshToken = new RefreshTokenEntity($this->server); +// $refreshToken->setId(SecureKey::generate()); +// $refreshToken->setExpireTime($this->server->getGrantType('refresh_token')->getRefreshTokenTTL() + time()); +// $refreshToken->setAccessToken($accessToken); +// $this->server->getTokenType()->setParam('refresh_token', $refreshToken->getId()); +// $tokenType->setParam('refresh_token', $refreshToken); } - // Save everything - $session->save(); - $accessToken->setSession($session); - $accessToken->save(); + // Save the access token + $this->accessTokenRepository->create($accessToken); - if ($this->server->hasGrantType('refresh_token')) { - $refreshToken->setAccessToken($accessToken); - $refreshToken->save(); - } + // Inject the access token into token type + $tokenType->setAccessToken($accessToken); - return $this->server->getTokenType()->generateResponse(); + return $tokenType; } } From eabcf82268a3e56b46288c7fee1ae2ff2b7a75d1 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:10:50 +0100 Subject: [PATCH 041/444] Added UserRepositoryInterface --- src/Repositories/UserRepositoryInterface.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/Repositories/UserRepositoryInterface.php diff --git a/src/Repositories/UserRepositoryInterface.php b/src/Repositories/UserRepositoryInterface.php new file mode 100644 index 00000000..818eb135 --- /dev/null +++ b/src/Repositories/UserRepositoryInterface.php @@ -0,0 +1,15 @@ + Date: Sun, 5 Apr 2015 21:11:10 +0100 Subject: [PATCH 042/444] Updated examples --- examples/composer.lock | 47 +++++++++++++++++++- examples/public/jwt.php | 40 +++++++++++++++++ examples/public/password.php | 34 ++++++++++++++ examples/src/Entities/UserEntity.php | 17 +++++++ examples/src/Repositories/UserRepository.php | 22 +++++++++ 5 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 examples/public/jwt.php create mode 100644 examples/public/password.php create mode 100644 examples/src/Entities/UserEntity.php create mode 100644 examples/src/Repositories/UserRepository.php diff --git a/examples/composer.lock b/examples/composer.lock index 8bc48e8e..8f5782c0 100644 --- a/examples/composer.lock +++ b/examples/composer.lock @@ -4,7 +4,7 @@ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "8d3e15426ebda5d273b960d5c9f373b5", + "hash": "9ae3d11ba275cce8764cfa3002ec7c93", "packages": [ { "name": "alexbilbie/proton", @@ -187,6 +187,51 @@ ], "time": "2014-12-20 21:24:13" }, + { + "name": "firebase/php-jwt", + "version": "2.0.0", + "target-dir": "Firebase/PHP-JWT", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "ffcfd888ce1e4f2d70cac2dc9b7301038332fe57" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/ffcfd888ce1e4f2d70cac2dc9b7301038332fe57", + "reference": "ffcfd888ce1e4f2d70cac2dc9b7301038332fe57", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "Authentication/", + "Exceptions/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "time": "2015-04-01 18:46:38" + }, { "name": "illuminate/container", "version": "v5.0.26", diff --git a/examples/public/jwt.php b/examples/public/jwt.php new file mode 100644 index 00000000..7dca6764 --- /dev/null +++ b/examples/public/jwt.php @@ -0,0 +1,40 @@ +addRepository(new ClientRepository()); +$server->addRepository(new ScopeRepository()); +$server->addRepository(new AccessTokenRepository()); +$server->addRepository(new UserRepository()); + +// Enable the password grant, respond with JWTs +$server->enableGrantType('PasswordGrant', new JsonWebTokenType()); + +// Setup JWT params +JsonWebTokenType::setIssuer('http://example.com/'); +JsonWebTokenType::setAudience('http://myawesomeapp.com/'); +JsonWebTokenType::setEncryptionKey('foobar123'); + +// Setup app + routing +$application = new \Proton\Application(); +$application->post('/access_token', function (Request $request) use ($server) { + try { + return $server->getAccessTokenResponse($request); + } catch (OAuthException $e) { + return $e->generateHttpResponse(); + } +}); + +// Run the app +$application->run(); diff --git a/examples/public/password.php b/examples/public/password.php new file mode 100644 index 00000000..fff4717b --- /dev/null +++ b/examples/public/password.php @@ -0,0 +1,34 @@ +addRepository(new ClientRepository()); +$server->addRepository(new ScopeRepository()); +$server->addRepository(new AccessTokenRepository()); +$server->addRepository(new UserRepository()); + +// Enable the password grant +$server->enableGrantType('PasswordGrant'); + +// Setup app + routing +$application = new \Proton\Application(); +$application->post('/access_token', function (Request $request) use ($server) { + try { + return $server->getAccessTokenResponse($request); + } catch (OAuthException $e) { + return $e->generateHttpResponse(); + } +}); + +// Run the app +$application->run(); diff --git a/examples/src/Entities/UserEntity.php b/examples/src/Entities/UserEntity.php new file mode 100644 index 00000000..8feb8c73 --- /dev/null +++ b/examples/src/Entities/UserEntity.php @@ -0,0 +1,17 @@ + Date: Sun, 5 Apr 2015 21:11:35 +0100 Subject: [PATCH 043/444] Added firebase/php-jwt to composer.json --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 42950d9a..6c0a44ff 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,8 @@ "php": ">=5.4.0", "symfony/http-foundation": "~2.4", "league/event": "~2.1", - "league/container": "~1.0" + "league/container": "~1.0", + "firebase/php-jwt": "~2.0" }, "require-dev": { "phpunit/phpunit": "4.3.*", From 110d5ce76fc4c4a83fb584c659017eadee4cce17 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:11:51 +0100 Subject: [PATCH 044/444] Respond with json content-type header --- src/Exception/OAuthException.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Exception/OAuthException.php b/src/Exception/OAuthException.php index fa8b465b..9183a9d2 100644 --- a/src/Exception/OAuthException.php +++ b/src/Exception/OAuthException.php @@ -80,7 +80,9 @@ class OAuthException extends \Exception */ public function getHttpHeaders() { - $headers = []; + $headers = [ + 'Content-type' => 'application/json' + ]; switch ($this->httpStatusCode) { case 401: $headers[] = 'HTTP/1.1 401 Unauthorized'; From b5bbf8332f346a02b2ee2ebc0d212de578761e50 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:12:05 +0100 Subject: [PATCH 045/444] Added JsonWebTokenType --- src/TokenTypes/JsonWebTokenType.php | 125 ++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 src/TokenTypes/JsonWebTokenType.php diff --git a/src/TokenTypes/JsonWebTokenType.php b/src/TokenTypes/JsonWebTokenType.php new file mode 100644 index 00000000..7ea5051a --- /dev/null +++ b/src/TokenTypes/JsonWebTokenType.php @@ -0,0 +1,125 @@ + $this->accessToken->getIdentifier(), + 'token_type' => 'Bearer', + 'expires_in' => $this->accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp() + ]; + + if (!is_null($this->getParam('refresh_token'))) { + $return['refresh_token'] = $this->getParam('refresh_token'); + } + + $return['id_token'] = $this->generateJWT(); + + return $return; + } + + /** + * Generate an JWT + * @return string + */ + public function generateJWT() + { + $now = new \DateTime(); + + $token = [ + 'iss' => self::$issuer, + 'aud' => self::$audience, + 'sub' => $this->accessToken->getOwnerIdentifier(), + 'exp' => $this->accessToken->getExpiryDateTime()->getTimestamp(), + 'nbf' => $now->getTimestamp(), + 'iat' => $now->getTimestamp(), + 'jti' => SecureKey::generate() + ]; + + return JWT::encode($token, self::$encryptionKey); + } + + /** + * @return \Symfony\Component\HttpFoundation\Response + */ + public function generateHttpResponse() + { + return new Response( + json_encode([ + $this->generateResponse() + ]), + 200, + [ + 'Content-type' => 'application/json', + 'Cache-Control' => 'no-store', + 'Pragma' => 'no-cache' + ] + ); + } + + /** + * Determine the access token in the authorization header + * + * @param \Symfony\Component\HttpFoundation\Request $request + * + * @return string + */ + public function determineAccessTokenInHeader(Request $request) + { + // TODO: Implement determineAccessTokenInHeader() method. + } +} From d3ed4548810e0b04b538cd101c7909ddbf9b2880 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:12:26 +0100 Subject: [PATCH 046/444] Added PasswordGrantProvider --- .../PasswordGrantProvider.php | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/ServiceProviders/PasswordGrantProvider.php diff --git a/src/ServiceProviders/PasswordGrantProvider.php b/src/ServiceProviders/PasswordGrantProvider.php new file mode 100644 index 00000000..540c73b3 --- /dev/null +++ b/src/ServiceProviders/PasswordGrantProvider.php @@ -0,0 +1,37 @@ +getContainer(); + + $container->add('PasswordGrant', function () use ($container) { + + $refreshTokenRepository = null; + if ($container->isRegistered('RefreshTokenRepository')) { + $refreshTokenRepository = $container->get('RefreshTokenRepository'); + } + + $grant = new PasswordGrant( + $container->get('emitter'), + $container->get('ClientRepository'), + $container->get('ScopeRepository'), + $container->get('AccessTokenRepository'), + $container->get('UserRepository'), + $refreshTokenRepository + ); + return $grant; + }); + } +} From 61ab07069207768403d6bcc4e7dbf7a4603244ed Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:12:55 +0100 Subject: [PATCH 047/444] Renamed ClientCredentialsGrantServerProvider to ClientCredentialsGrantProvider --- src/ServiceProviders/ClientCredentialsGrantProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ServiceProviders/ClientCredentialsGrantProvider.php b/src/ServiceProviders/ClientCredentialsGrantProvider.php index 97232f94..c56b0baf 100644 --- a/src/ServiceProviders/ClientCredentialsGrantProvider.php +++ b/src/ServiceProviders/ClientCredentialsGrantProvider.php @@ -5,7 +5,7 @@ namespace League\OAuth2\Server\ServiceProviders; use League\Container\ServiceProvider; use League\OAuth2\Server\Grant\ClientCredentialsGrant; -class ClientCredentialsGrantServerProvider extends ServiceProvider +class ClientCredentialsGrantProvider extends ServiceProvider { protected $provides = ['ClientCredentialsGrant']; From e88d80291809f1b17873936696702af7de7bee35 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:13:04 +0100 Subject: [PATCH 048/444] Added UserEntityInterface --- src/Entities/Interfaces/UserEntityInterface.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/Entities/Interfaces/UserEntityInterface.php diff --git a/src/Entities/Interfaces/UserEntityInterface.php b/src/Entities/Interfaces/UserEntityInterface.php new file mode 100644 index 00000000..27338737 --- /dev/null +++ b/src/Entities/Interfaces/UserEntityInterface.php @@ -0,0 +1,12 @@ + Date: Sun, 5 Apr 2015 21:13:15 +0100 Subject: [PATCH 049/444] Namespace updates --- src/Repositories/RefreshTokenRepositoryInterface.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Repositories/RefreshTokenRepositoryInterface.php b/src/Repositories/RefreshTokenRepositoryInterface.php index bf65468c..98c4631e 100644 --- a/src/Repositories/RefreshTokenRepositoryInterface.php +++ b/src/Repositories/RefreshTokenRepositoryInterface.php @@ -9,14 +9,12 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\Storage; - -use League\OAuth2\Server\Entity\RefreshTokenEntity; +namespace League\OAuth2\Server\Repositories; /** * Refresh token interface */ -interface RefreshTokenInterface extends StorageInterface +interface RefreshTokenRepositoryInterface extends RepositoryInterface { /** * Return a new instance of \League\OAuth2\Server\Entity\RefreshTokenEntity From bdd71743cde8695270448d2d58dfeacfc376c82e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:13:45 +0100 Subject: [PATCH 050/444] Added knowledge of UserRepository --- src/AbstractServer.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/AbstractServer.php b/src/AbstractServer.php index 68685fe0..6f694c69 100644 --- a/src/AbstractServer.php +++ b/src/AbstractServer.php @@ -20,6 +20,7 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\UserRepositoryInterface; use Symfony\Component\HttpFoundation\Request; /** @@ -93,6 +94,9 @@ abstract class AbstractServer implements ContainerAwareInterface, EmitterAwareIn case ($repository instanceof ScopeRepositoryInterface): $this->getContainer()->add('ScopeRepository', $repository); break; + case ($repository instanceof UserRepositoryInterface): + $this->getContainer()->add('UserRepository', $repository); + break; } } From 8fcf93c48941b58f78d4830d1f01bca251c9f650 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:13:53 +0100 Subject: [PATCH 051/444] Removed unused method --- src/AbstractServer.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/AbstractServer.php b/src/AbstractServer.php index 6f694c69..fe196167 100644 --- a/src/AbstractServer.php +++ b/src/AbstractServer.php @@ -99,18 +99,4 @@ abstract class AbstractServer implements ContainerAwareInterface, EmitterAwareIn break; } } - - /** - * Get a hydrated grant - * - * @param string $grant - * @param \DateInterval $tokenTTL - * - * @return \League\OAuth2\Server\Repositories\RepositoryInterface - * @deprecated - */ - public function getGrant($grant, \DateInterval $tokenTTL) - { - return $this->getContainer()->get($grant, [$this->responseType, $tokenTTL]); - } } From 1f1f0d8f15e2b0f4f9af6997afd97b89bf9456fd Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:14:06 +0100 Subject: [PATCH 052/444] Added PasswordGrantProvider to container --- src/AbstractServer.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AbstractServer.php b/src/AbstractServer.php index fe196167..eba3f2be 100644 --- a/src/AbstractServer.php +++ b/src/AbstractServer.php @@ -44,7 +44,8 @@ abstract class AbstractServer implements ContainerAwareInterface, EmitterAwareIn { $this->setContainer(new Container()); $this->getContainer()->singleton('emitter', $this->getEmitter()); - $this->getContainer()->addServiceProvider('League\OAuth2\Server\ServiceProviders\ClientCredentialsGrantServerProvider'); + $this->getContainer()->addServiceProvider('League\OAuth2\Server\ServiceProviders\ClientCredentialsGrantProvider'); + $this->getContainer()->addServiceProvider('League\OAuth2\Server\ServiceProviders\PasswordGrantProvider'); } /** From be14b3a2df524fb883fc9bc3a9f0d6ef87b801f7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:14:22 +0100 Subject: [PATCH 053/444] Updated namespace --- src/Server.php | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Server.php b/src/Server.php index a560c72b..f119109a 100644 --- a/src/Server.php +++ b/src/Server.php @@ -2,8 +2,8 @@ namespace League\OAuth2\Server; use DateInterval; -use League\OAuth2\Server\ResponseTypes\BearerTokenResponseType; -use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; +use League\OAuth2\Server\TokenTypes\BearerTokenType; +use League\OAuth2\Server\TokenTypes\TokenTypeInterface; use Symfony\Component\HttpFoundation\Request; class Server extends AbstractServer @@ -14,9 +14,9 @@ class Server extends AbstractServer protected $enabledGrantTypes = []; /** - * @var \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface[] + * @var TokenTypeInterface[] */ - protected $grantTypeResponseTypes = []; + protected $grantTypeTokenTypes = []; /** * @var DateInterval[] @@ -24,7 +24,7 @@ class Server extends AbstractServer protected $grantTypeAccessTokenTTL = []; /** - * @var \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface + * @var TokenTypeInterface */ protected $defaultResponseType; @@ -41,16 +41,16 @@ class Server extends AbstractServer /** * New server instance * - * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $defaultResponseType - * @param DateInterval $defaultAccessTokenTTL + * @param TokenTypeInterface $defaultResponseType + * @param DateInterval $defaultAccessTokenTTL */ public function __construct( - ResponseTypeInterface $defaultResponseType = null, + TokenTypeInterface $defaultResponseType = null, DateInterval $defaultAccessTokenTTL = null ) { - $this->defaultResponseType = ($defaultResponseType instanceof ResponseTypeInterface) + $this->defaultResponseType = ($defaultResponseType instanceof TokenTypeInterface) ? $defaultResponseType - : new BearerTokenResponseType(); + : new BearerTokenType(); $this->defaultAccessTokenTTL = ($defaultAccessTokenTTL instanceof DateInterval) ? $defaultAccessTokenTTL @@ -60,15 +60,15 @@ class Server extends AbstractServer } /** - * @param string $grantType - * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType - * @param DateInterval $accessTokenTTL + * @param string $grantType + * @param TokenTypeInterface $tokenType + * @param DateInterval $accessTokenTTL * * @throws \Exception */ public function enableGrantType( $grantType, - ResponseTypeInterface $responseType = null, + TokenTypeInterface $tokenType = null, DateInterval $accessTokenTTL = null ) { if ($this->getContainer()->isInServiceProvider($grantType)) { @@ -80,10 +80,10 @@ class Server extends AbstractServer } // Set grant response type - if ($responseType instanceof ResponseTypeInterface) { - $this->grantTypeResponseTypes[$grantIdentifier] = $responseType; + if ($tokenType instanceof TokenTypeInterface) { + $this->grantTypeTokenTypes[$grantIdentifier] = $tokenType; } else { - $this->grantTypeResponseTypes[$grantIdentifier] = $this->defaultResponseType; + $this->grantTypeTokenTypes[$grantIdentifier] = $this->defaultResponseType; } // Set grant access token TTL @@ -99,7 +99,7 @@ class Server extends AbstractServer * * @param \Symfony\Component\HttpFoundation\Request $request * - * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface + * @return TokenTypeInterface * @throws \Exception */ public function getAccessTokenResponse(Request $request = null) @@ -112,17 +112,17 @@ class Server extends AbstractServer $grantType = $request->request->get('grant_type', null); if ($grantType === null || !isset($this->enabledGrantTypes[$grantType])) { - throw new \Exception('Unknown grant type'); + throw new Exception\InvalidGrantException($grantType); } - $responseType = $this->enabledGrantTypes[$grantType]->getAccessTokenAsType( + $tokenType = $this->enabledGrantTypes[$grantType]->getAccessTokenAsType( $request, - $this->grantTypeResponseTypes[$grantType], + $this->grantTypeTokenTypes[$grantType], $this->grantTypeAccessTokenTTL[$grantType], $this->scopeDelimiter ); - return $responseType->generateHttpResponse(); + return $tokenType->generateHttpResponse(); } /** From d468cbf600454cd53381f7417bf18dc0e8885838 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:56:42 +0100 Subject: [PATCH 054/444] Updated AuthCodeRepositoryInterface --- src/AbstractServer.php | 4 +++ .../AuthCodeRepositoryInterface.php | 34 ++++--------------- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/src/AbstractServer.php b/src/AbstractServer.php index eba3f2be..28b3d23a 100644 --- a/src/AbstractServer.php +++ b/src/AbstractServer.php @@ -16,6 +16,7 @@ use League\Container\ContainerAwareInterface; use League\Container\ContainerAwareTrait; use League\Event\EmitterAwareInterface; use League\Event\EmitterTrait; +use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; @@ -98,6 +99,9 @@ abstract class AbstractServer implements ContainerAwareInterface, EmitterAwareIn case ($repository instanceof UserRepositoryInterface): $this->getContainer()->add('UserRepository', $repository); break; + case ($repository instanceof AuthCodeRepositoryInterface): + $this->getContainer()->add('AuthCodeRepository', $repository); + break; } } } diff --git a/src/Repositories/AuthCodeRepositoryInterface.php b/src/Repositories/AuthCodeRepositoryInterface.php index 1fe0f8b9..734f5305 100644 --- a/src/Repositories/AuthCodeRepositoryInterface.php +++ b/src/Repositories/AuthCodeRepositoryInterface.php @@ -9,22 +9,21 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\Storage; +namespace League\OAuth2\Server\Repositories; -use League\OAuth2\Server\Entity\AuthCodeEntity; -use League\OAuth2\Server\Entity\ScopeEntity; +use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; /** * Auth code storage interface */ -interface AuthCodeInterface extends StorageInterface +interface AuthCodeRepositoryInterface extends RepositoryInterface { /** * Get the auth code * * @param string $code * - * @return \League\OAuth2\Server\Entity\AuthCodeEntity + * @return \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface */ public function get($code); @@ -40,31 +39,10 @@ interface AuthCodeInterface extends StorageInterface */ public function create($token, $expireTime, $sessionId, $redirectUri); - /** - * Get the scopes for an access token - * - * @param \League\OAuth2\Server\Entity\AuthCodeEntity $token The auth code - * - * @return array Array of \League\OAuth2\Server\Entity\ScopeEntity - */ - public function getScopes(AuthCodeEntity $token); - - /** - * Associate a scope with an acess token - * - * @param \League\OAuth2\Server\Entity\AuthCodeEntity $token The auth code - * @param \League\OAuth2\Server\Entity\ScopeEntity $scope The scope - * - * @return void - */ - public function associateScope(AuthCodeEntity $token, ScopeEntity $scope); - /** * Delete an access token * - * @param \League\OAuth2\Server\Entity\AuthCodeEntity $token The access token to delete - * - * @return void + * @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $token The access token to delete */ - public function delete(AuthCodeEntity $token); + public function delete(AuthCodeEntityInterface $token); } From a0d5d5817bc7342b98bb2d7c702b4d3454400813 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:57:04 +0100 Subject: [PATCH 055/444] Updated AuthCodeEntity --- src/Entities/AuthCodeEntity.php | 22 +++++++++++++++++-- .../Interfaces/AuthCodeEntityInterface.php | 11 +++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/Entities/AuthCodeEntity.php b/src/Entities/AuthCodeEntity.php index 3d2354af..7e49317f 100644 --- a/src/Entities/AuthCodeEntity.php +++ b/src/Entities/AuthCodeEntity.php @@ -1,7 +1,7 @@ redirectUri; + } + + /** + * @param string $uri + */ + public function setRedirectUri($uri) + { + $this->redirectUri = $uri; + } } diff --git a/src/Entities/Interfaces/AuthCodeEntityInterface.php b/src/Entities/Interfaces/AuthCodeEntityInterface.php index 2029c305..c78f82c7 100644 --- a/src/Entities/Interfaces/AuthCodeEntityInterface.php +++ b/src/Entities/Interfaces/AuthCodeEntityInterface.php @@ -1,7 +1,16 @@ Date: Sun, 5 Apr 2015 21:57:17 +0100 Subject: [PATCH 056/444] Added isExpired method --- src/Entities/Interfaces/TokenInterface.php | 6 ++++++ src/Entities/Traits/TokenEntityTrait.php | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/src/Entities/Interfaces/TokenInterface.php b/src/Entities/Interfaces/TokenInterface.php index 22f37d05..89e223ac 100644 --- a/src/Entities/Interfaces/TokenInterface.php +++ b/src/Entities/Interfaces/TokenInterface.php @@ -76,4 +76,10 @@ interface TokenInterface * @return ScopeEntityInterface[] */ public function getScopes(); + + /** + * Has the token expired? + * @return bool + */ + public function isExpired(); } diff --git a/src/Entities/Traits/TokenEntityTrait.php b/src/Entities/Traits/TokenEntityTrait.php index bcd756bf..92503973 100644 --- a/src/Entities/Traits/TokenEntityTrait.php +++ b/src/Entities/Traits/TokenEntityTrait.php @@ -123,4 +123,13 @@ trait TokenEntityTrait { $this->client = $client; } + + /** + * Has the token expired? + * @return bool + */ + public function isExpired() + { + return (new \DateTime()) > $this->getExpiryDateTime(); + } } \ No newline at end of file From a15995c1266e40e2715445a532de39bdec79adda Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 5 Apr 2015 21:57:29 +0100 Subject: [PATCH 057/444] First commit of updated auth code grant --- src/Grant/AuthCodeGrant.php | 181 +++++++++++++++++++++--------------- 1 file changed, 105 insertions(+), 76 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 46ceb062..d6411237 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -11,20 +11,54 @@ namespace League\OAuth2\Server\Grant; -use League\OAuth2\Server\Entity\AccessTokenEntity; -use League\OAuth2\Server\Entity\AuthCodeEntity; -use League\OAuth2\Server\Entity\ClientEntity; -use League\OAuth2\Server\Entity\RefreshTokenEntity; -use League\OAuth2\Server\Entity\SessionEntity; -use League\OAuth2\Server\Event; -use League\OAuth2\Server\Exception; -use League\OAuth2\Server\Util\SecureKey; +use League\Event\Emitter; +use League\Event\Event; +use League\OAuth2\Server\Entities\AccessTokenEntity; +use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; +use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Exception\InvalidClientException; +use League\OAuth2\Server\Exception\InvalidRequestException; +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\TokenTypes\TokenTypeInterface; +use League\OAuth2\Server\Utils\SecureKey; +use Symfony\Component\HttpFoundation\Request; +use DateInterval; /** * Auth code grant class */ class AuthCodeGrant extends AbstractGrant { + /** + * @var \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface + */ + protected $authCodeRepository; + + /** + * @param \League\Event\Emitter $emitter + * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository + * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository + * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository + * @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository + * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository + */ + public function __construct( + Emitter $emitter, + ClientRepositoryInterface $clientRepository, + ScopeRepositoryInterface $scopeRepository, + AccessTokenRepositoryInterface $accessTokenRepository, + AuthCodeRepositoryInterface $authCodeRepository, + RefreshTokenRepositoryInterface $refreshTokenRepository = null + ) { + $this->authCodeRepository = $authCodeRepository; + $this->refreshTokenRepository = $refreshTokenRepository; + parent::__construct($emitter, $clientRepository, $scopeRepository, $accessTokenRepository); + } + /** * Grant identifier * @@ -79,17 +113,17 @@ class AuthCodeGrant extends AbstractGrant * * @throws */ - public function checkAuthorizeParams() + /*public function checkAuthorizeParams() { // Get required params - $clientId = $this->server->getRequest()->query->get('client_id', null); + $clientId = $request->query->get('client_id', null); if (is_null($clientId)) { - throw new Exception\InvalidRequestException('client_id'); + throw new InvalidRequestException('client_id'); } - $redirectUri = $this->server->getRequest()->query->get('redirect_uri', null); + $redirectUri = $request->query->get('redirect_uri', null); if (is_null($redirectUri)) { - throw new Exception\InvalidRequestException('redirect_uri'); + throw new InvalidRequestException('redirect_uri'); } // Validate client ID and redirect URI @@ -101,18 +135,18 @@ class AuthCodeGrant extends AbstractGrant ); if (($client instanceof ClientEntity) === false) { - $this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($this->server->getRequest())); + $this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($request)); throw new Exception\InvalidClientException(); } - $state = $this->server->getRequest()->query->get('state', null); + $state = $request->query->get('state', null); if ($this->server->stateParamRequired() === true && is_null($state)) { - throw new Exception\InvalidRequestException('state', $redirectUri); + throw new InvalidRequestException('state', $redirectUri); } - $responseType = $this->server->getRequest()->query->get('response_type', null); + $responseType = $request->query->get('response_type', null); if (is_null($responseType)) { - throw new Exception\InvalidRequestException('response_type', $redirectUri); + throw new InvalidRequestException('response_type', $redirectUri); } // Ensure response type is one that is recognised @@ -121,7 +155,7 @@ class AuthCodeGrant extends AbstractGrant } // Validate any scopes that are in the request - $scopeParam = $this->server->getRequest()->query->get('scope', ''); + $scopeParam = $request->query->get('scope', ''); $scopes = $this->validateScopes($scopeParam, $client, $redirectUri); return [ @@ -131,7 +165,7 @@ class AuthCodeGrant extends AbstractGrant 'response_type' => $responseType, 'scopes' => $scopes ]; - } + }*/ /** * Parse a new authorize request @@ -142,7 +176,7 @@ class AuthCodeGrant extends AbstractGrant * * @return string An authorisation code */ - public function newAuthorizeRequest($type, $typeId, $authParams = []) + /*public function newAuthorizeRequest($type, $typeId, $authParams = []) { // Create a new session $session = new SessionEntity($this->server); @@ -164,110 +198,105 @@ class AuthCodeGrant extends AbstractGrant $authCode->save(); return $authCode->generateRedirectUri($authParams['state']); - } + }*/ /** - * Complete the auth code grant + * Return an access token * - * @return array + * @param \Symfony\Component\HttpFoundation\Request $request + * @param \League\OAuth2\Server\TokenTypes\TokenTypeInterface $tokenType + * @param \DateInterval $accessTokenTTL + * @param string $scopeDelimiter * - * @throws + * @return \League\OAuth2\Server\TokenTypes\TokenTypeInterface + * @throws \League\OAuth2\Server\Exception\InvalidClientException + * @throws \League\OAuth2\Server\Exception\InvalidGrantException + * @throws \League\OAuth2\Server\Exception\InvalidRequestException */ - public function completeFlow() - { + public function getAccessTokenAsType( + Request $request, + TokenTypeInterface $tokenType, + DateInterval $accessTokenTTL, + $scopeDelimiter = ' ' + ) { // Get the required params - $clientId = $this->server->getRequest()->request->get('client_id', $this->server->getRequest()->getUser()); + $clientId = $request->request->get('client_id', $request->getUser()); if (is_null($clientId)) { - throw new Exception\InvalidRequestException('client_id'); + throw new InvalidRequestException('client_id'); } - $clientSecret = $this->server->getRequest()->request->get('client_secret', - $this->server->getRequest()->getPassword()); + $clientSecret = $request->request->get('client_secret', + $request->getPassword()); if (is_null($clientSecret)) { - throw new Exception\InvalidRequestException('client_secret'); + throw new InvalidRequestException('client_secret'); } - $redirectUri = $this->server->getRequest()->request->get('redirect_uri', null); + $redirectUri = $request->request->get('redirect_uri', null); if (is_null($redirectUri)) { - throw new Exception\InvalidRequestException('redirect_uri'); + throw new InvalidRequestException('redirect_uri'); } // Validate client ID and client secret - $client = $this->server->getClientStorage()->get( + $client = $this->clientRepository->get( $clientId, $clientSecret, $redirectUri, $this->getIdentifier() ); - if (($client instanceof ClientEntity) === false) { - $this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($this->server->getRequest())); - throw new Exception\InvalidClientException(); + if (($client instanceof ClientEntityInterface) === false) { + $this->emitter->emit(new Event('client.authentication.failed', $request)); + throw new InvalidClientException(); } // Validate the auth code - $authCode = $this->server->getRequest()->request->get('code', null); + $authCode = $request->request->get('code', null); if (is_null($authCode)) { - throw new Exception\InvalidRequestException('code'); + throw new InvalidRequestException('code'); } - $code = $this->server->getAuthCodeStorage()->get($authCode); - if (($code instanceof AuthCodeEntity) === false) { - throw new Exception\InvalidRequestException('code'); + $code = $this->authCodeRepository->get($authCode); + if (($code instanceof AuthCodeEntityInterface) === false) { + throw new InvalidRequestException('code'); } // Ensure the auth code hasn't expired if ($code->isExpired() === true) { - throw new Exception\InvalidRequestException('code'); + throw new InvalidRequestException('code'); } // Check redirect URI presented matches redirect URI originally used in authorize request if ($code->getRedirectUri() !== $redirectUri) { - throw new Exception\InvalidRequestException('redirect_uri'); + throw new InvalidRequestException('redirect_uri'); } - $session = $code->getSession(); - $session->associateClient($client); - - $authCodeScopes = $code->getScopes(); - // Generate the access token $accessToken = new AccessTokenEntity($this->server); - $accessToken->setId(SecureKey::generate()); - $accessToken->setExpireTime($this->getAccessTokenTTL() + time()); + $accessToken->setIdentifier(SecureKey::generate()); + $accessToken->setExpiryDateTime((new \DateTime)->add($accessTokenTTL)); + $accessToken->setClient($client); - foreach ($authCodeScopes as $authCodeScope) { - $session->associateScope($authCodeScope); + foreach ($code->getScopes() as $scope) { + $accessToken->addScope($scope); } - foreach ($session->getScopes() as $scope) { - $accessToken->associateScope($scope); - } - - $this->server->getTokenType()->setSession($session); - $this->server->getTokenType()->setParam('access_token', $accessToken->getId()); - $this->server->getTokenType()->setParam('expires_in', $this->getAccessTokenTTL()); + $tokenType->setAccessToken($accessToken); // Associate a refresh token if set - if ($this->server->hasGrantType('refresh_token')) { - $refreshToken = new RefreshTokenEntity($this->server); - $refreshToken->setId(SecureKey::generate()); - $refreshToken->setExpireTime($this->server->getGrantType('refresh_token')->getRefreshTokenTTL() + time()); - $this->server->getTokenType()->setParam('refresh_token', $refreshToken->getId()); + if ($this->refreshTokenRepository instanceof RefreshTokenRepositoryInterface) { +// $refreshToken = new RefreshTokenEntity($this->server); +// $refreshToken->setId(SecureKey::generate()); +// $refreshToken->setExpireTime($this->server->getGrantType('refresh_token')->getRefreshTokenTTL() + time()); +// $tokenType->setParam('refresh_token', $refreshToken->getId()); +// $refreshToken->setAccessToken($accessToken); } // Expire the auth code - $code->expire(); + $this->authCodeRepository->delete($code); - // Save all the things - $accessToken->setSession($session); - $accessToken->save(); + // Save the access token + $this->accessTokenRepository->create($accessToken); - if (isset($refreshToken) && $this->server->hasGrantType('refresh_token')) { - $refreshToken->setAccessToken($accessToken); - $refreshToken->save(); - } - - return $this->server->getTokenType()->generateResponse(); + return $tokenType; } } From 385b03db6f0952f99a7b112be988ca8cc4d212ce Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 6 Apr 2015 08:08:18 +0100 Subject: [PATCH 058/444] Import DateTime instead of using root namespace --- src/Entities/Traits/TokenEntityTrait.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Entities/Traits/TokenEntityTrait.php b/src/Entities/Traits/TokenEntityTrait.php index 92503973..e55cc2eb 100644 --- a/src/Entities/Traits/TokenEntityTrait.php +++ b/src/Entities/Traits/TokenEntityTrait.php @@ -1,6 +1,7 @@ expiryDateTime = $dateTime; } @@ -130,6 +131,6 @@ trait TokenEntityTrait */ public function isExpired() { - return (new \DateTime()) > $this->getExpiryDateTime(); + return (new DateTime()) > $this->getExpiryDateTime(); } } \ No newline at end of file From 90d18c553d2747f2c8a2bf275c76848817485837 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 6 Apr 2015 08:13:41 +0100 Subject: [PATCH 059/444] Broke expiration DateTime out into seperate variable for readability --- src/Grant/AuthCodeGrant.php | 3 ++- src/Grant/ClientCredentialsGrant.php | 3 ++- src/Grant/PasswordGrant.php | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index d6411237..acd2f381 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -273,7 +273,8 @@ class AuthCodeGrant extends AbstractGrant // Generate the access token $accessToken = new AccessTokenEntity($this->server); $accessToken->setIdentifier(SecureKey::generate()); - $accessToken->setExpiryDateTime((new \DateTime)->add($accessTokenTTL)); + $expirationDateTime = (new \DateTime())->add($accessTokenTTL); + $accessToken->setExpiryDateTime($expirationDateTime); $accessToken->setClient($client); foreach ($code->getScopes() as $scope) { diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 39cab779..50be9a1f 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -82,7 +82,8 @@ class ClientCredentialsGrant extends AbstractGrant // Generate an access token $accessToken = new AccessTokenEntity(); $accessToken->setIdentifier(SecureKey::generate()); - $accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL)); + $expirationDateTime = (new \DateTime())->add($accessTokenTTL); + $accessToken->setExpiryDateTime($expirationDateTime); $accessToken->setClient($client); $accessToken->setOwner('client', $client->getIdentifier()); diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index c29c867c..e50f4708 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -147,7 +147,8 @@ class PasswordGrant extends AbstractGrant // Generate an access token $accessToken = new AccessTokenEntity(); $accessToken->setIdentifier(SecureKey::generate()); - $accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL)); + $expirationDateTime = (new \DateTime())->add($accessTokenTTL); + $accessToken->setExpiryDateTime($expirationDateTime); $accessToken->setOwner('user', $user->getIdentifier()); $accessToken->setClient($client); From 39df4ff9b1e74c61f3481a115342fc69ddda70c0 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 6 Apr 2015 08:21:25 +0100 Subject: [PATCH 060/444] Clarified docblock --- src/Repositories/ClientRepositoryInterface.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Repositories/ClientRepositoryInterface.php b/src/Repositories/ClientRepositoryInterface.php index 09360909..b1f16ad4 100644 --- a/src/Repositories/ClientRepositoryInterface.php +++ b/src/Repositories/ClientRepositoryInterface.php @@ -19,10 +19,10 @@ interface ClientRepositoryInterface extends RepositoryInterface /** * Get a client * - * @param string $clientIdentifier The client's identifier - * @param string $clientSecret The client's secret (default = "null") - * @param string $redirectUri The client's redirect URI (default = "null") - * @param string $grantType The grant type used (default = "null") + * @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|null $grantType The grant type used * * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface */ From 9985f3eee2d21c8ef4531d855e35a8ddb979f6f7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 6 Apr 2015 08:23:18 +0100 Subject: [PATCH 061/444] Fixed docblock --- src/Server.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Server.php b/src/Server.php index f119109a..29560ba1 100644 --- a/src/Server.php +++ b/src/Server.php @@ -26,7 +26,7 @@ class Server extends AbstractServer /** * @var TokenTypeInterface */ - protected $defaultResponseType; + protected $defaultTokenType; /** * @var DateInterval @@ -41,15 +41,15 @@ class Server extends AbstractServer /** * New server instance * - * @param TokenTypeInterface $defaultResponseType - * @param DateInterval $defaultAccessTokenTTL + * @param TokenTypeInterface $defaultTokenType + * @param DateInterval $defaultAccessTokenTTL */ public function __construct( - TokenTypeInterface $defaultResponseType = null, + TokenTypeInterface $defaultTokenType = null, DateInterval $defaultAccessTokenTTL = null ) { - $this->defaultResponseType = ($defaultResponseType instanceof TokenTypeInterface) - ? $defaultResponseType + $this->defaultResponseType = ($defaultTokenType instanceof TokenTypeInterface) + ? $defaultTokenType : new BearerTokenType(); $this->defaultAccessTokenTTL = ($defaultAccessTokenTTL instanceof DateInterval) @@ -60,9 +60,9 @@ class Server extends AbstractServer } /** - * @param string $grantType + * @param string $grantType * @param TokenTypeInterface $tokenType - * @param DateInterval $accessTokenTTL + * @param DateInterval $accessTokenTTL * * @throws \Exception */ From 95a2308ff6d9b06e3e2d1fa12dc6958208ff5a08 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 6 Apr 2015 08:23:24 +0100 Subject: [PATCH 062/444] Added @todo --- src/Server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Server.php b/src/Server.php index 29560ba1..6b788ee7 100644 --- a/src/Server.php +++ b/src/Server.php @@ -76,7 +76,7 @@ class Server extends AbstractServer $grantIdentifier = $grant->getIdentifier(); $this->enabledGrantTypes[$grantIdentifier] = $grant; } else { - throw new \Exception('Unregistered grant type'); + throw new \Exception('Unregistered grant type'); // @TODO fix } // Set grant response type From 8e9b12fefd437f73cdf14fcfccb0dcd5f8a8302e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 6 Apr 2015 08:23:35 +0100 Subject: [PATCH 063/444] Code readability --- src/Server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Server.php b/src/Server.php index 6b788ee7..5a7bfaa6 100644 --- a/src/Server.php +++ b/src/Server.php @@ -111,7 +111,7 @@ class Server extends AbstractServer // Run the requested grant type $grantType = $request->request->get('grant_type', null); - if ($grantType === null || !isset($this->enabledGrantTypes[$grantType])) { + if ($grantType === null || isset($this->enabledGrantTypes[$grantType]) === false) { throw new Exception\InvalidGrantException($grantType); } From 2e3c6b4f3aa5b569b7396e36eb52360977250a4e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 6 Apr 2015 08:32:44 +0100 Subject: [PATCH 064/444] Refactored constructor to set defaults, added new setter methods for default token TTL and default token type --- src/Server.php | 60 +++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/src/Server.php b/src/Server.php index 5a7bfaa6..1199bb27 100644 --- a/src/Server.php +++ b/src/Server.php @@ -1,4 +1,5 @@ defaultResponseType = ($defaultTokenType instanceof TokenTypeInterface) - ? $defaultTokenType - : new BearerTokenType(); - - $this->defaultAccessTokenTTL = ($defaultAccessTokenTTL instanceof DateInterval) - ? $defaultAccessTokenTTL - : new DateInterval('PT01H'); // default of 1 hour + public function __construct() { + $this->defaultTokenType = new BearerTokenType(); + $this->defaultAccessTokenTTL = new DateInterval('PT01H'); // default of 1 hour parent::__construct(); } + /** + * Set the default token type that grants will return + * + * @param TokenTypeInterface $defaultTokenType + */ + public function setDefaultTokenType(TokenTypeInterface $defaultTokenType) + { + $this->defaultTokenType = $defaultTokenType; + } + + /** + * Set the delimiter used to separate scopes in a request + * + * @param string $scopeDelimiter + */ + public function setScopeDelimiter($scopeDelimiter) + { + $this->scopeDelimiter = $scopeDelimiter; + } + + /** + * Set the default TTL of access tokens + * + * @param DateInterval $defaultAccessTokenTTL + */ + public function setDefaultAccessTokenTTL(DateInterval $defaultAccessTokenTTL) + { + $this->defaultAccessTokenTTL = $defaultAccessTokenTTL; + } + /** * @param string $grantType * @param TokenTypeInterface $tokenType @@ -83,7 +103,7 @@ class Server extends AbstractServer if ($tokenType instanceof TokenTypeInterface) { $this->grantTypeTokenTypes[$grantIdentifier] = $tokenType; } else { - $this->grantTypeTokenTypes[$grantIdentifier] = $this->defaultResponseType; + $this->grantTypeTokenTypes[$grantIdentifier] = $this->defaultTokenType; } // Set grant access token TTL @@ -124,14 +144,4 @@ class Server extends AbstractServer return $tokenType->generateHttpResponse(); } - - /** - * Set the delimiter used to separate scopes in a request - * - * @param string $scopeDelimiter - */ - public function setScopeDelimiter($scopeDelimiter) - { - $this->scopeDelimiter = $scopeDelimiter; - } } From 18b104d0ac04d4311c6bd1c7e812aa9d72e03496 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 6 Apr 2015 08:34:50 +0100 Subject: [PATCH 065/444] Run `codecept build` to generate test files --- .travis.yml | 2 +- tests/api/ApiTester.php | 2389 --------------------------------------- 2 files changed, 1 insertion(+), 2390 deletions(-) delete mode 100644 tests/api/ApiTester.php diff --git a/.travis.yml b/.travis.yml index 9bce3e7a..34e237af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ before_script: - cd ../.. script: - - vendor/bin/codecept run + - vendor/bin/codecept build && vendor/bin/codecept run after_script: - wget https://scrutinizer-ci.com/ocular.phar diff --git a/tests/api/ApiTester.php b/tests/api/ApiTester.php deleted file mode 100644 index 8b6a0307..00000000 --- a/tests/api/ApiTester.php +++ /dev/null @@ -1,2389 +0,0 @@ -scenario->runStep(new \Codeception\Step\Action('setHeader', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Adds HTTP authentication via username/password. - * - * @param $username - * @param $password - * @see \Codeception\Module\REST::amHttpAuthenticated() - */ - public function amHttpAuthenticated($username, $password) { - return $this->scenario->runStep(new \Codeception\Step\Condition('amHttpAuthenticated', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Opens the page for the given relative URI. - * - * ``` php - * amOnPage('/'); - * // opens /register page - * $I->amOnPage('/register'); - * ?> - * ``` - * - * @param $page - * @see \Codeception\Module\PhpBrowser::amOnPage() - */ - public function amOnPage($page) { - return $this->scenario->runStep(new \Codeception\Step\Condition('amOnPage', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Open web page at the given absolute URL and sets its hostname as the base host. - * - * ``` php - * amOnUrl('http://codeception.com'); - * $I->amOnPage('/quickstart'); // moves to http://codeception.com/quickstart - * ?> - * ``` - * @see \Codeception\Module\PhpBrowser::amOnUrl() - */ - public function amOnUrl($url) { - return $this->scenario->runStep(new \Codeception\Step\Condition('amOnUrl', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Changes the subdomain for the 'url' configuration parameter. - * Does not open a page; use `amOnPage` for that. - * - * ``` php - * amOnSubdomain('user'); - * $I->amOnPage('/'); - * // moves to http://user.mysite.com/ - * ?> - * ``` - * - * @param $subdomain - * - * @return mixed - * @see \Codeception\Module\PhpBrowser::amOnSubdomain() - */ - public function amOnSubdomain($subdomain) { - return $this->scenario->runStep(new \Codeception\Step\Condition('amOnSubdomain', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Low-level API method. - * If Codeception commands are not enough, use [Guzzle HTTP Client](http://guzzlephp.org/) methods directly - * - * Example: - * - * ``` php - * executeInGuzzle(function (\GuzzleHttp\Client $client) { - * $client->get('/get', ['query' => ['foo' => 'bar']]); - * }); - * ?> - * ``` - * - * It is not recommended to use this command on a regular basis. - * If Codeception lacks important Guzzle Client methods, implement them and submit patches. - * - * @param callable $function - * @see \Codeception\Module\PhpBrowser::executeInGuzzle() - */ - public function executeInGuzzle($function) { - return $this->scenario->runStep(new \Codeception\Step\Action('executeInGuzzle', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Perform a click on a link or a button, given by a locator. - * If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string. - * For buttons, the "value" attribute, "name" attribute, and inner text are searched. - * For links, the link text is searched. - * For images, the "alt" attribute and inner text of any parent links are searched. - * - * The second parameter is a context (CSS or XPath locator) to narrow the search. - * - * Note that if the locator matches a button of type `submit`, the form will be submitted. - * - * ``` php - * click('Logout'); - * // button of form - * $I->click('Submit'); - * // CSS button - * $I->click('#form input[type=submit]'); - * // XPath - * $I->click('//form/*[@type=submit]'); - * // link in context - * $I->click('Logout', '#nav'); - * // using strict locator - * $I->click(['link' => 'Login']); - * ?> - * ``` - * - * @param $link - * @param $context - * @see \Codeception\Lib\InnerBrowser::click() - */ - public function click($link, $context = null) { - return $this->scenario->runStep(new \Codeception\Step\Action('click', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current page contains the given string. - * Specify a locator as the second parameter to match a specific region. - * - * ``` php - * see('Logout'); // I can suppose user is logged in - * $I->see('Sign Up','h1'); // I can suppose it's a signup page - * $I->see('Sign Up','//body/h1'); // with XPath - * ?> - * ``` - * - * @param $text - * @param null $selector - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::see() - */ - public function canSee($text, $selector = null) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('see', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current page contains the given string. - * Specify a locator as the second parameter to match a specific region. - * - * ``` php - * see('Logout'); // I can suppose user is logged in - * $I->see('Sign Up','h1'); // I can suppose it's a signup page - * $I->see('Sign Up','//body/h1'); // with XPath - * ?> - * ``` - * - * @param $text - * @param null $selector - * @see \Codeception\Lib\InnerBrowser::see() - */ - public function see($text, $selector = null) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('see', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current page doesn't contain the text specified. - * Give a locator as the second parameter to match a specific region. - * - * ```php - * dontSee('Login'); // I can suppose user is already logged in - * $I->dontSee('Sign Up','h1'); // I can suppose it's not a signup page - * $I->dontSee('Sign Up','//body/h1'); // with XPath - * ?> - * ``` - * - * @param $text - * @param null $selector - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSee() - */ - public function cantSee($text, $selector = null) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSee', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current page doesn't contain the text specified. - * Give a locator as the second parameter to match a specific region. - * - * ```php - * dontSee('Login'); // I can suppose user is already logged in - * $I->dontSee('Sign Up','h1'); // I can suppose it's not a signup page - * $I->dontSee('Sign Up','//body/h1'); // with XPath - * ?> - * ``` - * - * @param $text - * @param null $selector - * @see \Codeception\Lib\InnerBrowser::dontSee() - */ - public function dontSee($text, $selector = null) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSee', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there's a link with the specified text. - * Give a full URL as the second parameter to match links with that exact URL. - * - * ``` php - * seeLink('Logout'); // matches Logout - * $I->seeLink('Logout','/logout'); // matches Logout - * ?> - * ``` - * - * @param $text - * @param null $url - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeLink() - */ - public function canSeeLink($text, $url = null) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeLink', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there's a link with the specified text. - * Give a full URL as the second parameter to match links with that exact URL. - * - * ``` php - * seeLink('Logout'); // matches Logout - * $I->seeLink('Logout','/logout'); // matches Logout - * ?> - * ``` - * - * @param $text - * @param null $url - * @see \Codeception\Lib\InnerBrowser::seeLink() - */ - public function seeLink($text, $url = null) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeLink', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page doesn't contain a link with the given string. - * If the second parameter is given, only links with a matching "href" attribute will be checked. - * - * ``` php - * dontSeeLink('Logout'); // I suppose user is not logged in - * $I->dontSeeLink('Checkout now', '/store/cart.php'); - * ?> - * ``` - * - * @param $text - * @param null $url - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeLink() - */ - public function cantSeeLink($text, $url = null) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeLink', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page doesn't contain a link with the given string. - * If the second parameter is given, only links with a matching "href" attribute will be checked. - * - * ``` php - * dontSeeLink('Logout'); // I suppose user is not logged in - * $I->dontSeeLink('Checkout now', '/store/cart.php'); - * ?> - * ``` - * - * @param $text - * @param null $url - * @see \Codeception\Lib\InnerBrowser::dontSeeLink() - */ - public function dontSeeLink($text, $url = null) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeLink', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current URI contains the given string. - * - * ``` php - * seeInCurrentUrl('home'); - * // to match: /users/1 - * $I->seeInCurrentUrl('/users/'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeInCurrentUrl() - */ - public function canSeeInCurrentUrl($uri) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeInCurrentUrl', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current URI contains the given string. - * - * ``` php - * seeInCurrentUrl('home'); - * // to match: /users/1 - * $I->seeInCurrentUrl('/users/'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::seeInCurrentUrl() - */ - public function seeInCurrentUrl($uri) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeInCurrentUrl', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URI doesn't contain the given string. - * - * ``` php - * dontSeeInCurrentUrl('/users/'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeInCurrentUrl() - */ - public function cantSeeInCurrentUrl($uri) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInCurrentUrl', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URI doesn't contain the given string. - * - * ``` php - * dontSeeInCurrentUrl('/users/'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::dontSeeInCurrentUrl() - */ - public function dontSeeInCurrentUrl($uri) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeInCurrentUrl', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL is equal to the given string. - * Unlike `seeInCurrentUrl`, this only matches the full URL. - * - * ``` php - * seeCurrentUrlEquals('/'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlEquals() - */ - public function canSeeCurrentUrlEquals($uri) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeCurrentUrlEquals', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL is equal to the given string. - * Unlike `seeInCurrentUrl`, this only matches the full URL. - * - * ``` php - * seeCurrentUrlEquals('/'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlEquals() - */ - public function seeCurrentUrlEquals($uri) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeCurrentUrlEquals', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL doesn't equal the given string. - * Unlike `dontSeeInCurrentUrl`, this only matches the full URL. - * - * ``` php - * dontSeeCurrentUrlEquals('/'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlEquals() - */ - public function cantSeeCurrentUrlEquals($uri) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCurrentUrlEquals', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL doesn't equal the given string. - * Unlike `dontSeeInCurrentUrl`, this only matches the full URL. - * - * ``` php - * dontSeeCurrentUrlEquals('/'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlEquals() - */ - public function dontSeeCurrentUrlEquals($uri) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeCurrentUrlEquals', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL matches the given regular expression. - * - * ``` php - * seeCurrentUrlMatches('~$/users/(\d+)~'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlMatches() - */ - public function canSeeCurrentUrlMatches($uri) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeCurrentUrlMatches', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the current URL matches the given regular expression. - * - * ``` php - * seeCurrentUrlMatches('~$/users/(\d+)~'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::seeCurrentUrlMatches() - */ - public function seeCurrentUrlMatches($uri) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeCurrentUrlMatches', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current url doesn't match the given regular expression. - * - * ``` php - * dontSeeCurrentUrlMatches('~$/users/(\d+)~'); - * ?> - * ``` - * - * @param $uri - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlMatches() - */ - public function cantSeeCurrentUrlMatches($uri) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCurrentUrlMatches', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that current url doesn't match the given regular expression. - * - * ``` php - * dontSeeCurrentUrlMatches('~$/users/(\d+)~'); - * ?> - * ``` - * - * @param $uri - * @see \Codeception\Lib\InnerBrowser::dontSeeCurrentUrlMatches() - */ - public function dontSeeCurrentUrlMatches($uri) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeCurrentUrlMatches', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Executes the given regular expression against the current URI and returns the first match. - * If no parameters are provided, the full URI is returned. - * - * ``` php - * grabFromCurrentUrl('~$/user/(\d+)/~'); - * $uri = $I->grabFromCurrentUrl(); - * ?> - * ``` - * - * @param null $uri - * - * @internal param $url - * @return mixed - * @see \Codeception\Lib\InnerBrowser::grabFromCurrentUrl() - */ - public function grabFromCurrentUrl($uri = null) { - return $this->scenario->runStep(new \Codeception\Step\Action('grabFromCurrentUrl', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the specified checkbox is checked. - * - * ``` php - * seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms - * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user agreed to terms, If there is only one checkbox in form. - * $I->seeCheckboxIsChecked('//form/input[@type=checkbox and @name=agree]'); - * ?> - * ``` - * - * @param $checkbox - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeCheckboxIsChecked() - */ - public function canSeeCheckboxIsChecked($checkbox) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeCheckboxIsChecked', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the specified checkbox is checked. - * - * ``` php - * seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms - * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user agreed to terms, If there is only one checkbox in form. - * $I->seeCheckboxIsChecked('//form/input[@type=checkbox and @name=agree]'); - * ?> - * ``` - * - * @param $checkbox - * @see \Codeception\Lib\InnerBrowser::seeCheckboxIsChecked() - */ - public function seeCheckboxIsChecked($checkbox) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeCheckboxIsChecked', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Check that the specified checkbox is unchecked. - * - * ``` php - * dontSeeCheckboxIsChecked('#agree'); // I suppose user didn't agree to terms - * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user didn't check the first checkbox in form. - * ?> - * ``` - * - * @param $checkbox - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeCheckboxIsChecked() - */ - public function cantSeeCheckboxIsChecked($checkbox) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCheckboxIsChecked', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Check that the specified checkbox is unchecked. - * - * ``` php - * dontSeeCheckboxIsChecked('#agree'); // I suppose user didn't agree to terms - * $I->seeCheckboxIsChecked('#signup_form input[type=checkbox]'); // I suppose user didn't check the first checkbox in form. - * ?> - * ``` - * - * @param $checkbox - * @see \Codeception\Lib\InnerBrowser::dontSeeCheckboxIsChecked() - */ - public function dontSeeCheckboxIsChecked($checkbox) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeCheckboxIsChecked', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given input field or textarea contains the given value. - * For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath. - * - * ``` php - * seeInField('Body','Type your comment here'); - * $I->seeInField('form textarea[name=body]','Type your comment here'); - * $I->seeInField('form input[type=hidden]','hidden_value'); - * $I->seeInField('#searchform input','Search'); - * $I->seeInField('//form/*[@name=search]','Search'); - * $I->seeInField(['name' => 'search'], 'Search'); - * ?> - * ``` - * - * @param $field - * @param $value - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeInField() - */ - public function canSeeInField($field, $value) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeInField', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given input field or textarea contains the given value. - * For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath. - * - * ``` php - * seeInField('Body','Type your comment here'); - * $I->seeInField('form textarea[name=body]','Type your comment here'); - * $I->seeInField('form input[type=hidden]','hidden_value'); - * $I->seeInField('#searchform input','Search'); - * $I->seeInField('//form/*[@name=search]','Search'); - * $I->seeInField(['name' => 'search'], 'Search'); - * ?> - * ``` - * - * @param $field - * @param $value - * @see \Codeception\Lib\InnerBrowser::seeInField() - */ - public function seeInField($field, $value) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeInField', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that an input field or textarea doesn't contain the given value. - * For fuzzy locators, the field is matched by label text, CSS and XPath. - * - * ``` php - * dontSeeInField('Body','Type your comment here'); - * $I->dontSeeInField('form textarea[name=body]','Type your comment here'); - * $I->dontSeeInField('form input[type=hidden]','hidden_value'); - * $I->dontSeeInField('#searchform input','Search'); - * $I->dontSeeInField('//form/*[@name=search]','Search'); - * $I->dontSeeInField(['name' => 'search'], 'Search'); - * ?> - * ``` - * - * @param $field - * @param $value - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeInField() - */ - public function cantSeeInField($field, $value) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInField', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that an input field or textarea doesn't contain the given value. - * For fuzzy locators, the field is matched by label text, CSS and XPath. - * - * ``` php - * dontSeeInField('Body','Type your comment here'); - * $I->dontSeeInField('form textarea[name=body]','Type your comment here'); - * $I->dontSeeInField('form input[type=hidden]','hidden_value'); - * $I->dontSeeInField('#searchform input','Search'); - * $I->dontSeeInField('//form/*[@name=search]','Search'); - * $I->dontSeeInField(['name' => 'search'], 'Search'); - * ?> - * ``` - * - * @param $field - * @param $value - * @see \Codeception\Lib\InnerBrowser::dontSeeInField() - */ - public function dontSeeInField($field, $value) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeInField', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Submits the given form on the page, optionally with the given form values. - * Give the form fields values as an array. - * - * Skipped fields will be filled by their values from the page. - * You don't need to click the 'Submit' button afterwards. - * This command itself triggers the request to form's action. - * - * You can optionally specify what button's value to include - * in the request with the last parameter as an alternative to - * explicitly setting its value in the second parameter, as - * button values are not otherwise included in the request. - * - * Examples: - * - * ``` php - * submitForm('#login', array('login' => 'davert', 'password' => '123456')); - * // or - * $I->submitForm('#login', array('login' => 'davert', 'password' => '123456'), 'submitButtonName'); - * - * ``` - * - * For example, given this sample "Sign Up" form: - * - * ``` html - *
- * Login:
- * Password:
- * Do you agree to out terms?
- * Select pricing plan - * - *
- * ``` - * - * You could write the following to submit it: - * - * ``` php - * submitForm('#userForm', array('user' => array('login' => 'Davert', 'password' => '123456', 'agree' => true)), 'submitButton'); - * - * ``` - * Note that "2" will be the submitted value for the "plan" field, as it is the selected option. - * - * You can also emulate a JavaScript submission by not specifying any buttons in the third parameter to submitForm. - * - * ```php - * submitForm('#userForm', array('user' => array('login' => 'Davert', 'password' => '123456', 'agree' => true))); - * - * ``` - * - * @param $selector - * @param $params - * @param $button - * @see \Codeception\Lib\InnerBrowser::submitForm() - */ - public function submitForm($selector, $params, $button = null) { - return $this->scenario->runStep(new \Codeception\Step\Action('submitForm', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Fills a text field or textarea with the given string. - * - * ``` php - * fillField("//input[@type='text']", "Hello World!"); - * $I->fillField(['name' => 'email'], 'jon@mail.com'); - * ?> - * ``` - * - * @param $field - * @param $value - * @see \Codeception\Lib\InnerBrowser::fillField() - */ - public function fillField($field, $value) { - return $this->scenario->runStep(new \Codeception\Step\Action('fillField', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Selects an option in a select tag or in radio button group. - * - * ``` php - * selectOption('form select[name=account]', 'Premium'); - * $I->selectOption('form input[name=payment]', 'Monthly'); - * $I->selectOption('//form/select[@name=account]', 'Monthly'); - * ?> - * ``` - * - * Provide an array for the second argument to select multiple options: - * - * ``` php - * selectOption('Which OS do you use?', array('Windows','Linux')); - * ?> - * ``` - * - * @param $select - * @param $option - * @see \Codeception\Lib\InnerBrowser::selectOption() - */ - public function selectOption($select, $option) { - return $this->scenario->runStep(new \Codeception\Step\Action('selectOption', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Ticks a checkbox. For radio buttons, use the `selectOption` method instead. - * - * ``` php - * checkOption('#agree'); - * ?> - * ``` - * - * @param $option - * @see \Codeception\Lib\InnerBrowser::checkOption() - */ - public function checkOption($option) { - return $this->scenario->runStep(new \Codeception\Step\Action('checkOption', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Unticks a checkbox. - * - * ``` php - * uncheckOption('#notify'); - * ?> - * ``` - * - * @param $option - * @see \Codeception\Lib\InnerBrowser::uncheckOption() - */ - public function uncheckOption($option) { - return $this->scenario->runStep(new \Codeception\Step\Action('uncheckOption', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Attaches a file relative to the Codeception data directory to the given file upload field. - * - * ``` php - * attachFile('input[@type="file"]', 'prices.xls'); - * ?> - * ``` - * - * @param $field - * @param $filename - * @see \Codeception\Lib\InnerBrowser::attachFile() - */ - public function attachFile($field, $filename) { - return $this->scenario->runStep(new \Codeception\Step\Action('attachFile', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * If your page triggers an ajax request, you can perform it manually. - * This action sends a GET ajax request with specified params. - * - * See ->sendAjaxPostRequest for examples. - * - * @param $uri - * @param $params - * @see \Codeception\Lib\InnerBrowser::sendAjaxGetRequest() - */ - public function sendAjaxGetRequest($uri, $params = null) { - return $this->scenario->runStep(new \Codeception\Step\Action('sendAjaxGetRequest', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * If your page triggers an ajax request, you can perform it manually. - * This action sends a POST ajax request with specified params. - * Additional params can be passed as array. - * - * Example: - * - * Imagine that by clicking checkbox you trigger ajax request which updates user settings. - * We emulate that click by running this ajax request manually. - * - * ``` php - * sendAjaxPostRequest('/updateSettings', array('notifications' => true)); // POST - * $I->sendAjaxGetRequest('/updateSettings', array('notifications' => true)); // GET - * - * ``` - * - * @param $uri - * @param $params - * @see \Codeception\Lib\InnerBrowser::sendAjaxPostRequest() - */ - public function sendAjaxPostRequest($uri, $params = null) { - return $this->scenario->runStep(new \Codeception\Step\Action('sendAjaxPostRequest', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * If your page triggers an ajax request, you can perform it manually. - * This action sends an ajax request with specified method and params. - * - * Example: - * - * You need to perform an ajax request specifying the HTTP method. - * - * ``` php - * sendAjaxRequest('PUT', '/posts/7', array('title' => 'new title')); - * - * ``` - * - * @param $method - * @param $uri - * @param $params - * @see \Codeception\Lib\InnerBrowser::sendAjaxRequest() - */ - public function sendAjaxRequest($method, $uri, $params = null) { - return $this->scenario->runStep(new \Codeception\Step\Action('sendAjaxRequest', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Finds and returns the text contents of the given element. - * If a fuzzy locator is used, the element is found using CSS, XPath, and by matching the full page source by regular expression. - * - * ``` php - * grabTextFrom('h1'); - * $heading = $I->grabTextFrom('descendant-or-self::h1'); - * $value = $I->grabTextFrom('~ - * ``` - * - * @param $cssOrXPathOrRegex - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::grabTextFrom() - */ - public function grabTextFrom($cssOrXPathOrRegex) { - return $this->scenario->runStep(new \Codeception\Step\Action('grabTextFrom', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Grabs the value of the given attribute value from the given element. - * Fails if element is not found. - * - * ``` php - * grabAttributeFrom('#tooltip', 'title'); - * ?> - * ``` - * - * - * @param $cssOrXpath - * @param $attribute - * @internal param $element - * @return mixed - * @see \Codeception\Lib\InnerBrowser::grabAttributeFrom() - */ - public function grabAttributeFrom($cssOrXpath, $attribute) { - return $this->scenario->runStep(new \Codeception\Step\Action('grabAttributeFrom', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * @param $field - * - * @return array|mixed|null|string - * @see \Codeception\Lib\InnerBrowser::grabValueFrom() - */ - public function grabValueFrom($field) { - return $this->scenario->runStep(new \Codeception\Step\Action('grabValueFrom', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Sets a cookie with the given name and value. - * - * ``` php - * setCookie('PHPSESSID', 'el4ukv0kqbvoirg7nkp4dncpk3'); - * ?> - * ``` - * - * @param $cookie - * @param $value - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::setCookie() - */ - public function setCookie($name, $val) { - return $this->scenario->runStep(new \Codeception\Step\Action('setCookie', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Grabs a cookie value. - * - * @param $cookie - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::grabCookie() - */ - public function grabCookie($name) { - return $this->scenario->runStep(new \Codeception\Step\Action('grabCookie', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that a cookie with the given name is set. - * - * ``` php - * seeCookie('PHPSESSID'); - * ?> - * ``` - * - * @param $cookie - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeCookie() - */ - public function canSeeCookie($name) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeCookie', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that a cookie with the given name is set. - * - * ``` php - * seeCookie('PHPSESSID'); - * ?> - * ``` - * - * @param $cookie - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::seeCookie() - */ - public function seeCookie($name) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeCookie', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there isn't a cookie with the given name. - * - * @param $cookie - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeCookie() - */ - public function cantSeeCookie($name) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeCookie', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there isn't a cookie with the given name. - * - * @param $cookie - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::dontSeeCookie() - */ - public function dontSeeCookie($name) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeCookie', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Unsets cookie with the given name. - * - * @param $cookie - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::resetCookie() - */ - public function resetCookie($name) { - return $this->scenario->runStep(new \Codeception\Step\Action('resetCookie', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given element exists on the page and is visible. - * You can also specify expected attributes of this element. - * - * ``` php - * seeElement('.error'); - * $I->seeElement('//form/input[1]'); - * $I->seeElement('input', ['name' => 'login']); - * $I->seeElement('input', ['value' => '123456']); - * - * // strict locator in first arg, attributes in second - * $I->seeElement(['css' => 'form input'], ['name' => 'login']); - * ?> - * ``` - * - * @param $selector - * @param array $attributes - * @return - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeElement() - */ - public function canSeeElement($selector, $attributes = null) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeElement', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given element exists on the page and is visible. - * You can also specify expected attributes of this element. - * - * ``` php - * seeElement('.error'); - * $I->seeElement('//form/input[1]'); - * $I->seeElement('input', ['name' => 'login']); - * $I->seeElement('input', ['value' => '123456']); - * - * // strict locator in first arg, attributes in second - * $I->seeElement(['css' => 'form input'], ['name' => 'login']); - * ?> - * ``` - * - * @param $selector - * @param array $attributes - * @return - * @see \Codeception\Lib\InnerBrowser::seeElement() - */ - public function seeElement($selector, $attributes = null) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeElement', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given element is invisible or not present on the page. - * You can also specify expected attributes of this element. - * - * ``` php - * dontSeeElement('.error'); - * $I->dontSeeElement('//form/input[1]'); - * $I->dontSeeElement('input', ['name' => 'login']); - * $I->dontSeeElement('input', ['value' => '123456']); - * ?> - * ``` - * - * @param $selector - * @param array $attributes - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeElement() - */ - public function cantSeeElement($selector, $attributes = null) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeElement', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given element is invisible or not present on the page. - * You can also specify expected attributes of this element. - * - * ``` php - * dontSeeElement('.error'); - * $I->dontSeeElement('//form/input[1]'); - * $I->dontSeeElement('input', ['name' => 'login']); - * $I->dontSeeElement('input', ['value' => '123456']); - * ?> - * ``` - * - * @param $selector - * @param array $attributes - * @see \Codeception\Lib\InnerBrowser::dontSeeElement() - */ - public function dontSeeElement($selector, $attributes = null) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeElement', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there are a certain number of elements matched by the given locator on the page. - * - * ``` php - * seeNumberOfElements('tr', 10); - * $I->seeNumberOfElements('tr', [0,10]); //between 0 and 10 elements - * ?> - * ``` - * @param $selector - * @param mixed $expected: - * - string: strict number - * - array: range of numbers [0,10] - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeNumberOfElements() - */ - public function canSeeNumberOfElements($selector, $expected) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeNumberOfElements', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that there are a certain number of elements matched by the given locator on the page. - * - * ``` php - * seeNumberOfElements('tr', 10); - * $I->seeNumberOfElements('tr', [0,10]); //between 0 and 10 elements - * ?> - * ``` - * @param $selector - * @param mixed $expected: - * - string: strict number - * - array: range of numbers [0,10] - * @see \Codeception\Lib\InnerBrowser::seeNumberOfElements() - */ - public function seeNumberOfElements($selector, $expected) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeNumberOfElements', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given option is selected. - * - * ``` php - * seeOptionIsSelected('#form input[name=payment]', 'Visa'); - * ?> - * ``` - * - * @param $selector - * @param $optionText - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeOptionIsSelected() - */ - public function canSeeOptionIsSelected($select, $optionText) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeOptionIsSelected', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given option is selected. - * - * ``` php - * seeOptionIsSelected('#form input[name=payment]', 'Visa'); - * ?> - * ``` - * - * @param $selector - * @param $optionText - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::seeOptionIsSelected() - */ - public function seeOptionIsSelected($select, $optionText) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeOptionIsSelected', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given option is not selected. - * - * ``` php - * dontSeeOptionIsSelected('#form input[name=payment]', 'Visa'); - * ?> - * ``` - * - * @param $selector - * @param $optionText - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeOptionIsSelected() - */ - public function cantSeeOptionIsSelected($select, $optionText) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeOptionIsSelected', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the given option is not selected. - * - * ``` php - * dontSeeOptionIsSelected('#form input[name=payment]', 'Visa'); - * ?> - * ``` - * - * @param $selector - * @param $optionText - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::dontSeeOptionIsSelected() - */ - public function dontSeeOptionIsSelected($select, $optionText) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeOptionIsSelected', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Asserts that current page has 404 response status code. - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seePageNotFound() - */ - public function canSeePageNotFound() { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seePageNotFound', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Asserts that current page has 404 response status code. - * @see \Codeception\Lib\InnerBrowser::seePageNotFound() - */ - public function seePageNotFound() { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seePageNotFound', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks response code equals to provided value. - * - * @param $code - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\REST::seeResponseCodeIs() - */ - public function canSeeResponseCodeIs($code) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseCodeIs', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks response code equals to provided value. - * - * @param $code - * @see \Codeception\Module\REST::seeResponseCodeIs() - */ - public function seeResponseCodeIs($code) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseCodeIs', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page title contains the given string. - * - * ``` php - * seeInTitle('Blog - Post #1'); - * ?> - * ``` - * - * @param $title - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::seeInTitle() - */ - public function canSeeInTitle($title) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeInTitle', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page title contains the given string. - * - * ``` php - * seeInTitle('Blog - Post #1'); - * ?> - * ``` - * - * @param $title - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::seeInTitle() - */ - public function seeInTitle($title) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeInTitle', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page title does not contain the given string. - * - * @param $title - * - * @return mixed - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Lib\InnerBrowser::dontSeeInTitle() - */ - public function cantSeeInTitle($title) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeInTitle', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that the page title does not contain the given string. - * - * @param $title - * - * @return mixed - * @see \Codeception\Lib\InnerBrowser::dontSeeInTitle() - */ - public function dontSeeInTitle($title) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeInTitle', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Sets HTTP header - * - * @param $name - * @param $value - * @see \Codeception\Module\REST::haveHttpHeader() - */ - public function haveHttpHeader($name, $value) { - return $this->scenario->runStep(new \Codeception\Step\Action('haveHttpHeader', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks over the given HTTP header and (optionally) - * its value, asserting that are there - * - * @param $name - * @param $value - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\REST::seeHttpHeader() - */ - public function canSeeHttpHeader($name, $value = null) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeHttpHeader', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks over the given HTTP header and (optionally) - * its value, asserting that are there - * - * @param $name - * @param $value - * @see \Codeception\Module\REST::seeHttpHeader() - */ - public function seeHttpHeader($name, $value = null) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeHttpHeader', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks over the given HTTP header and (optionally) - * its value, asserting that are not there - * - * @param $name - * @param $value - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\REST::dontSeeHttpHeader() - */ - public function cantSeeHttpHeader($name, $value = null) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeHttpHeader', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks over the given HTTP header and (optionally) - * its value, asserting that are not there - * - * @param $name - * @param $value - * @see \Codeception\Module\REST::dontSeeHttpHeader() - */ - public function dontSeeHttpHeader($name, $value = null) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeHttpHeader', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that http response header is received only once. - * HTTP RFC2616 allows multiple response headers with the same name. - * You can check that you didn't accidentally sent the same header twice. - * - * ``` php - * seeHttpHeaderOnce('Cache-Control'); - * ?>> - * ``` - * - * @param $name - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\REST::seeHttpHeaderOnce() - */ - public function canSeeHttpHeaderOnce($name) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeHttpHeaderOnce', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that http response header is received only once. - * HTTP RFC2616 allows multiple response headers with the same name. - * You can check that you didn't accidentally sent the same header twice. - * - * ``` php - * seeHttpHeaderOnce('Cache-Control'); - * ?>> - * ``` - * - * @param $name - * @see \Codeception\Module\REST::seeHttpHeaderOnce() - */ - public function seeHttpHeaderOnce($name) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeHttpHeaderOnce', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Returns the value of the specified header name - * - * @param $name - * @param Boolean $first Whether to return the first value or all header values - * - * @return string|array The first header value if $first is true, an array of values otherwise - * @see \Codeception\Module\REST::grabHttpHeader() - */ - public function grabHttpHeader($name, $first = null) { - return $this->scenario->runStep(new \Codeception\Step\Action('grabHttpHeader', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Adds Digest authentication via username/password. - * - * @param $username - * @param $password - * @see \Codeception\Module\REST::amDigestAuthenticated() - */ - public function amDigestAuthenticated($username, $password) { - return $this->scenario->runStep(new \Codeception\Step\Condition('amDigestAuthenticated', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Adds Bearer authentication via access token. - * - * @param $accessToken - * @see \Codeception\Module\REST::amBearerAuthenticated() - */ - public function amBearerAuthenticated($accessToken) { - return $this->scenario->runStep(new \Codeception\Step\Condition('amBearerAuthenticated', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Sends a POST request to given uri. - * - * Parameters and files (as array of filenames) can be provided. - * - * @param $url - * @param array|\JsonSerializable $params - * @param array $files - * @see \Codeception\Module\REST::sendPOST() - */ - public function sendPOST($url, $params = null, $files = null) { - return $this->scenario->runStep(new \Codeception\Step\Action('sendPOST', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Sends a HEAD request to given uri. - * - * @param $url - * @param array $params - * @see \Codeception\Module\REST::sendHEAD() - */ - public function sendHEAD($url, $params = null) { - return $this->scenario->runStep(new \Codeception\Step\Action('sendHEAD', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Sends an OPTIONS request to given uri. - * - * @param $url - * @param array $params - * @see \Codeception\Module\REST::sendOPTIONS() - */ - public function sendOPTIONS($url, $params = null) { - return $this->scenario->runStep(new \Codeception\Step\Action('sendOPTIONS', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Sends a GET request to given uri. - * - * @param $url - * @param array $params - * @see \Codeception\Module\REST::sendGET() - */ - public function sendGET($url, $params = null) { - return $this->scenario->runStep(new \Codeception\Step\Action('sendGET', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Sends PUT request to given uri. - * - * @param $url - * @param array $params - * @param array $files - * @see \Codeception\Module\REST::sendPUT() - */ - public function sendPUT($url, $params = null, $files = null) { - return $this->scenario->runStep(new \Codeception\Step\Action('sendPUT', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Sends PATCH request to given uri. - * - * @param $url - * @param array $params - * @param array $files - * @see \Codeception\Module\REST::sendPATCH() - */ - public function sendPATCH($url, $params = null, $files = null) { - return $this->scenario->runStep(new \Codeception\Step\Action('sendPATCH', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Sends DELETE request to given uri. - * - * @param $url - * @param array $params - * @param array $files - * @see \Codeception\Module\REST::sendDELETE() - */ - public function sendDELETE($url, $params = null, $files = null) { - return $this->scenario->runStep(new \Codeception\Step\Action('sendDELETE', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Sends LINK request to given uri. - * - * @param $url - * @param array $linkEntries (entry is array with keys "uri" and "link-param") - * - * @link http://tools.ietf.org/html/rfc2068#section-19.6.2.4 - * - * @author samva.ua@gmail.com - * @see \Codeception\Module\REST::sendLINK() - */ - public function sendLINK($url, $linkEntries) { - return $this->scenario->runStep(new \Codeception\Step\Action('sendLINK', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Sends UNLINK request to given uri. - * - * @param $url - * @param array $linkEntries (entry is array with keys "uri" and "link-param") - * @link http://tools.ietf.org/html/rfc2068#section-19.6.2.4 - * @author samva.ua@gmail.com - * @see \Codeception\Module\REST::sendUNLINK() - */ - public function sendUNLINK($url, $linkEntries) { - return $this->scenario->runStep(new \Codeception\Step\Action('sendUNLINK', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks whether last response was valid JSON. - * This is done with json_last_error function. - * - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\REST::seeResponseIsJson() - */ - public function canSeeResponseIsJson() { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseIsJson', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks whether last response was valid JSON. - * This is done with json_last_error function. - * - * @see \Codeception\Module\REST::seeResponseIsJson() - */ - public function seeResponseIsJson() { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseIsJson', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks whether last response was valid XML. - * This is done with libxml_get_last_error function. - * - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\REST::seeResponseIsXml() - */ - public function canSeeResponseIsXml() { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseIsXml', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks whether last response was valid XML. - * This is done with libxml_get_last_error function. - * - * @see \Codeception\Module\REST::seeResponseIsXml() - */ - public function seeResponseIsXml() { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseIsXml', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks whether the last response contains text. - * - * @param $text - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\REST::seeResponseContains() - */ - public function canSeeResponseContains($text) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseContains', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks whether the last response contains text. - * - * @param $text - * @see \Codeception\Module\REST::seeResponseContains() - */ - public function seeResponseContains($text) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseContains', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks whether last response do not contain text. - * - * @param $text - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\REST::dontSeeResponseContains() - */ - public function cantSeeResponseContains($text) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeResponseContains', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks whether last response do not contain text. - * - * @param $text - * @see \Codeception\Module\REST::dontSeeResponseContains() - */ - public function dontSeeResponseContains($text) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeResponseContains', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks whether the last JSON response contains provided array. - * The response is converted to array with json_decode($response, true) - * Thus, JSON is represented by associative array. - * This method matches that response array contains provided array. - * - * Examples: - * - * ``` php - * seeResponseContainsJson(array('name' => 'john')); - * - * // response {user: john, profile: { email: john@gmail.com }} - * $I->seeResponseContainsJson(array('email' => 'john@gmail.com')); - * - * ?> - * ``` - * - * This method recursively checks if one array can be found inside of another. - * - * @param array $json - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\REST::seeResponseContainsJson() - */ - public function canSeeResponseContainsJson($json = null) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseContainsJson', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks whether the last JSON response contains provided array. - * The response is converted to array with json_decode($response, true) - * Thus, JSON is represented by associative array. - * This method matches that response array contains provided array. - * - * Examples: - * - * ``` php - * seeResponseContainsJson(array('name' => 'john')); - * - * // response {user: john, profile: { email: john@gmail.com }} - * $I->seeResponseContainsJson(array('email' => 'john@gmail.com')); - * - * ?> - * ``` - * - * This method recursively checks if one array can be found inside of another. - * - * @param array $json - * @see \Codeception\Module\REST::seeResponseContainsJson() - */ - public function seeResponseContainsJson($json = null) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseContainsJson', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Returns current response so that it can be used in next scenario steps. - * - * Example: - * - * ``` php - * grabResponse(); - * $I->sendPUT('/user', array('id' => $user_id, 'name' => 'davert')); - * ?> - * ``` - * - * @version 1.1 - * @return string - * @see \Codeception\Module\REST::grabResponse() - */ - public function grabResponse() { - return $this->scenario->runStep(new \Codeception\Step\Action('grabResponse', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Returns data from the current JSON response using specified path - * so that it can be used in next scenario steps. - * - * **this method is deprecated in favor of `grabDataFromResponseByJsonPath`** - * - * Example: - * - * ``` php - * grabDataFromJsonResponse('user.user_id'); - * $I->sendPUT('/user', array('id' => $user_id, 'name' => 'davert')); - * ?> - * ``` - * - * @deprecated please use `grabDataFromResponseByJsonPath` - * @param string $path - * @return string - * @see \Codeception\Module\REST::grabDataFromJsonResponse() - */ - public function grabDataFromJsonResponse($path = null) { - return $this->scenario->runStep(new \Codeception\Step\Action('grabDataFromJsonResponse', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Returns data from the current JSON response using [JSONPath](http://goessner.net/articles/JsonPath/) as selector. - * JsonPath is XPath equivalent for querying Json structures. Try your JsonPath expressions [online](http://jsonpath.curiousconcept.com/). - * Even for a single value an array is returned. - * - * This method **require [`flow/jsonpath`](https://github.com/FlowCommunications/JSONPath/) library to be installed**. - * - * Example: - * - * ``` php - * grabDataFromJsonResponse('$..users[0].id'); - * $I->sendPUT('/user', array('id' => $firstUser[0], 'name' => 'davert')); - * ?> - * ``` - * - * @param $jsonPath - * @return array - * @version 2.0.9 - * @throws \Exception - * @see \Codeception\Module\REST::grabDataFromResponseByJsonPath() - */ - public function grabDataFromResponseByJsonPath($jsonPath) { - return $this->scenario->runStep(new \Codeception\Step\Action('grabDataFromResponseByJsonPath', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if json structure in response matches the xpath provided. - * JSON is not supposed to be checked against XPath, yet it can be converted to xml and used with XPath. - * This assertion allows you to check the structure of response json. - * * - * ```json - * ```json - * { "store": { - * "book": [ - * { "category": "reference", - * "author": "Nigel Rees", - * "title": "Sayings of the Century", - * "price": 8.95 - * }, - * { "category": "fiction", - * "author": "Evelyn Waugh", - * "title": "Sword of Honour", - * "price": 12.99 - * } - * ], - * "bicycle": { - * "color": "red", - * "price": 19.95 - * } - * } - * } - * ``` - * - * ```php - * seeResponseJsonMatchesXpath('//store/book/author'); - * // first book in store has author - * $I->seeResponseJsonMatchesXpath('//store/book[1]/author'); - * // at least one item in store has price - * $I->seeResponseJsonMatchesXpath('/store//price'); - * ?> - * ``` - * - * @version 2.0.9 - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\REST::seeResponseJsonMatchesXpath() - */ - public function canSeeResponseJsonMatchesXpath($xpath) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseJsonMatchesXpath', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if json structure in response matches the xpath provided. - * JSON is not supposed to be checked against XPath, yet it can be converted to xml and used with XPath. - * This assertion allows you to check the structure of response json. - * * - * ```json - * ```json - * { "store": { - * "book": [ - * { "category": "reference", - * "author": "Nigel Rees", - * "title": "Sayings of the Century", - * "price": 8.95 - * }, - * { "category": "fiction", - * "author": "Evelyn Waugh", - * "title": "Sword of Honour", - * "price": 12.99 - * } - * ], - * "bicycle": { - * "color": "red", - * "price": 19.95 - * } - * } - * } - * ``` - * - * ```php - * seeResponseJsonMatchesXpath('//store/book/author'); - * // first book in store has author - * $I->seeResponseJsonMatchesXpath('//store/book[1]/author'); - * // at least one item in store has price - * $I->seeResponseJsonMatchesXpath('/store//price'); - * ?> - * ``` - * - * @version 2.0.9 - * @see \Codeception\Module\REST::seeResponseJsonMatchesXpath() - */ - public function seeResponseJsonMatchesXpath($xpath) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseJsonMatchesXpath', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if json structure in response matches [JsonPath](http://goessner.net/articles/JsonPath/). - * JsonPath is XPath equivalent for querying Json structures. Try your JsonPath expressions [online](http://jsonpath.curiousconcept.com/). - * This assertion allows you to check the structure of response json. - * - * This method **require [`flow/jsonpath`](https://github.com/FlowCommunications/JSONPath/) library to be installed**. - * - * ```json - * { "store": { - * "book": [ - * { "category": "reference", - * "author": "Nigel Rees", - * "title": "Sayings of the Century", - * "price": 8.95 - * }, - * { "category": "fiction", - * "author": "Evelyn Waugh", - * "title": "Sword of Honour", - * "price": 12.99 - * } - * ], - * "bicycle": { - * "color": "red", - * "price": 19.95 - * } - * } - * } - * ``` - * - * ```php - * seeResponseJsonMatchesJsonPath('$.store.book[*].author'); - * // first book in store has author - * $I->seeResponseJsonMatchesJsonPath('$.store.book[0].author'); - * // at least one item in store has price - * $I->seeResponseJsonMatchesJsonPath('$.store..price'); - * ?> - * ``` - * - * @version 2.0.9 - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\REST::seeResponseJsonMatchesJsonPath() - */ - public function canSeeResponseJsonMatchesJsonPath($jsonPath) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseJsonMatchesJsonPath', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if json structure in response matches [JsonPath](http://goessner.net/articles/JsonPath/). - * JsonPath is XPath equivalent for querying Json structures. Try your JsonPath expressions [online](http://jsonpath.curiousconcept.com/). - * This assertion allows you to check the structure of response json. - * - * This method **require [`flow/jsonpath`](https://github.com/FlowCommunications/JSONPath/) library to be installed**. - * - * ```json - * { "store": { - * "book": [ - * { "category": "reference", - * "author": "Nigel Rees", - * "title": "Sayings of the Century", - * "price": 8.95 - * }, - * { "category": "fiction", - * "author": "Evelyn Waugh", - * "title": "Sword of Honour", - * "price": 12.99 - * } - * ], - * "bicycle": { - * "color": "red", - * "price": 19.95 - * } - * } - * } - * ``` - * - * ```php - * seeResponseJsonMatchesJsonPath('$.store.book[*].author'); - * // first book in store has author - * $I->seeResponseJsonMatchesJsonPath('$.store.book[0].author'); - * // at least one item in store has price - * $I->seeResponseJsonMatchesJsonPath('$.store..price'); - * ?> - * ``` - * - * @version 2.0.9 - * @see \Codeception\Module\REST::seeResponseJsonMatchesJsonPath() - */ - public function seeResponseJsonMatchesJsonPath($jsonPath) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseJsonMatchesJsonPath', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Opposite to seeResponseContainsJson - * - * @param array $json - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\REST::dontSeeResponseContainsJson() - */ - public function cantSeeResponseContainsJson($json = null) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeResponseContainsJson', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Opposite to seeResponseContainsJson - * - * @param array $json - * @see \Codeception\Module\REST::dontSeeResponseContainsJson() - */ - public function dontSeeResponseContainsJson($json = null) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeResponseContainsJson', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if response is exactly the same as provided. - * - * @param $response - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\REST::seeResponseEquals() - */ - public function canSeeResponseEquals($response) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('seeResponseEquals', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks if response is exactly the same as provided. - * - * @param $response - * @see \Codeception\Module\REST::seeResponseEquals() - */ - public function seeResponseEquals($response) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('seeResponseEquals', func_get_args())); - } - - - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that response code is not equal to provided value. - * - * @param $code - * Conditional Assertion: Test won't be stopped on fail - * @see \Codeception\Module\REST::dontSeeResponseCodeIs() - */ - public function cantSeeResponseCodeIs($code) { - return $this->scenario->runStep(new \Codeception\Step\ConditionalAssertion('dontSeeResponseCodeIs', func_get_args())); - } - /** - * [!] Method is generated. Documentation taken from corresponding module. - * - * Checks that response code is not equal to provided value. - * - * @param $code - * @see \Codeception\Module\REST::dontSeeResponseCodeIs() - */ - public function dontSeeResponseCodeIs($code) { - return $this->scenario->runStep(new \Codeception\Step\Assertion('dontSeeResponseCodeIs', func_get_args())); - } -} From 82413513e8002dc197a2fd9f13059eb88cd78ac1 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 14 Oct 2015 09:51:53 +0100 Subject: [PATCH 066/444] Checkin --- composer.json | 8 +- examples/composer.json | 1 - examples/composer.lock | 669 ++++------------------ examples/public/client_credentials.php | 26 +- src/Exception/InvalidRequestException.php | 2 +- src/Exception/OAuthException.php | 47 +- src/Grant/AbstractGrant.php | 32 +- src/Grant/AuthCodeGrant.php | 2 +- src/Grant/ClientCredentialsGrant.php | 53 +- src/Grant/GrantTypeInterface.php | 30 +- src/Grant/RefreshTokenGrant.php | 2 +- src/ResourceServer.php | 154 ----- src/Server.php | 127 ++-- src/TokenTypes/BearerTokenType.php | 24 +- src/TokenTypes/TokenTypeInterface.php | 11 +- 15 files changed, 337 insertions(+), 851 deletions(-) delete mode 100644 src/ResourceServer.php diff --git a/composer.json b/composer.json index 6c0a44ff..19dc5c40 100644 --- a/composer.json +++ b/composer.json @@ -4,14 +4,12 @@ "homepage": "http://oauth2.thephpleague.com/", "license": "MIT", "require": { - "php": ">=5.4.0", - "symfony/http-foundation": "~2.4", + "php": ">=5.5.9", "league/event": "~2.1", - "league/container": "~1.0", - "firebase/php-jwt": "~2.0" + "zendframework/zend-diactoros": "~1.1" }, "require-dev": { - "phpunit/phpunit": "4.3.*", + "phpunit/phpunit": "4.8.*", "mockery/mockery": "0.9.*", "codeception/codeception": "~2.0", "flow/jsonpath": "0.2.*" diff --git a/examples/composer.json b/examples/composer.json index 572002da..6b017bce 100644 --- a/examples/composer.json +++ b/examples/composer.json @@ -2,7 +2,6 @@ "name": "", "require": { "alexbilbie/proton": "~1.4", - "illuminate/database": "~5.0", "ircmaxell/password-compat": "~1.0" }, "autoload": { diff --git a/examples/composer.lock b/examples/composer.lock index 8f5782c0..8570127f 100644 --- a/examples/composer.lock +++ b/examples/composer.lock @@ -1,10 +1,11 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "9ae3d11ba275cce8764cfa3002ec7c93", + "hash": "ad90034834be06a42fc0b780af9a9425", + "content-hash": "caf5b7d7e9c81d118a89ce3b7a38b6ad", "packages": [ { "name": "alexbilbie/proton", @@ -64,368 +65,6 @@ ], "time": "2015-03-26 17:35:31" }, - { - "name": "danielstjules/stringy", - "version": "1.9.0", - "source": { - "type": "git", - "url": "https://github.com/danielstjules/Stringy.git", - "reference": "3cf18e9e424a6dedc38b7eb7ef580edb0929461b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/danielstjules/Stringy/zipball/3cf18e9e424a6dedc38b7eb7ef580edb0929461b", - "reference": "3cf18e9e424a6dedc38b7eb7ef580edb0929461b", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Stringy\\": "src/" - }, - "files": [ - "src/Create.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel St. Jules", - "email": "danielst.jules@gmail.com", - "homepage": "http://www.danielstjules.com" - } - ], - "description": "A string manipulation library with multibyte support", - "homepage": "https://github.com/danielstjules/Stringy", - "keywords": [ - "UTF", - "helpers", - "manipulation", - "methods", - "multibyte", - "string", - "utf-8", - "utility", - "utils" - ], - "time": "2015-02-10 06:19:18" - }, - { - "name": "doctrine/inflector", - "version": "v1.0.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/inflector.git", - "reference": "0bcb2e79d8571787f18b7eb036ed3d004908e604" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/0bcb2e79d8571787f18b7eb036ed3d004908e604", - "reference": "0bcb2e79d8571787f18b7eb036ed3d004908e604", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "4.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "Doctrine\\Common\\Inflector\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Common String Manipulations with regard to casing and singular/plural rules.", - "homepage": "http://www.doctrine-project.org", - "keywords": [ - "inflection", - "pluralize", - "singularize", - "string" - ], - "time": "2014-12-20 21:24:13" - }, - { - "name": "firebase/php-jwt", - "version": "2.0.0", - "target-dir": "Firebase/PHP-JWT", - "source": { - "type": "git", - "url": "https://github.com/firebase/php-jwt.git", - "reference": "ffcfd888ce1e4f2d70cac2dc9b7301038332fe57" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/firebase/php-jwt/zipball/ffcfd888ce1e4f2d70cac2dc9b7301038332fe57", - "reference": "ffcfd888ce1e4f2d70cac2dc9b7301038332fe57", - "shasum": "" - }, - "require": { - "php": ">=5.2.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "Authentication/", - "Exceptions/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Neuman Vong", - "email": "neuman+pear@twilio.com", - "role": "Developer" - }, - { - "name": "Anant Narayanan", - "email": "anant@php.net", - "role": "Developer" - } - ], - "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", - "homepage": "https://github.com/firebase/php-jwt", - "time": "2015-04-01 18:46:38" - }, - { - "name": "illuminate/container", - "version": "v5.0.26", - "source": { - "type": "git", - "url": "https://github.com/illuminate/container.git", - "reference": "a11c01c1d8b6941bd7ef2f104749ada5e34f146e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/illuminate/container/zipball/a11c01c1d8b6941bd7ef2f104749ada5e34f146e", - "reference": "a11c01c1d8b6941bd7ef2f104749ada5e34f146e", - "shasum": "" - }, - "require": { - "illuminate/contracts": "5.0.*", - "php": ">=5.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "psr-4": { - "Illuminate\\Container\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylorotwell@gmail.com" - } - ], - "description": "The Illuminate Container package.", - "homepage": "http://laravel.com", - "time": "2015-03-25 17:06:14" - }, - { - "name": "illuminate/contracts", - "version": "v5.0.0", - "source": { - "type": "git", - "url": "https://github.com/illuminate/contracts.git", - "reference": "78f1dba092d5fcb6d3a19537662abe31c4d128fd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/illuminate/contracts/zipball/78f1dba092d5fcb6d3a19537662abe31c4d128fd", - "reference": "78f1dba092d5fcb6d3a19537662abe31c4d128fd", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "psr-4": { - "Illuminate\\Contracts\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylorotwell@gmail.com" - } - ], - "description": "The Illuminate Contracts package.", - "time": "2015-01-30 16:27:08" - }, - { - "name": "illuminate/database", - "version": "v5.0.27", - "source": { - "type": "git", - "url": "https://github.com/illuminate/database.git", - "reference": "8d41d6a2c20b4295f7f77b5ee1ac91d9060510f5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/illuminate/database/zipball/8d41d6a2c20b4295f7f77b5ee1ac91d9060510f5", - "reference": "8d41d6a2c20b4295f7f77b5ee1ac91d9060510f5", - "shasum": "" - }, - "require": { - "illuminate/container": "5.0.*", - "illuminate/contracts": "5.0.*", - "illuminate/support": "5.0.*", - "nesbot/carbon": "~1.0", - "php": ">=5.4.0" - }, - "suggest": { - "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.4).", - "illuminate/console": "Required to use the database commands (5.0.*).", - "illuminate/events": "Required to use the observers with Eloquent (5.0.*).", - "illuminate/filesystem": "Required to use the migrations (5.0.*)." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "psr-4": { - "Illuminate\\Database\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylorotwell@gmail.com" - } - ], - "description": "The Illuminate Database package.", - "homepage": "http://laravel.com", - "keywords": [ - "database", - "laravel", - "orm", - "sql" - ], - "time": "2015-04-04 01:34:34" - }, - { - "name": "illuminate/support", - "version": "v5.0.26", - "source": { - "type": "git", - "url": "https://github.com/illuminate/support.git", - "reference": "29e8618a45d090572e092abf193a257bf28c48d9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/29e8618a45d090572e092abf193a257bf28c48d9", - "reference": "29e8618a45d090572e092abf193a257bf28c48d9", - "shasum": "" - }, - "require": { - "danielstjules/stringy": "~1.8", - "doctrine/inflector": "~1.0", - "ext-mbstring": "*", - "illuminate/contracts": "5.0.*", - "php": ">=5.4.0" - }, - "suggest": { - "jeremeamia/superclosure": "Required to be able to serialize closures (~2.0)." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "psr-4": { - "Illuminate\\Support\\": "" - }, - "files": [ - "helpers.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylorotwell@gmail.com" - } - ], - "description": "The Illuminate Support package.", - "homepage": "http://laravel.com", - "time": "2015-03-27 14:49:11" - }, { "name": "ircmaxell/password-compat", "version": "v1.0.4", @@ -470,16 +109,16 @@ }, { "name": "league/container", - "version": "1.3.1", + "version": "1.3.2", "source": { "type": "git", "url": "https://github.com/thephpleague/container.git", - "reference": "6cbb3d83bfb979eaf43cd3c279c22abf3fbcf9ff" + "reference": "7e6c17fe48f76f3b97aeca70dc29c3f3c7c88d15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/container/zipball/6cbb3d83bfb979eaf43cd3c279c22abf3fbcf9ff", - "reference": "6cbb3d83bfb979eaf43cd3c279c22abf3fbcf9ff", + "url": "https://api.github.com/repos/thephpleague/container/zipball/7e6c17fe48f76f3b97aeca70dc29c3f3c7c88d15", + "reference": "7e6c17fe48f76f3b97aeca70dc29c3f3c7c88d15", "shasum": "" }, "require": { @@ -494,7 +133,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3-dev" + "dev-master": "2.0-dev", + "dev-1.x": "1.3-dev" } }, "autoload": { @@ -523,20 +163,20 @@ "injection", "league" ], - "time": "2015-02-21 18:55:49" + "time": "2015-04-05 17:14:48" }, { "name": "league/event", - "version": "2.1.1", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/thephpleague/event.git", - "reference": "cecc6213023a8b18efb163853569082051e5f1ea" + "reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/event/zipball/cecc6213023a8b18efb163853569082051e5f1ea", - "reference": "cecc6213023a8b18efb163853569082051e5f1ea", + "url": "https://api.github.com/repos/thephpleague/event/zipball/e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd", + "reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd", "shasum": "" }, "require": { @@ -573,20 +213,20 @@ "event", "listener" ], - "time": "2015-03-30 07:53:52" + "time": "2015-05-21 12:24:47" }, { "name": "league/route", - "version": "1.1.0", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/thephpleague/route.git", - "reference": "06b0b3cb203f329875ad534d0f8a049d23767005" + "reference": "079e87a4653b43e2cba47b9e0563179c1c49fcf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/route/zipball/06b0b3cb203f329875ad534d0f8a049d23767005", - "reference": "06b0b3cb203f329875ad534d0f8a049d23767005", + "url": "https://api.github.com/repos/thephpleague/route/zipball/079e87a4653b43e2cba47b9e0563179c1c49fcf8", + "reference": "079e87a4653b43e2cba47b9e0563179c1c49fcf8", "shasum": "" }, "require": { @@ -631,20 +271,20 @@ "league", "route" ], - "time": "2015-02-24 18:34:01" + "time": "2015-09-11 07:40:31" }, { "name": "monolog/monolog", - "version": "1.13.1", + "version": "1.17.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "c31a2c4e8db5da8b46c74cf275d7f109c0f249ac" + "reference": "0524c87587ab85bc4c2d6f5b41253ccb930a5422" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c31a2c4e8db5da8b46c74cf275d7f109c0f249ac", - "reference": "c31a2c4e8db5da8b46c74cf275d7f109c0f249ac", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/0524c87587ab85bc4c2d6f5b41253ccb930a5422", + "reference": "0524c87587ab85bc4c2d6f5b41253ccb930a5422", "shasum": "" }, "require": { @@ -655,12 +295,14 @@ "psr/log-implementation": "1.0.0" }, "require-dev": { - "aws/aws-sdk-php": "~2.4, >2.4.8", + "aws/aws-sdk-php": "^2.4.9", "doctrine/couchdb": "~1.0@dev", "graylog2/gelf-php": "~1.0", - "phpunit/phpunit": "~4.0", - "raven/raven": "~0.5", - "ruflin/elastica": "0.90.*", + "php-console/php-console": "^3.1.3", + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "2.3.0", + "raven/raven": "~0.11", + "ruflin/elastica": ">=0.90 <3.0", "swiftmailer/swiftmailer": "~5.3", "videlalvaro/php-amqplib": "~2.4" }, @@ -670,6 +312,7 @@ "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", "ext-mongo": "Allow sending log messages to a MongoDB server", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "php-console/php-console": "Allow sending log messages to Google Chrome", "raven/raven": "Allow sending log messages to a Sentry server", "rollbar/rollbar": "Allow sending log messages to Rollbar", "ruflin/elastica": "Allow sending log messages to an Elastic Search server", @@ -678,7 +321,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.13.x-dev" + "dev-master": "1.16.x-dev" } }, "autoload": { @@ -704,67 +347,20 @@ "logging", "psr-3" ], - "time": "2015-03-09 09:58:04" - }, - { - "name": "nesbot/carbon", - "version": "1.18.0", - "source": { - "type": "git", - "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "99e2f69f7bdc2cc4334b2d00f1e0ba450623ea36" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/99e2f69f7bdc2cc4334b2d00f1e0ba450623ea36", - "reference": "99e2f69f7bdc2cc4334b2d00f1e0ba450623ea36", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "symfony/translation": "2.6.*" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "Carbon": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Brian Nesbitt", - "email": "brian@nesbot.com", - "homepage": "http://nesbot.com" - } - ], - "description": "A simple API extension for DateTime.", - "homepage": "http://carbon.nesbot.com", - "keywords": [ - "date", - "datetime", - "time" - ], - "time": "2015-03-26 03:05:57" + "time": "2015-08-31 09:17:37" }, { "name": "nikic/fast-route", - "version": "v0.4.0", + "version": "v0.6.0", "source": { "type": "git", "url": "https://github.com/nikic/FastRoute.git", - "reference": "f26a8f7788f25c0e3e9b1579d38d7ccab2755320" + "reference": "31fa86924556b80735f98b294a7ffdfb26789f22" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/FastRoute/zipball/f26a8f7788f25c0e3e9b1579d38d7ccab2755320", - "reference": "f26a8f7788f25c0e3e9b1579d38d7ccab2755320", + "url": "https://api.github.com/repos/nikic/FastRoute/zipball/31fa86924556b80735f98b294a7ffdfb26789f22", + "reference": "31fa86924556b80735f98b294a7ffdfb26789f22", "shasum": "" }, "require": { @@ -794,7 +390,7 @@ "router", "routing" ], - "time": "2015-02-26 15:33:07" + "time": "2015-06-18 19:15:47" }, { "name": "psr/log", @@ -836,21 +432,20 @@ }, { "name": "symfony/debug", - "version": "v2.6.6", - "target-dir": "Symfony/Component/Debug", + "version": "v2.7.5", "source": { "type": "git", - "url": "https://github.com/symfony/Debug.git", - "reference": "d49a46a20a8f0544aedac54466750ad787d3d3e3" + "url": "https://github.com/symfony/debug.git", + "reference": "c79c361bca8e5ada6a47603875a3c964d03b67b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Debug/zipball/d49a46a20a8f0544aedac54466750ad787d3d3e3", - "reference": "d49a46a20a8f0544aedac54466750ad787d3d3e3", + "url": "https://api.github.com/repos/symfony/debug/zipball/c79c361bca8e5ada6a47603875a3c964d03b67b1", + "reference": "c79c361bca8e5ada6a47603875a3c964d03b67b1", "shasum": "" }, "require": { - "php": ">=5.3.3", + "php": ">=5.3.9", "psr/log": "~1.0" }, "conflict": { @@ -858,22 +453,17 @@ }, "require-dev": { "symfony/class-loader": "~2.2", - "symfony/http-foundation": "~2.1", "symfony/http-kernel": "~2.3.24|~2.5.9|~2.6,>=2.6.2", "symfony/phpunit-bridge": "~2.7" }, - "suggest": { - "symfony/http-foundation": "", - "symfony/http-kernel": "" - }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "2.7-dev" } }, "autoload": { - "psr-0": { + "psr-4": { "Symfony\\Component\\Debug\\": "" } }, @@ -882,36 +472,35 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Debug Component", - "homepage": "http://symfony.com", - "time": "2015-03-22 16:55:57" + "homepage": "https://symfony.com", + "time": "2015-09-14 08:41:38" }, { "name": "symfony/event-dispatcher", - "version": "v2.6.6", - "target-dir": "Symfony/Component/EventDispatcher", + "version": "v2.7.5", "source": { "type": "git", - "url": "https://github.com/symfony/EventDispatcher.git", - "reference": "70f7c8478739ad21e3deef0d977b38c77f1fb284" + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "ae4dcc2a8d3de98bd794167a3ccda1311597c5d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/70f7c8478739ad21e3deef0d977b38c77f1fb284", - "reference": "70f7c8478739ad21e3deef0d977b38c77f1fb284", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ae4dcc2a8d3de98bd794167a3ccda1311597c5d9", + "reference": "ae4dcc2a8d3de98bd794167a3ccda1311597c5d9", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3.9" }, "require-dev": { "psr/log": "~1.0", @@ -928,11 +517,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "2.7-dev" } }, "autoload": { - "psr-0": { + "psr-4": { "Symfony\\Component\\EventDispatcher\\": "" } }, @@ -941,36 +530,35 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony EventDispatcher Component", - "homepage": "http://symfony.com", - "time": "2015-03-13 17:37:22" + "homepage": "https://symfony.com", + "time": "2015-09-22 13:49:29" }, { "name": "symfony/http-foundation", - "version": "v2.6.6", - "target-dir": "Symfony/Component/HttpFoundation", + "version": "v2.7.5", "source": { "type": "git", - "url": "https://github.com/symfony/HttpFoundation.git", - "reference": "8a6337233f08f7520de97f4ffd6f00e947d892f9" + "url": "https://github.com/symfony/http-foundation.git", + "reference": "e1509119f164a0d0a940d7d924d693a7a28a5470" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/8a6337233f08f7520de97f4ffd6f00e947d892f9", - "reference": "8a6337233f08f7520de97f4ffd6f00e947d892f9", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e1509119f164a0d0a940d7d924d693a7a28a5470", + "reference": "e1509119f164a0d0a940d7d924d693a7a28a5470", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3.9" }, "require-dev": { "symfony/expression-language": "~2.4", @@ -979,15 +567,15 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "2.7-dev" } }, "autoload": { - "psr-0": { + "psr-4": { "Symfony\\Component\\HttpFoundation\\": "" }, "classmap": [ - "Symfony/Component/HttpFoundation/Resources/stubs" + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -995,45 +583,47 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony HttpFoundation Component", - "homepage": "http://symfony.com", - "time": "2015-04-01 16:50:12" + "homepage": "https://symfony.com", + "time": "2015-09-22 13:49:29" }, { "name": "symfony/http-kernel", - "version": "v2.6.6", - "target-dir": "Symfony/Component/HttpKernel", + "version": "v2.7.5", "source": { "type": "git", - "url": "https://github.com/symfony/HttpKernel.git", - "reference": "3829cacfe21eaf3f73604a62d79183d1f6e792c4" + "url": "https://github.com/symfony/http-kernel.git", + "reference": "353aa457424262d7d4e4289ea483145921cffcb5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/HttpKernel/zipball/3829cacfe21eaf3f73604a62d79183d1f6e792c4", - "reference": "3829cacfe21eaf3f73604a62d79183d1f6e792c4", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/353aa457424262d7d4e4289ea483145921cffcb5", + "reference": "353aa457424262d7d4e4289ea483145921cffcb5", "shasum": "" }, "require": { - "php": ">=5.3.3", + "php": ">=5.3.9", "psr/log": "~1.0", "symfony/debug": "~2.6,>=2.6.2", - "symfony/event-dispatcher": "~2.5.9|~2.6,>=2.6.2", + "symfony/event-dispatcher": "~2.6,>=2.6.7", "symfony/http-foundation": "~2.5,>=2.5.4" }, + "conflict": { + "symfony/config": "<2.7" + }, "require-dev": { "symfony/browser-kit": "~2.3", "symfony/class-loader": "~2.1", - "symfony/config": "~2.0,>=2.0.5", + "symfony/config": "~2.7", "symfony/console": "~2.3", "symfony/css-selector": "~2.0,>=2.0.5", "symfony/dependency-injection": "~2.2", @@ -1060,11 +650,11 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "2.7-dev" } }, "autoload": { - "psr-0": { + "psr-4": { "Symfony\\Component\\HttpKernel\\": "" } }, @@ -1073,77 +663,18 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony HttpKernel Component", - "homepage": "http://symfony.com", - "time": "2015-04-01 16:55:26" - }, - { - "name": "symfony/translation", - "version": "v2.6.6", - "target-dir": "Symfony/Component/Translation", - "source": { - "type": "git", - "url": "https://github.com/symfony/Translation.git", - "reference": "bd939f05cdaca128f4ddbae1b447d6f0203b60af" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Translation/zipball/bd939f05cdaca128f4ddbae1b447d6f0203b60af", - "reference": "bd939f05cdaca128f4ddbae1b447d6f0203b60af", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.3,>=2.3.12", - "symfony/intl": "~2.3", - "symfony/phpunit-bridge": "~2.7", - "symfony/yaml": "~2.2" - }, - "suggest": { - "psr/log": "To use logging capability in translator", - "symfony/config": "", - "symfony/yaml": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Translation\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "Symfony Translation Component", - "homepage": "http://symfony.com", - "time": "2015-03-30 15:54:10" + "homepage": "https://symfony.com", + "time": "2015-09-25 11:16:52" } ], "packages-dev": [], diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index 1075fe14..db359b92 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -1,32 +1,20 @@ addRepository(new ClientRepository()); -$server->addRepository(new ScopeRepository()); -$server->addRepository(new AccessTokenRepository()); -// Enable the client credentials grant which will return access tokens that last for 24 hours -$server->enableGrantType('ClientCredentialsGrant', null, new \DateInterval('PT24H')); +// Init our repositories +$clientRepository = new ClientRepository(); +$scopeRepository = new ScopeRepository(); +$accessTokenRepository = new AccessTokenRepository(); -// Setup app + routing -$application = new \Proton\Application(); -$application->post('/access_token', function (Request $request) use ($server) { - try { - return $server->getAccessTokenResponse($request); - } catch (OAuthException $e) { - return $e->generateHttpResponse(); - } -}); - -// Run the app -$application->run(); +// Enable the client credentials grant on the server +$server->enableGrantType(new ClientCredentialsGrant($clientRepository, $scopeRepository, $accessTokenRepository)); diff --git a/src/Exception/InvalidRequestException.php b/src/Exception/InvalidRequestException.php index 05535203..d4d0c3a1 100644 --- a/src/Exception/InvalidRequestException.php +++ b/src/Exception/InvalidRequestException.php @@ -30,7 +30,7 @@ class InvalidRequestException extends OAuthException * {@inheritdoc} */ - public function __construct($parameter, $redirectUri = null) + public function __construct($parameter, $redirectUri = null, $description = null) { parent::__construct( sprintf( diff --git a/src/Exception/OAuthException.php b/src/Exception/OAuthException.php index 9183a9d2..3fb7840b 100644 --- a/src/Exception/OAuthException.php +++ b/src/Exception/OAuthException.php @@ -11,9 +11,11 @@ namespace League\OAuth2\Server\Exception; -use League\OAuth2\Server\Util\RedirectUri; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; +use League\OAuth2\Server\Utils\RedirectUri; +use Psr\Http\Message\ResponseInterface; +use Zend\Diactoros\Request; +use Zend\Diactoros\Response; +use Zend\Diactoros\ServerRequest; /** * Exception class @@ -37,14 +39,21 @@ class OAuthException extends \Exception */ public $errorType = ''; + /** + * @var string + */ + private $description; + /** * Throw a new exception * - * @param string $msg Exception Message + * @param string $msg Exception Message + * @param string|null $description Description of error */ - public function __construct($msg = 'An error occured') + public function __construct($msg = 'An error occurred', $description = null) { parent::__construct($msg); + $this->description = $description; } /** @@ -81,7 +90,7 @@ class OAuthException extends \Exception public function getHttpHeaders() { $headers = [ - 'Content-type' => 'application/json' + 'Content-type' => 'application/json' ]; switch ($this->httpStatusCode) { case 401: @@ -110,11 +119,11 @@ class OAuthException extends \Exception // @codeCoverageIgnoreStart if ($this->errorType === 'invalid_client') { $authScheme = null; - $request = new Request(); - if ($request->getUser() !== null) { + $request = new ServerRequest(); + if ($request->getServerParams()['PHP_AUTH_USER'] !== null) { $authScheme = 'Basic'; } else { - $authHeader = $request->headers->get('Authorization'); + $authHeader = $request->getHeader('authorization'); if ($authHeader !== null) { if (strpos($authHeader, 'Bearer') === 0) { $authScheme = 'Bearer'; @@ -124,7 +133,7 @@ class OAuthException extends \Exception } } if ($authScheme !== null) { - $headers[] = 'WWW-Authenticate: ' . $authScheme . ' realm=""'; + $headers[] = 'WWW-Authenticate: ' . $authScheme . ' realm="OAuth"'; } } // @codeCoverageIgnoreEnd @@ -133,17 +142,21 @@ class OAuthException extends \Exception /** * Generate a HTTP response - * @return \Symfony\Component\HttpFoundation\Response + * @return ResponseInterface */ public function generateHttpResponse() { + $payload = [ + 'error' => $this->errorType, + 'message' => $this->getMessage() + ]; + + if ($this->description !== null) { + $payload['description'] = $this->description; + } + return new Response( - json_encode( - [ - 'error' => $this->errorType, - 'message' => $this->getMessage() - ] - ), + json_encode($payload), $this->httpStatusCode, $this->getHttpHeaders() ); diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 3734f91a..3cca9373 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -18,6 +18,7 @@ use League\OAuth2\Server\Exception; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use Psr\Http\Message\ServerRequestInterface; /** * Abstract grant class @@ -39,7 +40,7 @@ abstract class AbstractGrant implements GrantTypeInterface protected $respondsWith = 'token'; /** - * @var \Symfony\Component\HttpFoundation\Request + * @var ServerRequestInterface */ protected $request; @@ -64,18 +65,15 @@ abstract class AbstractGrant implements GrantTypeInterface protected $scopeRepository; /** - * @param \League\Event\Emitter $emitter * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository */ public function __construct( - Emitter $emitter, ClientRepositoryInterface $clientRepository, ScopeRepositoryInterface $scopeRepository, AccessTokenRepositoryInterface $accessTokenRepository ) { - $this->emitter = $emitter; $this->clientRepository = $clientRepository; $this->scopeRepository = $scopeRepository; $this->accessTokenRepository = $accessTokenRepository; @@ -98,8 +96,8 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @param string $scopeParamValue A string containing a delimited set of scope identifiers - * @param string $scopeDelimiter The delimiter between the scopes in the value string + * @param string $scopeParamValue A string containing a delimited set of scope identifiers + * @param string $scopeDelimiterString The delimiter between the scopes in the value string * @param ClientEntityInterface $client * @param string $redirectUri * @@ -108,18 +106,16 @@ abstract class AbstractGrant implements GrantTypeInterface */ public function validateScopes( $scopeParamValue, - $scopeDelimiter, + $scopeDelimiterString, ClientEntityInterface $client, $redirectUri = null ) { - $scopesList = explode($scopeDelimiter, trim($scopeParamValue)); - - for ($i = 0; $i < count($scopesList); $i++) { - $scopesList[$i] = trim($scopesList[$i]); - if ($scopesList[$i] === '') { - unset($scopesList[$i]); // Remove any junk scopes + $scopesList = array_filter( + explode($scopeDelimiterString, trim($scopeParamValue)), + function ($scope) { + return !empty($scope); } - } + ); $scopes = []; foreach ($scopesList as $scopeItem) { @@ -138,4 +134,12 @@ abstract class AbstractGrant implements GrantTypeInterface return $scopes; } + + /** + * @param Emitter $emitter + */ + public function setEmitter(Emitter $emitter) + { + $this->emitter = $emitter; + } } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index acd2f381..a7ae36bb 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -222,7 +222,7 @@ class AuthCodeGrant extends AbstractGrant // Get the required params $clientId = $request->request->get('client_id', $request->getUser()); if (is_null($clientId)) { - throw new InvalidRequestException('client_id'); + throw new InvalidRequestException('client_id', ''); } $clientSecret = $request->request->get('client_secret', diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 50be9a1f..a6cd7da9 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -18,7 +18,7 @@ use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Exception; use League\OAuth2\Server\TokenTypes\TokenTypeInterface; use League\OAuth2\Server\Utils\SecureKey; -use Symfony\Component\HttpFoundation\Request; +use Psr\Http\Message\ServerRequestInterface; /** * Client credentials grant class @@ -35,7 +35,7 @@ class ClientCredentialsGrant extends AbstractGrant /** * Return an access token * - * @param \Symfony\Component\HttpFoundation\Request $request + * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\TokenTypes\TokenTypeInterface $tokenType * @param \DateInterval $accessTokenTTL * @param string $scopeDelimiter @@ -45,19 +45,29 @@ class ClientCredentialsGrant extends AbstractGrant * @throws \League\OAuth2\Server\Exception\InvalidRequestException * @throws \League\OAuth2\Server\Exception\InvalidScopeException */ - public function getAccessTokenAsType( - Request $request, + public function respondToRequest( + ServerRequestInterface $request, TokenTypeInterface $tokenType, DateInterval $accessTokenTTL, $scopeDelimiter = ' ' ) { // Get the required params - $clientId = $request->request->get('client_id', $request->getUser()); + $clientId = isset($request->getParsedBody()['client_id']) + ? $request->getParsedBody()['client_id'] // $_POST['client_id'] + : isset($request->getServerParams()['PHP_AUTH_USER']) + ? $request->getServerParams()['PHP_AUTH_USER'] // $_SERVER['PHP_AUTH_USER'] + : null; + if (is_null($clientId)) { throw new Exception\InvalidRequestException('client_id'); } - $clientSecret = $request->request->get('client_secret', $request->getPassword()); + $clientSecret = isset($request->getParsedBody()['client_secret']) + ? $request->getParsedBody()['client_secret'] // $_POST['client_id'] + : isset($request->getServerParams()['PHP_AUTH_PW']) + ? $request->getServerParams()['PHP_AUTH_PW'] // $_SERVER['PHP_AUTH_USER'] + : null; + if (is_null($clientSecret)) { throw new Exception\InvalidRequestException('client_secret'); } @@ -76,14 +86,15 @@ class ClientCredentialsGrant extends AbstractGrant } // Validate any scopes that are in the request - $scopeParam = $request->request->get('scope', ''); + $scopeParam = isset($request->getParsedBody()['scope']) + ? $request->getParsedBody()['scope'] // $_POST['scope'] + : ''; $scopes = $this->validateScopes($scopeParam, $scopeDelimiter, $client); // Generate an access token $accessToken = new AccessTokenEntity(); $accessToken->setIdentifier(SecureKey::generate()); - $expirationDateTime = (new \DateTime())->add($accessTokenTTL); - $accessToken->setExpiryDateTime($expirationDateTime); + $accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL)); $accessToken->setClient($client); $accessToken->setOwner('client', $client->getIdentifier()); @@ -100,4 +111,28 @@ class ClientCredentialsGrant extends AbstractGrant return $tokenType; } + + /** + * The grant type should return true if it is able to respond to this request. + * + * For example most grant types will check that the $_POST['grant_type'] property matches it's identifier property. + * + * Some grants, such as the authorization code grant can respond to multiple requests + * - i.e. a client requesting an authorization code and requesting an access token + * + * @param \Psr\Http\Message\ServerRequestInterface $request + * + * @return boolean + */ + public function canRespondToRequest(ServerRequestInterface $request) + { + if ( + isset($request->getParsedBody()['grant_type']) + && $request->getParsedBody()['grant_type'] === 'client_credentials' + ) { + return true; + } + + return false; + } } diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 739b2a20..c553b093 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -12,8 +12,9 @@ namespace League\OAuth2\Server\Grant; use DateInterval; +use League\Event\Emitter; use League\OAuth2\Server\TokenTypes\TokenTypeInterface; -use Symfony\Component\HttpFoundation\Request; +use Psr\Http\Message\ServerRequestInterface; /** * Grant type interface @@ -37,17 +38,38 @@ interface GrantTypeInterface /** * Return an access token * - * @param \Symfony\Component\HttpFoundation\Request $request + * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\TokenTypes\TokenTypeInterface $tokenType * @param \DateInterval $accessTokenTTL * @param string $scopeDelimiter * * @return \League\OAuth2\Server\TokenTypes\TokenTypeInterface */ - public function getAccessTokenAsType( - Request $request, + public function respondToRequest( + ServerRequestInterface $request, TokenTypeInterface $tokenType, DateInterval $accessTokenTTL, $scopeDelimiter = ' ' ); + + /** + * The grant type should return true if it is able to respond to this request. + * + * For example most grant types will check that the $_POST['grant_type'] property matches it's identifier property. + * + * Some grants, such as the authorization code grant can respond to multiple requests + * - i.e. a client requesting an authorization code and requesting an access token + * + * @param \Psr\Http\Message\ServerRequestInterface $request + * + * @return boolean + */ + public function canRespondToRequest(ServerRequestInterface $request); + + /** + * Set the event emitter + * + * @param \League\Event\Emitter $emitter + */ + public function setEmitter(Emitter $emitter); } diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 1e11bd85..3357ed5d 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -19,7 +19,7 @@ use League\OAuth2\Server\Exception; use League\OAuth2\Server\Util\SecureKey; /** - * Referesh token grant + * Refresh token grant */ class RefreshTokenGrant extends AbstractGrant { diff --git a/src/ResourceServer.php b/src/ResourceServer.php deleted file mode 100644 index ab9ebec4..00000000 --- a/src/ResourceServer.php +++ /dev/null @@ -1,154 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server; - -use League\OAuth2\Server\Entity\AccessTokenEntity; -use League\OAuth2\Server\Exception\AccessDeniedException; -use League\OAuth2\Server\Exception\InvalidRequestException; -use League\OAuth2\Server\Storage\AccessTokenInterface; -use League\OAuth2\Server\Storage\ClientInterface; -use League\OAuth2\Server\Storage\ScopeInterface; -use League\OAuth2\Server\Storage\SessionInterface; -use League\OAuth2\Server\TokenType\Bearer; - -/** - * OAuth 2.0 Resource Server - */ -class ResourceServer extends AbstractServer -{ - /** - * The access token - * - * @var \League\OAuth2\Server\Entity\AccessTokenEntity - */ - protected $accessToken; - - /** - * The query string key which is used by clients to present the access token (default: access_token) - * - * @var string - */ - protected $tokenKey = 'access_token'; - - /** - * Initialise the resource server - * - * @param \League\OAuth2\Server\Storage\SessionInterface $sessionStorage - * @param \League\OAuth2\Server\Storage\AccessTokenInterface $accessTokenStorage - * @param \League\OAuth2\Server\Storage\ClientInterface $clientStorage - * @param \League\OAuth2\Server\Storage\ScopeInterface $scopeStorage - * - * @return self - */ - public function __construct( - SessionInterface $sessionStorage, - AccessTokenInterface $accessTokenStorage, - ClientInterface $clientStorage, - ScopeInterface $scopeStorage - ) { - $this->setSessionStorage($sessionStorage); - $this->setAccessTokenStorage($accessTokenStorage); - $this->setClientStorage($clientStorage); - $this->setScopeStorage($scopeStorage); - - // Set Bearer as the default token type - $this->setTokenType(new Bearer()); - - parent::__construct(); - - return $this; - } - - /** - * Sets the query string key for the access token. - * - * @param string $key The new query string key - * - * @return self - */ - public function setIdKey($key) - { - $this->tokenKey = $key; - - return $this; - } - - /** - * Gets the access token - * - * @return \League\OAuth2\Server\Entity\AccessTokenEntity - */ - public function getAccessToken() - { - return $this->accessToken; - } - - /** - * Checks if the access token is valid or not - * - * @param bool $headerOnly Limit Access Token to Authorization header - * @param \League\OAuth2\Server\Entity\AccessTokenEntity|null $accessToken Access Token - * - * @throws \League\OAuth2\Server\Exception\AccessDeniedException - * @throws \League\OAuth2\Server\Exception\InvalidRequestException - * - * @return bool - */ - public function isValidRequest($headerOnly = true, $accessToken = null) - { - $accessTokenString = ($accessToken !== null) - ? $accessToken - : $this->determineAccessToken($headerOnly); - - // Set the access token - $this->accessToken = $this->getAccessTokenStorage()->get($accessTokenString); - - // Ensure the access token exists - if (!$this->accessToken instanceof AccessTokenEntity) { - throw new AccessDeniedException(); - } - - // Check the access token hasn't expired - // Ensure the auth code hasn't expired - if ($this->accessToken->isExpired() === true) { - throw new AccessDeniedException(); - } - - return true; - } - - /** - * Reads in the access token from the headers - * - * @param bool $headerOnly Limit Access Token to Authorization header - * - * @throws \League\OAuth2\Server\Exception\InvalidRequestException Thrown if there is no access token presented - * - * @return string - */ - public function determineAccessToken($headerOnly = false) - { - if ($this->getRequest()->headers->get('Authorization') !== null) { - $accessToken = $this->getTokenType()->determineAccessTokenInHeader($this->getRequest()); - } elseif ($headerOnly === false) { - $accessToken = ($this->getRequest()->server->get('REQUEST_METHOD') === 'GET') - ? $this->getRequest()->query->get($this->tokenKey) - : $this->getRequest()->request->get($this->tokenKey); - } - - if (empty($accessToken)) { - throw new InvalidRequestException('access token'); - } - - return $accessToken; - } -} diff --git a/src/Server.php b/src/Server.php index 1199bb27..87beb38c 100644 --- a/src/Server.php +++ b/src/Server.php @@ -3,12 +3,24 @@ namespace League\OAuth2\Server; use DateInterval; +use League\Event\EmitterAwareInterface; +use League\Event\EmitterAwareTrait; +use League\OAuth2\Server\Grant\GrantTypeInterface; +//use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; +//use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; +//use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use League\OAuth2\Server\Repositories\RepositoryInterface; +//use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +//use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\TokenTypes\BearerTokenType; use League\OAuth2\Server\TokenTypes\TokenTypeInterface; -use Symfony\Component\HttpFoundation\Request; +use Psr\Http\Message\ServerRequestInterface; +use Zend\Diactoros\ServerRequestFactory; -class Server extends AbstractServer +class Server implements EmitterAwareInterface { + use EmitterAwareTrait; + /** * @var \League\OAuth2\Server\Grant\GrantTypeInterface[] */ @@ -37,16 +49,20 @@ class Server extends AbstractServer /** * @var string */ - protected $scopeDelimiter = ' '; + protected $scopeDelimiterString = ' '; + + /** + * @var RepositoryInterface[] + */ +// protected $repositories = []; /** * New server instance */ - public function __construct() { - $this->defaultTokenType = new BearerTokenType(); - $this->defaultAccessTokenTTL = new DateInterval('PT01H'); // default of 1 hour - - parent::__construct(); + public function __construct() + { + $this->setDefaultTokenType(new BearerTokenType()); + $this->setDefaultAccessTokenTTL(new DateInterval('PT01H')); // default of 1 hour } /** @@ -60,13 +76,13 @@ class Server extends AbstractServer } /** - * Set the delimiter used to separate scopes in a request + * Set the delimiter string used to separate scopes in a request * - * @param string $scopeDelimiter + * @param string $scopeDelimiterString */ - public function setScopeDelimiter($scopeDelimiter) + public function setScopeDelimiterString($scopeDelimiterString) { - $this->scopeDelimiter = $scopeDelimiter; + $this->scopeDelimiterString = $scopeDelimiterString; } /** @@ -80,68 +96,89 @@ class Server extends AbstractServer } /** - * @param string $grantType - * @param TokenTypeInterface $tokenType - * @param DateInterval $accessTokenTTL + * Enable a grant type on the server * - * @throws \Exception + * @param \League\OAuth2\Server\Grant\GrantTypeInterface $grantType + * @param TokenTypeInterface $tokenType + * @param DateInterval $accessTokenTTL */ public function enableGrantType( - $grantType, + GrantTypeInterface $grantType, TokenTypeInterface $tokenType = null, DateInterval $accessTokenTTL = null ) { - if ($this->getContainer()->isInServiceProvider($grantType)) { - $grant = $this->getContainer()->get($grantType); - $grantIdentifier = $grant->getIdentifier(); - $this->enabledGrantTypes[$grantIdentifier] = $grant; - } else { - throw new \Exception('Unregistered grant type'); // @TODO fix - } + $grantType->setEmitter($this->getEmitter()); + $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; // Set grant response type if ($tokenType instanceof TokenTypeInterface) { - $this->grantTypeTokenTypes[$grantIdentifier] = $tokenType; + $this->grantTypeTokenTypes[$grantType->getIdentifier()] = $tokenType; } else { - $this->grantTypeTokenTypes[$grantIdentifier] = $this->defaultTokenType; + $this->grantTypeTokenTypes[$grantType->getIdentifier()] = $this->defaultTokenType; } // Set grant access token TTL if ($accessTokenTTL instanceof DateInterval) { - $this->grantTypeAccessTokenTTL[$grantIdentifier] = $accessTokenTTL; + $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL; } else { - $this->grantTypeAccessTokenTTL[$grantIdentifier] = $this->defaultAccessTokenTTL; + $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $this->defaultAccessTokenTTL; } } /** * Return an access token response * - * @param \Symfony\Component\HttpFoundation\Request $request + * @param \Psr\Http\Message\ServerRequestInterface $request * - * @return TokenTypeInterface - * @throws \Exception + * @return \League\OAuth2\Server\TokenTypes\TokenTypeInterface + * @throws \League\OAuth2\Server\Exception\InvalidGrantException */ - public function getAccessTokenResponse(Request $request = null) + public function respondToRequest(ServerRequestInterface $request = null) { if ($request === null) { - $request = Request::createFromGlobals(); + $request = ServerRequestFactory::fromGlobals(); } - // Run the requested grant type - $grantType = $request->request->get('grant_type', null); - - if ($grantType === null || isset($this->enabledGrantTypes[$grantType]) === false) { - throw new Exception\InvalidGrantException($grantType); + $response = null; + foreach ($this->enabledGrantTypes as $grantType) { + if ($grantType->canRespondToRequest($request)) { + $response = $grantType->respondToRequest( + $request, + $this->grantTypeTokenTypes[$grantType->getIdentifier()], + $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()], + $this->scopeDelimiterString + ); + } } - $tokenType = $this->enabledGrantTypes[$grantType]->getAccessTokenAsType( - $request, - $this->grantTypeTokenTypes[$grantType], - $this->grantTypeAccessTokenTTL[$grantType], - $this->scopeDelimiter - ); + if ($response === null) { + // do something here + } - return $tokenType->generateHttpResponse(); + return $response; } + + /** + * @param \League\OAuth2\Server\Repositories\RepositoryInterface $repository + */ + /*public function addRepository(RepositoryInterface $repository) + { + switch ($repository) { + case ($repository instanceof AccessTokenRepositoryInterface): + $this->repositories[AccessTokenRepositoryInterface::class] = $repository; + break; + case ($repository instanceof ClientRepositoryInterface): + $this->repositories[ClientRepositoryInterface::class] = $repository; + break; + case ($repository instanceof ScopeRepositoryInterface): + $this->repositories[ScopeRepositoryInterface::class] = $repository; + break; + case ($repository instanceof UserRepositoryInterface): + $this->repositories[UserRepositoryInterface::class] = $repository; + break; + case ($repository instanceof AuthCodeRepositoryInterface): + $this->repositories[AuthCodeRepositoryInterface::class] = $repository; + break; + } + }*/ } diff --git a/src/TokenTypes/BearerTokenType.php b/src/TokenTypes/BearerTokenType.php index 2fb932bf..bc22caab 100644 --- a/src/TokenTypes/BearerTokenType.php +++ b/src/TokenTypes/BearerTokenType.php @@ -11,7 +11,8 @@ namespace League\OAuth2\Server\TokenTypes; -use Symfony\Component\HttpFoundation\Request; +use Psr\Http\Message\ServerRequestInterface; +use Zend\Diactoros\Response; class BearerTokenType extends AbstractTokenType { @@ -20,25 +21,36 @@ class BearerTokenType extends AbstractTokenType */ public function generateResponse() { - $return = [ + $values = [ 'access_token' => $this->accessToken->getIdentifier(), 'token_type' => 'Bearer', 'expires_in' => $this->accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp() ]; if (!is_null($this->getParam('refresh_token'))) { - $return['refresh_token'] = $this->getParam('refresh_token'); + $values['refresh_token'] = $this->getParam('refresh_token'); } - return $return; + $response = new Response( + 'php://memory', + 200, + [ + 'pragma' => 'no-cache', + 'cache-control' => 'no-store', + 'content-type' => 'application/json;charset=UTF-8' + ] + ); + $response->getBody()->write(json_encode($values)); + + return $response; } /** * {@inheritdoc} */ - public function determineAccessTokenInHeader(Request $request) + public function determineAccessTokenInHeader(ServerRequestInterface $request) { - $header = $request->headers->get('Authorization'); + $header = $request->getHeader('authorization'); $accessToken = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header)); // ^(?:\s+)?Bearer\s([a-zA-Z0-9-._~+/=]*) diff --git a/src/TokenTypes/TokenTypeInterface.php b/src/TokenTypes/TokenTypeInterface.php index 04fd0610..3946eeb9 100644 --- a/src/TokenTypes/TokenTypeInterface.php +++ b/src/TokenTypes/TokenTypeInterface.php @@ -12,14 +12,15 @@ namespace League\OAuth2\Server\TokenTypes; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use Symfony\Component\HttpFoundation\Request; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; interface TokenTypeInterface { /** * Generate a response * - * @return array + * @return ResponseInterface */ public function generateResponse(); @@ -48,14 +49,14 @@ interface TokenTypeInterface /** * Determine the access token in the authorization header * - * @param \Symfony\Component\HttpFoundation\Request $request + * @param ServerRequestInterface $request * * @return string */ - public function determineAccessTokenInHeader(Request $request); + public function determineAccessTokenInHeader(ServerRequestInterface $request); /** - * @return \Symfony\Component\HttpFoundation\Response + * @return ResponseInterface */ public function generateHttpResponse(); } From 41c7a6e73140559ba74485f4abdff447de1ec040 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 13 Nov 2015 17:37:28 +0000 Subject: [PATCH 067/444] Removed old exceptions --- src/Exception/InvalidClientException.php | 36 ---- src/Exception/InvalidGrantException.php | 42 ----- src/Exception/InvalidRequestException.php | 44 ----- src/Exception/InvalidScopeException.php | 44 ----- src/Exception/OAuthException.php | 164 ------------------ .../UnsupportedGrantTypeException.php | 42 ----- src/TokenTypes/TokenTypeInterface.php | 62 ------- 7 files changed, 434 deletions(-) delete mode 100644 src/Exception/InvalidClientException.php delete mode 100644 src/Exception/InvalidGrantException.php delete mode 100644 src/Exception/InvalidRequestException.php delete mode 100644 src/Exception/InvalidScopeException.php delete mode 100644 src/Exception/OAuthException.php delete mode 100644 src/Exception/UnsupportedGrantTypeException.php delete mode 100644 src/TokenTypes/TokenTypeInterface.php diff --git a/src/Exception/InvalidClientException.php b/src/Exception/InvalidClientException.php deleted file mode 100644 index ba01d277..00000000 --- a/src/Exception/InvalidClientException.php +++ /dev/null @@ -1,36 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Exception; - -/** - * Exception class - */ -class InvalidClientException extends OAuthException -{ - /** - * {@inheritdoc} - */ - public $httpStatusCode = 401; - - /** - * {@inheritdoc} - */ - public $errorType = 'invalid_client'; - - /** - * {@inheritdoc} - */ - public function __construct() - { - parent::__construct('Client authentication failed.'); - } -} diff --git a/src/Exception/InvalidGrantException.php b/src/Exception/InvalidGrantException.php deleted file mode 100644 index 051330e9..00000000 --- a/src/Exception/InvalidGrantException.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Exception; - -/** - * Exception class - */ -class InvalidGrantException extends OAuthException -{ - /** - * {@inheritdoc} - */ - public $httpStatusCode = 400; - - /** - * {@inheritdoc} - */ - public $errorType = 'invalid_grant'; - - /** - * {@inheritdoc} - */ - - public function __construct($parameter) - { - parent::__construct( - sprintf( - '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. Check the "%s" parameter.', - $parameter - ) - ); - } -} diff --git a/src/Exception/InvalidRequestException.php b/src/Exception/InvalidRequestException.php deleted file mode 100644 index d4d0c3a1..00000000 --- a/src/Exception/InvalidRequestException.php +++ /dev/null @@ -1,44 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Exception; - -/** - * Exception class - */ -class InvalidRequestException extends OAuthException -{ - /** - * {@inheritdoc} - */ - public $httpStatusCode = 400; - - /** - * {@inheritdoc} - */ - public $errorType = 'invalid_request'; - - /** - * {@inheritdoc} - */ - - public function __construct($parameter, $redirectUri = null, $description = null) - { - parent::__construct( - sprintf( - 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "%s" parameter.', - $parameter - ) - ); - - $this->redirectUri = $redirectUri; - } -} diff --git a/src/Exception/InvalidScopeException.php b/src/Exception/InvalidScopeException.php deleted file mode 100644 index f0574f8d..00000000 --- a/src/Exception/InvalidScopeException.php +++ /dev/null @@ -1,44 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Exception; - -/** - * Exception class - */ -class InvalidScopeException extends OAuthException -{ - /** - * {@inheritdoc} - */ - public $httpStatusCode = 400; - - /** - * {@inheritdoc} - */ - public $errorType = 'invalid_scope'; - - /** - * {@inheritdoc} - */ - - public function __construct($parameter, $redirectUri = null) - { - parent::__construct( - sprintf( - 'The requested scope is invalid, unknown, or malformed. Check the "%s" scope.', - $parameter - ) - ); - - $this->redirectUri = $redirectUri; - } -} diff --git a/src/Exception/OAuthException.php b/src/Exception/OAuthException.php deleted file mode 100644 index 3fb7840b..00000000 --- a/src/Exception/OAuthException.php +++ /dev/null @@ -1,164 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Exception; - -use League\OAuth2\Server\Utils\RedirectUri; -use Psr\Http\Message\ResponseInterface; -use Zend\Diactoros\Request; -use Zend\Diactoros\Response; -use Zend\Diactoros\ServerRequest; - -/** - * Exception class - */ -class OAuthException extends \Exception -{ - /** - * The HTTP status code for this exception that should be sent in the response - */ - public $httpStatusCode = 400; - - /** - * Redirect URI if the server should redirect back to the client - * - * @var string|null - */ - public $redirectUri = null; - - /** - * The exception type - */ - public $errorType = ''; - - /** - * @var string - */ - private $description; - - /** - * Throw a new exception - * - * @param string $msg Exception Message - * @param string|null $description Description of error - */ - public function __construct($msg = 'An error occurred', $description = null) - { - parent::__construct($msg); - $this->description = $description; - } - - /** - * Should the server redirect back to the client? - * - * @return bool - */ - public function shouldRedirect() - { - return is_null($this->redirectUri) ? false : true; - } - - /** - * Return redirect URI if set - * - * @return string|null - */ - public function getRedirectUri() - { - return RedirectUri::make( - $this->redirectUri, - [ - 'error' => $this->errorType, - 'message' => $this->getMessage(), - ] - ); - } - - /** - * 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' - ]; - switch ($this->httpStatusCode) { - case 401: - $headers[] = 'HTTP/1.1 401 Unauthorized'; - break; - case 500: - $headers[] = 'HTTP/1.1 500 Internal Server Error'; - break; - case 501: - $headers[] = 'HTTP/1.1 501 Not Implemented'; - break; - case 400: - default: - $headers[] = 'HTTP/1.1 400 Bad Request'; - break; - } - - // Add "WWW-Authenticate" header - // - // RFC 6749, section 5.2.: - // "If the client attempted to authenticate via the 'Authorization' - // request header field, the authorization server MUST - // respond with an HTTP 401 (Unauthorized) status code and - // include the "WWW-Authenticate" response header field - // matching the authentication scheme used by the client. - // @codeCoverageIgnoreStart - if ($this->errorType === 'invalid_client') { - $authScheme = null; - $request = new ServerRequest(); - if ($request->getServerParams()['PHP_AUTH_USER'] !== null) { - $authScheme = 'Basic'; - } else { - $authHeader = $request->getHeader('authorization'); - if ($authHeader !== null) { - if (strpos($authHeader, 'Bearer') === 0) { - $authScheme = 'Bearer'; - } elseif (strpos($authHeader, 'Basic') === 0) { - $authScheme = 'Basic'; - } - } - } - if ($authScheme !== null) { - $headers[] = 'WWW-Authenticate: ' . $authScheme . ' realm="OAuth"'; - } - } - // @codeCoverageIgnoreEnd - return $headers; - } - - /** - * Generate a HTTP response - * @return ResponseInterface - */ - public function generateHttpResponse() - { - $payload = [ - 'error' => $this->errorType, - 'message' => $this->getMessage() - ]; - - if ($this->description !== null) { - $payload['description'] = $this->description; - } - - return new Response( - json_encode($payload), - $this->httpStatusCode, - $this->getHttpHeaders() - ); - } -} diff --git a/src/Exception/UnsupportedGrantTypeException.php b/src/Exception/UnsupportedGrantTypeException.php deleted file mode 100644 index 5a4f1d90..00000000 --- a/src/Exception/UnsupportedGrantTypeException.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Exception; - -/** - * Exception class - */ -class UnsupportedGrantTypeException extends OAuthException -{ - /** - * {@inheritdoc} - */ - public $httpStatusCode = 400; - - /** - * {@inheritdoc} - */ - public $errorType = 'unsupported_grant_type'; - - /** - * {@inheritdoc} - */ - - public function __construct($parameter) - { - parent::__construct( - sprintf( - 'The authorization grant type "%s" is not supported by the authorization server.', - $parameter - ) - ); - } -} diff --git a/src/TokenTypes/TokenTypeInterface.php b/src/TokenTypes/TokenTypeInterface.php deleted file mode 100644 index 3946eeb9..00000000 --- a/src/TokenTypes/TokenTypeInterface.php +++ /dev/null @@ -1,62 +0,0 @@ - - * @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\Entities\Interfaces\AccessTokenEntityInterface; -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\ServerRequestInterface; - -interface TokenTypeInterface -{ - /** - * Generate a response - * - * @return ResponseInterface - */ - public function generateResponse(); - - /** - * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken - */ - public function setAccessToken(AccessTokenEntityInterface $accessToken); - - /** - * Set a key/value response pair - * - * @param string $key - * @param mixed $value - */ - public function setParam($key, $value); - - /** - * Get a key from the response array - * - * @param string $key - * - * @return mixed - */ - public function getParam($key); - - /** - * Determine the access token in the authorization header - * - * @param ServerRequestInterface $request - * - * @return string - */ - public function determineAccessTokenInHeader(ServerRequestInterface $request); - - /** - * @return ResponseInterface - */ - public function generateHttpResponse(); -} From b479cb7912030a50bb066c9e8cfe9e9b88eb7886 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 13 Nov 2015 17:37:37 +0000 Subject: [PATCH 068/444] New OAuthServerException class --- src/Exception/OAuthServerException.php | 247 +++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 src/Exception/OAuthServerException.php diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php new file mode 100644 index 00000000..c0ea5ec1 --- /dev/null +++ b/src/Exception/OAuthServerException.php @@ -0,0 +1,247 @@ +httpStatusCode = $httpStatusCode; + $this->errorType = $errorType; + $this->hint = $hint; + $this->redirectUri = $redirectUri; + } + + /** + * @return int + */ + public function getHttpStatusCode() + { + return $this->httpStatusCode; + } + + + /** + * @return string + */ + public function getErrorType() + { + return $this->errorType; + } + + /** + * 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' + ]; + + // Add "WWW-Authenticate" header + // + // RFC 6749, section 5.2.: + // "If the client attempted to authenticate via the 'Authorization' + // request header field, the authorization server MUST + // respond with an HTTP 401 (Unauthorized) status code and + // include the "WWW-Authenticate" response header field + // matching the authentication scheme used by the client. + // @codeCoverageIgnoreStart + if ($this->errorType === 'invalid_client') { + $authScheme = null; + $request = new ServerRequest(); + if ($request->getServerParams()['PHP_AUTH_USER'] !== null) { + $authScheme = 'Basic'; + } else { + $authHeader = $request->getHeader('authorization'); + if ($authHeader !== null) { + if (strpos($authHeader, 'Bearer') === 0) { + $authScheme = 'Bearer'; + } elseif (strpos($authHeader, 'Basic') === 0) { + $authScheme = 'Basic'; + } + } + } + if ($authScheme !== null) { + $headers[] = 'WWW-Authenticate: ' . $authScheme . ' realm="OAuth"'; + } + } + + // @codeCoverageIgnoreEnd + return $headers; + } + + /** + * Generate a HTTP response + * @return ResponseInterface + */ + public function generateHttpResponse() + { + $headers = $this->getHttpHeaders(); + + $payload = [ + 'error' => $this->errorType, + 'message' => $this->getMessage() + ]; + + if ($this->hint !== null) { + $payload['hint'] = $this->hint; + } + + if ($this->redirectUri !== null) { + $headers['Location'] = RedirectUri::make($this->redirectUri, $payload); + } + + $response = new Response( + 'php://memory', + $this->getHttpStatusCode(), + $headers + ); + $response->getBody()->write(json_encode($payload)); + + return $response; + } + + /** + * Invalid grant type error + * + * @param null|string $localizedError + * @param null|string $localizedHint + * + * @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; + + return new static($errorMessage, 'invalid_grant', 400, $hint); + } + + /** + * Unsupported grant type error + * + * @param null|string $localizedError + * @param null|string $localizedHint + * + * @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; + + return new static($errorMessage, 'unsupported_grant_type', 400, $hint); + } + + /** + * Invalid request error + * + * @param string $parameter The invalid parameter + * @param null|string $localizedError + * @param null|string $localizedHint + * + * @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) + { + $errorMessage = (is_null($localizedError)) + ? 'Client authentication failed' + : $localizedError; + + return new static($errorMessage, 'invalid_client', 401); + } + + /** + * 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 + * + * @return static + */ + public static function invalidScope($scope, $localizedError = null, $localizedHint = null, $redirectUri = null) + { + $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); + + return new static($errorMessage, 'invalid_scope', 400, $hint, $redirectUri); + } +} From 0a602cb022041243371c1b64f4390f9eb44e6896 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 13 Nov 2015 17:37:53 +0000 Subject: [PATCH 069/444] We don't support PHP 5.4 anymore --- .travis.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 34e237af..9ab34bb5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,17 +7,10 @@ cache: - vendor php: - - 5.4 - 5.5 - 5.6 - 7.0 - hhvm - -matrix: - allow_failures: - - php: 7.0 - - php: hhvm - fast_finish: true install: - travis_retry composer install --no-interaction --prefer-source From 1442842da9e62437ad31cb7fa78ad5ade5442b86 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 13 Nov 2015 17:38:23 +0000 Subject: [PATCH 070/444] TokenType -> ResponseType --- .../AbstractResponseType.php} | 25 ++------- .../BearerTokenResponse.php} | 6 +- .../JsonWebTokenType.php | 0 src/{TokenTypes => ResponseTypes}/MAC.php | 0 src/ResponseTypes/ResponseTypeInterface.php | 55 +++++++++++++++++++ 5 files changed, 62 insertions(+), 24 deletions(-) rename src/{TokenTypes/AbstractTokenType.php => ResponseTypes/AbstractResponseType.php} (61%) rename src/{TokenTypes/BearerTokenType.php => ResponseTypes/BearerTokenResponse.php} (91%) rename src/{TokenTypes => ResponseTypes}/JsonWebTokenType.php (100%) rename src/{TokenTypes => ResponseTypes}/MAC.php (100%) create mode 100644 src/ResponseTypes/ResponseTypeInterface.php diff --git a/src/TokenTypes/AbstractTokenType.php b/src/ResponseTypes/AbstractResponseType.php similarity index 61% rename from src/TokenTypes/AbstractTokenType.php rename to src/ResponseTypes/AbstractResponseType.php index 47900ca8..ed85c1c4 100644 --- a/src/TokenTypes/AbstractTokenType.php +++ b/src/ResponseTypes/AbstractResponseType.php @@ -1,6 +1,6 @@ @@ -9,15 +9,14 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\TokenTypes; +namespace League\OAuth2\Server\ResponseTypes; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use Symfony\Component\HttpFoundation\Response; -abstract class AbstractTokenType implements TokenTypeInterface +abstract class AbstractResponseType implements ResponseTypeInterface { /** - * Response array + * Response array for JSON serialization * * @var array */ @@ -51,20 +50,4 @@ abstract class AbstractTokenType implements TokenTypeInterface { $this->accessToken = $accessToken; } - - /** - * @return \Symfony\Component\HttpFoundation\Response - */ - public function generateHttpResponse() - { - return new Response( - json_encode($this->generateResponse()), - 200, - [ - 'Content-type' => 'application/json', - 'Cache-Control' => 'no-store', - 'Pragma' => 'no-cache' - ] - ); - } } diff --git a/src/TokenTypes/BearerTokenType.php b/src/ResponseTypes/BearerTokenResponse.php similarity index 91% rename from src/TokenTypes/BearerTokenType.php rename to src/ResponseTypes/BearerTokenResponse.php index bc22caab..3ee5671f 100644 --- a/src/TokenTypes/BearerTokenType.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -9,17 +9,17 @@ * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\TokenTypes; +namespace League\OAuth2\Server\ResponseTypes; use Psr\Http\Message\ServerRequestInterface; use Zend\Diactoros\Response; -class BearerTokenType extends AbstractTokenType +class BearerTokenResponse extends AbstractResponseType { /** * {@inheritdoc} */ - public function generateResponse() + public function generateHttpResponse() { $values = [ 'access_token' => $this->accessToken->getIdentifier(), diff --git a/src/TokenTypes/JsonWebTokenType.php b/src/ResponseTypes/JsonWebTokenType.php similarity index 100% rename from src/TokenTypes/JsonWebTokenType.php rename to src/ResponseTypes/JsonWebTokenType.php diff --git a/src/TokenTypes/MAC.php b/src/ResponseTypes/MAC.php similarity index 100% rename from src/TokenTypes/MAC.php rename to src/ResponseTypes/MAC.php diff --git a/src/ResponseTypes/ResponseTypeInterface.php b/src/ResponseTypes/ResponseTypeInterface.php new file mode 100644 index 00000000..039cf342 --- /dev/null +++ b/src/ResponseTypes/ResponseTypeInterface.php @@ -0,0 +1,55 @@ + + * @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; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; + +interface ResponseTypeInterface +{ + /** + * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken + */ + public function setAccessToken(AccessTokenEntityInterface $accessToken); + + /** + * Set a key/value response pair + * + * @param string $key + * @param mixed $value + */ + public function setParam($key, $value); + + /** + * Get a key from the response array + * + * @param string $key + * + * @return mixed + */ + public function getParam($key); + + /** + * Determine the access token in the authorization header + * + * @param ServerRequestInterface $request + * + * @return string + */ + public function determineAccessTokenInHeader(ServerRequestInterface $request); + + /** + * @return ResponseInterface + */ + public function generateHttpResponse(); +} From 03e4ac7ea69e6a3941f7b79d77bde475d37fd70f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 13 Nov 2015 17:38:48 +0000 Subject: [PATCH 071/444] Removed service providers --- .../ClientCredentialsGrantProvider.php | 29 --------------- .../PasswordGrantProvider.php | 37 ------------------- 2 files changed, 66 deletions(-) delete mode 100644 src/ServiceProviders/ClientCredentialsGrantProvider.php delete mode 100644 src/ServiceProviders/PasswordGrantProvider.php diff --git a/src/ServiceProviders/ClientCredentialsGrantProvider.php b/src/ServiceProviders/ClientCredentialsGrantProvider.php deleted file mode 100644 index c56b0baf..00000000 --- a/src/ServiceProviders/ClientCredentialsGrantProvider.php +++ /dev/null @@ -1,29 +0,0 @@ -getContainer(); - - $container->add('ClientCredentialsGrant', function () use ($container) { - $grant = new ClientCredentialsGrant( - $container->get('emitter'), - $container->get('ClientRepository'), - $container->get('ScopeRepository'), - $container->get('AccessTokenRepository') - ); - return $grant; - }); - } -} diff --git a/src/ServiceProviders/PasswordGrantProvider.php b/src/ServiceProviders/PasswordGrantProvider.php deleted file mode 100644 index 540c73b3..00000000 --- a/src/ServiceProviders/PasswordGrantProvider.php +++ /dev/null @@ -1,37 +0,0 @@ -getContainer(); - - $container->add('PasswordGrant', function () use ($container) { - - $refreshTokenRepository = null; - if ($container->isRegistered('RefreshTokenRepository')) { - $refreshTokenRepository = $container->get('RefreshTokenRepository'); - } - - $grant = new PasswordGrant( - $container->get('emitter'), - $container->get('ClientRepository'), - $container->get('ScopeRepository'), - $container->get('AccessTokenRepository'), - $container->get('UserRepository'), - $refreshTokenRepository - ); - return $grant; - }); - } -} From da8efa20cde2bc19bc139df66078ddb13d2e8ab3 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 13 Nov 2015 17:39:07 +0000 Subject: [PATCH 072/444] Updated repository method names to be more explicit --- .../AccessTokenRepositoryInterface.php | 17 ++++++++++------- .../AuthCodeRepositoryInterface.php | 11 +++++------ src/Repositories/ClientRepositoryInterface.php | 2 +- src/Repositories/MacTokenInterface.php | 8 +++++--- .../RefreshTokenRepositoryInterface.php | 18 +++++++++--------- src/Repositories/ScopeRepositoryInterface.php | 8 ++++---- src/Repositories/UserRepositoryInterface.php | 11 ++++++----- 7 files changed, 40 insertions(+), 35 deletions(-) diff --git a/src/Repositories/AccessTokenRepositoryInterface.php b/src/Repositories/AccessTokenRepositoryInterface.php index 41e3011c..13d0c5da 100644 --- a/src/Repositories/AccessTokenRepositoryInterface.php +++ b/src/Repositories/AccessTokenRepositoryInterface.php @@ -22,11 +22,11 @@ interface AccessTokenRepositoryInterface extends RepositoryInterface /** * Get an instance of Entity\AccessTokenEntity * - * @param string $tokenIdentifier The access token identifier + * @param string $token The access token identifier * * @return \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface */ - public function get($tokenIdentifier); + public function getAccessTokenEntityByTokenString($token); /** * Get the scopes for an access token @@ -35,14 +35,14 @@ interface AccessTokenRepositoryInterface extends RepositoryInterface * * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] */ - public function getScopes(AccessTokenEntityInterface $token); + public function getScopeEntitiesAssociatedWithAccessToken(AccessTokenEntityInterface $token); /** - * Creates a new access token + * Persists a new access token to storage * * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessTokenEntity */ - public function create(AccessTokenEntityInterface $accessTokenEntity); + public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity); /** * Associate a scope with an access token @@ -50,12 +50,15 @@ interface AccessTokenRepositoryInterface extends RepositoryInterface * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessTokenEntityInterface * @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface $scope */ - public function associateScope(AccessTokenEntityInterface $accessTokenEntityInterface, ScopeEntityInterface $scope); + public function associateScopeWithAccessToken( + AccessTokenEntityInterface $accessTokenEntityInterface, + ScopeEntityInterface $scope + ); /** * Delete an access token * * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken */ - public function delete(AccessTokenEntityInterface $accessToken); + public function deleteAccessToken(AccessTokenEntityInterface $accessToken); } diff --git a/src/Repositories/AuthCodeRepositoryInterface.php b/src/Repositories/AuthCodeRepositoryInterface.php index 734f5305..85852ef3 100644 --- a/src/Repositories/AuthCodeRepositoryInterface.php +++ b/src/Repositories/AuthCodeRepositoryInterface.php @@ -25,24 +25,23 @@ interface AuthCodeRepositoryInterface extends RepositoryInterface * * @return \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface */ - public function get($code); + public function getAuthCodeEntityByCodeString($code); /** - * Create an auth code. + * Persist a new authorization code * - * @param string $token The token ID + * @param string $code The authorization code string * @param integer $expireTime Token expire time - * @param integer $sessionId Session identifier * @param string $redirectUri Client redirect uri * * @return void */ - public function create($token, $expireTime, $sessionId, $redirectUri); + public function persistNewAuthCode($code, $expireTime, $redirectUri); /** * Delete an access token * * @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $token The access token to delete */ - public function delete(AuthCodeEntityInterface $token); + public function deleteAuthCodeEntity(AuthCodeEntityInterface $token); } diff --git a/src/Repositories/ClientRepositoryInterface.php b/src/Repositories/ClientRepositoryInterface.php index b1f16ad4..b9b9aa3a 100644 --- a/src/Repositories/ClientRepositoryInterface.php +++ b/src/Repositories/ClientRepositoryInterface.php @@ -26,5 +26,5 @@ interface ClientRepositoryInterface extends RepositoryInterface * * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface */ - public function get($clientIdentifier, $clientSecret = null, $redirectUri = null, $grantType = null); + public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null, $redirectUri = null); } diff --git a/src/Repositories/MacTokenInterface.php b/src/Repositories/MacTokenInterface.php index ed5a0633..4b84b147 100644 --- a/src/Repositories/MacTokenInterface.php +++ b/src/Repositories/MacTokenInterface.php @@ -11,11 +11,13 @@ namespace League\OAuth2\Server\Storage; +use League\OAuth2\Server\Repositories\RepositoryInterface; + /** * MacTokenInterface */ -interface MacTokenInterface extends StorageInterface +interface MacTokenInterface extends RepositoryInterface { /** * Create a MAC key linked to an access token @@ -23,12 +25,12 @@ interface MacTokenInterface extends StorageInterface * @param string $accessToken * @return void */ - public function create($macKey, $accessToken); + public function persistMacTokenEntity($macKey, $accessToken); /** * Get a MAC key by access token * @param string $accessToken * @return string */ - public function getByAccessToken($accessToken); + public function getMacKeyByAccessTokenString($accessToken); } diff --git a/src/Repositories/RefreshTokenRepositoryInterface.php b/src/Repositories/RefreshTokenRepositoryInterface.php index 98c4631e..bf3e2c8e 100644 --- a/src/Repositories/RefreshTokenRepositoryInterface.php +++ b/src/Repositories/RefreshTokenRepositoryInterface.php @@ -11,6 +11,8 @@ namespace League\OAuth2\Server\Repositories; +use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; + /** * Refresh token interface */ @@ -19,11 +21,11 @@ interface RefreshTokenRepositoryInterface extends RepositoryInterface /** * Return a new instance of \League\OAuth2\Server\Entity\RefreshTokenEntity * - * @param string $token + * @param string $token Refresh token string * - * @return \League\OAuth2\Server\Entity\RefreshTokenEntity + * @return \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface */ - public function get($token); + public function getRefreshTokenEntityByTokenString($token); /** * Create a new refresh token_name @@ -32,16 +34,14 @@ interface RefreshTokenRepositoryInterface extends RepositoryInterface * @param integer $expireTime * @param string $accessToken * - * @return \League\OAuth2\Server\Entity\RefreshTokenEntity + * @return \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface */ - public function create($token, $expireTime, $accessToken); + public function persistNewRefreshTokenEntity($token, $expireTime, $accessToken); /** * Delete the refresh token * - * @param \League\OAuth2\Server\Entity\RefreshTokenEntity $token - * - * @return void + * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $token */ - public function delete(RefreshTokenEntity $token); + public function deleteRefreshTokenEntity(RefreshTokenEntityInterface $token); } diff --git a/src/Repositories/ScopeRepositoryInterface.php b/src/Repositories/ScopeRepositoryInterface.php index 20bf2590..276ce264 100644 --- a/src/Repositories/ScopeRepositoryInterface.php +++ b/src/Repositories/ScopeRepositoryInterface.php @@ -19,11 +19,11 @@ interface ScopeRepositoryInterface extends RepositoryInterface /** * Return information about a scope * - * @param string $scopeIdentifier The scope identifier - * @param string $grantType The grant type used in the request (default = "null") - * @param string $clientId The client sending the request (default = "null") + * @param string $identifier The scope identifier + * @param string $grantType The grant type used in the request + * @param string $clientId The client sending the request * * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface */ - public function get($scopeIdentifier, $grantType = null, $clientId = null); + public function getScopeEntityByIdentifier($identifier, $grantType, $clientId = null); } diff --git a/src/Repositories/UserRepositoryInterface.php b/src/Repositories/UserRepositoryInterface.php index 818eb135..5767a5ed 100644 --- a/src/Repositories/UserRepositoryInterface.php +++ b/src/Repositories/UserRepositoryInterface.php @@ -1,15 +1,16 @@ Date: Fri, 13 Nov 2015 17:40:22 +0000 Subject: [PATCH 073/444] Updated examples composer --- examples/composer.json | 28 +- examples/composer.lock | 642 ++++++++++++----------------------------- 2 files changed, 202 insertions(+), 468 deletions(-) diff --git a/examples/composer.json b/examples/composer.json index 6b017bce..9c745658 100644 --- a/examples/composer.json +++ b/examples/composer.json @@ -1,13 +1,17 @@ { - "name": "", - "require": { - "alexbilbie/proton": "~1.4", - "ircmaxell/password-compat": "~1.0" - }, - "autoload": { - "psr-4": { - "League\\OAuth2\\Server\\": "../src/", - "OAuth2ServerExamples\\": "src/" - } - } -} \ No newline at end of file + "repositories": [ + { + "type": "path", + "url": ".." + } + ], + "require": { + "slim/slim": "3.0.0-RC2", + "league/oauth2-server": "dev-v5-one" + }, + "autoload": { + "psr-4": { + "OAuth2ServerExamples\\": "src/" + } + } +} diff --git a/examples/composer.lock b/examples/composer.lock index 8570127f..d2326f41 100644 --- a/examples/composer.lock +++ b/examples/composer.lock @@ -4,166 +4,35 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "ad90034834be06a42fc0b780af9a9425", - "content-hash": "caf5b7d7e9c81d118a89ce3b7a38b6ad", + "hash": "bf607d2626a69ff12f1099d3853c138b", + "content-hash": "38198bbba51d99684b5d1b50e08b3019", "packages": [ { - "name": "alexbilbie/proton", - "version": "1.4.1", + "name": "container-interop/container-interop", + "version": "1.1.0", "source": { "type": "git", - "url": "https://github.com/alexbilbie/Proton.git", - "reference": "007dd09af084167e834a6bb80f3777c6faabbe22" + "url": "https://github.com/container-interop/container-interop.git", + "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/alexbilbie/Proton/zipball/007dd09af084167e834a6bb80f3777c6faabbe22", - "reference": "007dd09af084167e834a6bb80f3777c6faabbe22", + "url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e", + "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e", "shasum": "" }, - "require": { - "league/container": "~1.0", - "league/event": "~2.1", - "league/route": "~1.0", - "monolog/monolog": "~1.12", - "php": ">=5.4.0", - "symfony/http-kernel": "~2.5" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.5-dev" - } - }, "autoload": { "psr-4": { - "Proton\\": "src/" + "Interop\\Container\\": "src/Interop/Container/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Alex Bilbie", - "email": "hello@alexbilbie.com" - } - ], - "description": "Micro PHP framework", - "homepage": "https://github.com/alexbilbie/proton", - "keywords": [ - "HttpKernelInterface", - "StackPHP", - "framework", - "micro", - "middleware", - "proton" - ], - "time": "2015-03-26 17:35:31" - }, - { - "name": "ircmaxell/password-compat", - "version": "v1.0.4", - "source": { - "type": "git", - "url": "https://github.com/ircmaxell/password_compat.git", - "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ircmaxell/password_compat/zipball/5c5cde8822a69545767f7c7f3058cb15ff84614c", - "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c", - "shasum": "" - }, - "require-dev": { - "phpunit/phpunit": "4.*" - }, - "type": "library", - "autoload": { - "files": [ - "lib/password.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Anthony Ferrara", - "email": "ircmaxell@php.net", - "homepage": "http://blog.ircmaxell.com" - } - ], - "description": "A compatibility library for the proposed simplified password hashing algorithm: https://wiki.php.net/rfc/password_hash", - "homepage": "https://github.com/ircmaxell/password_compat", - "keywords": [ - "hashing", - "password" - ], - "time": "2014-11-20 16:49:30" - }, - { - "name": "league/container", - "version": "1.3.2", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/container.git", - "reference": "7e6c17fe48f76f3b97aeca70dc29c3f3c7c88d15" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/container/zipball/7e6c17fe48f76f3b97aeca70dc29c3f3c7c88d15", - "reference": "7e6c17fe48f76f3b97aeca70dc29c3f3c7c88d15", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "replace": { - "orno/di": "~2.0" - }, - "require-dev": { - "phpunit/phpunit": "4.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev", - "dev-1.x": "1.3-dev" - } - }, - "autoload": { - "psr-4": { - "League\\Container\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Phil Bennett", - "email": "philipobenito@gmail.com", - "homepage": "http://philipobenito.github.io", - "role": "Developer" - } - ], - "description": "A fast and intuitive dependency injection container.", - "homepage": "https://github.com/thephpleague/container", - "keywords": [ - "container", - "dependency", - "di", - "injection", - "league" - ], - "time": "2015-04-05 17:14:48" + "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", + "time": "2014-12-30 15:22:37" }, { "name": "league/event", @@ -216,138 +85,69 @@ "time": "2015-05-21 12:24:47" }, { - "name": "league/route", - "version": "1.2.3", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/route.git", - "reference": "079e87a4653b43e2cba47b9e0563179c1c49fcf8" - }, + "name": "league/oauth2-server", + "version": "dev-v5-one", "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/route/zipball/079e87a4653b43e2cba47b9e0563179c1c49fcf8", - "reference": "079e87a4653b43e2cba47b9e0563179c1c49fcf8", - "shasum": "" + "type": "path", + "url": "../", + "reference": "82413513e8002dc197a2fd9f13059eb88cd78ac1", + "shasum": null }, "require": { - "league/container": "~1.0", - "nikic/fast-route": "~0.3", - "php": ">=5.4.0", - "symfony/http-foundation": "~2.6" + "league/event": "~2.1", + "php": ">=5.5.9", + "zendframework/zend-diactoros": "~1.1" }, "replace": { - "orno/http": "~1.0", - "orno/route": "~1.0" + "league/oauth2server": "*", + "lncd/oauth2": "*" }, "require-dev": { - "phpunit/phpunit": "4.*" + "codeception/codeception": "~2.0", + "flow/jsonpath": "0.2.*", + "mockery/mockery": "0.9.*", + "phpunit/phpunit": "4.8.*" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, "autoload": { "psr-4": { - "League\\Route\\": "src" + "League\\OAuth2\\Server\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "LeagueTests\\": "tests/unit/" } }, - "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { - "name": "Phil Bennett", - "email": "philipobenito@gmail.com", - "homepage": "http://philipobenito.github.io", + "name": "Alex Bilbie", + "email": "hello@alexbilbie.com", + "homepage": "http://www.alexbilbie.com", "role": "Developer" } ], - "description": "A fast routing and dispatch package built on top of FastRoute.", - "homepage": "https://github.com/thephpleague/route", + "description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.", + "homepage": "http://oauth2.thephpleague.com/", "keywords": [ - "league", - "route" - ], - "time": "2015-09-11 07:40:31" - }, - { - "name": "monolog/monolog", - "version": "1.17.1", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/monolog.git", - "reference": "0524c87587ab85bc4c2d6f5b41253ccb930a5422" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/0524c87587ab85bc4c2d6f5b41253ccb930a5422", - "reference": "0524c87587ab85bc4c2d6f5b41253ccb930a5422", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "psr/log": "~1.0" - }, - "provide": { - "psr/log-implementation": "1.0.0" - }, - "require-dev": { - "aws/aws-sdk-php": "^2.4.9", - "doctrine/couchdb": "~1.0@dev", - "graylog2/gelf-php": "~1.0", - "php-console/php-console": "^3.1.3", - "phpunit/phpunit": "~4.5", - "phpunit/phpunit-mock-objects": "2.3.0", - "raven/raven": "~0.11", - "ruflin/elastica": ">=0.90 <3.0", - "swiftmailer/swiftmailer": "~5.3", - "videlalvaro/php-amqplib": "~2.4" - }, - "suggest": { - "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", - "doctrine/couchdb": "Allow sending log messages to a CouchDB server", - "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-mongo": "Allow sending log messages to a MongoDB server", - "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "php-console/php-console": "Allow sending log messages to Google Chrome", - "raven/raven": "Allow sending log messages to a Sentry server", - "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.16.x-dev" - } - }, - "autoload": { - "psr-4": { - "Monolog\\": "src/Monolog" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "http://github.com/Seldaek/monolog", - "keywords": [ - "log", - "logging", - "psr-3" - ], - "time": "2015-08-31 09:17:37" + "api", + "auth", + "auth", + "authentication", + "authorisation", + "authorization", + "oauth", + "oauth 2", + "oauth 2.0", + "oauth2", + "protect", + "resource", + "secure", + "server" + ] }, { "name": "nikic/fast-route", @@ -393,23 +193,77 @@ "time": "2015-06-18 19:15:47" }, { - "name": "psr/log", - "version": "1.0.0", + "name": "pimple/pimple", + "version": "v3.0.2", "source": { "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + "url": "https://github.com/silexphp/Pimple.git", + "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "url": "https://api.github.com/repos/silexphp/Pimple/zipball/a30f7d6e57565a2e1a316e1baf2a483f788b258a", + "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a", "shasum": "" }, + "require": { + "php": ">=5.3.0" + }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, "autoload": { "psr-0": { - "Psr\\Log\\": "" + "Pimple": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Pimple, a simple Dependency Injection Container", + "homepage": "http://pimple.sensiolabs.org", + "keywords": [ + "container", + "dependency injection" + ], + "time": "2015-09-11 15:10:35" + }, + { + "name": "psr/http-message", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -422,49 +276,45 @@ "homepage": "http://www.php-fig.org/" } ], - "description": "Common interface for logging libraries", + "description": "Common interface for HTTP messages", "keywords": [ - "log", + "http", + "http-message", "psr", - "psr-3" + "psr-7", + "request", + "response" ], - "time": "2012-12-21 11:40:51" + "time": "2015-05-04 20:22:00" }, { - "name": "symfony/debug", - "version": "v2.7.5", + "name": "slim/slim", + "version": "3.0.0-RC2", "source": { "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "c79c361bca8e5ada6a47603875a3c964d03b67b1" + "url": "https://github.com/slimphp/Slim.git", + "reference": "c181a3a7666677fcf5dee2c03c504d5731262745" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/c79c361bca8e5ada6a47603875a3c964d03b67b1", - "reference": "c79c361bca8e5ada6a47603875a3c964d03b67b1", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/c181a3a7666677fcf5dee2c03c504d5731262745", + "reference": "c181a3a7666677fcf5dee2c03c504d5731262745", "shasum": "" }, "require": { - "php": ">=5.3.9", - "psr/log": "~1.0" - }, - "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + "container-interop/container-interop": "^1.1", + "nikic/fast-route": "^0.6", + "php": ">=5.5.0", + "pimple/pimple": "^3.0", + "psr/http-message": "^1.0" }, "require-dev": { - "symfony/class-loader": "~2.2", - "symfony/http-kernel": "~2.3.24|~2.5.9|~2.6,>=2.6.2", - "symfony/phpunit-bridge": "~2.7" + "phpunit/phpunit": "^4.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.7-dev" - } - }, "autoload": { "psr-4": { - "Symfony\\Component\\Debug\\": "" + "Slim\\": "Slim" } }, "notification-url": "https://packagist.org/downloads/", @@ -473,214 +323,94 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "https://joshlockhart.com" + }, + { + "name": "Gabriel Manricks", + "email": "gmanricks@me.com", + "homepage": "http://gabrielmanricks.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" } ], - "description": "Symfony Debug Component", - "homepage": "https://symfony.com", - "time": "2015-09-14 08:41:38" + "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", + "homepage": "http://slimframework.com", + "keywords": [ + "api", + "framework", + "micro", + "router" + ], + "time": "2015-11-09 10:57:43" }, { - "name": "symfony/event-dispatcher", - "version": "v2.7.5", + "name": "zendframework/zend-diactoros", + "version": "1.1.4", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "ae4dcc2a8d3de98bd794167a3ccda1311597c5d9" + "url": "https://github.com/zendframework/zend-diactoros.git", + "reference": "3f0ce6c0ba2106e018fb514a9f09dbb91eb6bfd0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ae4dcc2a8d3de98bd794167a3ccda1311597c5d9", - "reference": "ae4dcc2a8d3de98bd794167a3ccda1311597c5d9", + "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/3f0ce6c0ba2106e018fb514a9f09dbb91eb6bfd0", + "reference": "3f0ce6c0ba2106e018fb514a9f09dbb91eb6bfd0", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.4", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "~1.0.0" }, "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.0,>=2.0.5", - "symfony/dependency-injection": "~2.6", - "symfony/expression-language": "~2.6", - "symfony/phpunit-bridge": "~2.7", - "symfony/stopwatch": "~2.3" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" + "phpunit/phpunit": "~4.6", + "squizlabs/php_codesniffer": "^2.3.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-master": "1.0-dev", + "dev-develop": "1.1-dev" } }, "autoload": { "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" + "Zend\\Diactoros\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-2-Clause" ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } + "description": "PSR HTTP Message implementations", + "homepage": "https://github.com/zendframework/zend-diactoros", + "keywords": [ + "http", + "psr", + "psr-7" ], - "description": "Symfony EventDispatcher Component", - "homepage": "https://symfony.com", - "time": "2015-09-22 13:49:29" - }, - { - "name": "symfony/http-foundation", - "version": "v2.7.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "e1509119f164a0d0a940d7d924d693a7a28a5470" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e1509119f164a0d0a940d7d924d693a7a28a5470", - "reference": "e1509119f164a0d0a940d7d924d693a7a28a5470", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "require-dev": { - "symfony/expression-language": "~2.4", - "symfony/phpunit-bridge": "~2.7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.7-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpFoundation\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony HttpFoundation Component", - "homepage": "https://symfony.com", - "time": "2015-09-22 13:49:29" - }, - { - "name": "symfony/http-kernel", - "version": "v2.7.5", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-kernel.git", - "reference": "353aa457424262d7d4e4289ea483145921cffcb5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/353aa457424262d7d4e4289ea483145921cffcb5", - "reference": "353aa457424262d7d4e4289ea483145921cffcb5", - "shasum": "" - }, - "require": { - "php": ">=5.3.9", - "psr/log": "~1.0", - "symfony/debug": "~2.6,>=2.6.2", - "symfony/event-dispatcher": "~2.6,>=2.6.7", - "symfony/http-foundation": "~2.5,>=2.5.4" - }, - "conflict": { - "symfony/config": "<2.7" - }, - "require-dev": { - "symfony/browser-kit": "~2.3", - "symfony/class-loader": "~2.1", - "symfony/config": "~2.7", - "symfony/console": "~2.3", - "symfony/css-selector": "~2.0,>=2.0.5", - "symfony/dependency-injection": "~2.2", - "symfony/dom-crawler": "~2.0,>=2.0.5", - "symfony/expression-language": "~2.4", - "symfony/finder": "~2.0,>=2.0.5", - "symfony/phpunit-bridge": "~2.7", - "symfony/process": "~2.0,>=2.0.5", - "symfony/routing": "~2.2", - "symfony/stopwatch": "~2.3", - "symfony/templating": "~2.2", - "symfony/translation": "~2.0,>=2.0.5", - "symfony/var-dumper": "~2.6" - }, - "suggest": { - "symfony/browser-kit": "", - "symfony/class-loader": "", - "symfony/config": "", - "symfony/console": "", - "symfony/dependency-injection": "", - "symfony/finder": "", - "symfony/var-dumper": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.7-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpKernel\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony HttpKernel Component", - "homepage": "https://symfony.com", - "time": "2015-09-25 11:16:52" + "time": "2015-10-16 15:24:05" } ], "packages-dev": [], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "slim/slim": 5, + "league/oauth2-server": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": [], From c0823c464e04066cbbd7aca7925300bb4863f1cc Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 13 Nov 2015 17:40:29 +0000 Subject: [PATCH 074/444] Tidy --- composer.json | 118 +++++++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/composer.json b/composer.json index 19dc5c40..8fcad77f 100644 --- a/composer.json +++ b/composer.json @@ -1,61 +1,61 @@ { - "name": "league/oauth2-server", - "description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.", - "homepage": "http://oauth2.thephpleague.com/", - "license": "MIT", - "require": { - "php": ">=5.5.9", - "league/event": "~2.1", - "zendframework/zend-diactoros": "~1.1" - }, - "require-dev": { - "phpunit/phpunit": "4.8.*", - "mockery/mockery": "0.9.*", - "codeception/codeception": "~2.0", - "flow/jsonpath": "0.2.*" - }, - "repositories": [ - { - "type": "git", - "url": "https://github.com/thephpleague/oauth2-server.git" - } - ], - "keywords": [ - "oauth", - "oauth2", - "oauth 2", - "oauth 2.0", - "server", - "auth", - "authorization", - "authorisation", - "authentication", - "resource", - "api", - "auth", - "protect", - "secure" - ], - "authors": [ - { - "name": "Alex Bilbie", - "email": "hello@alexbilbie.com", - "homepage": "http://www.alexbilbie.com", - "role": "Developer" - } - ], - "replace": { - "lncd/oauth2": "*", - "league/oauth2server": "*" - }, - "autoload": { - "psr-4": { - "League\\OAuth2\\Server\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "LeagueTests\\": "tests/unit/" - } - } + "name": "league/oauth2-server", + "description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.", + "homepage": "http://oauth2.thephpleague.com/", + "license": "MIT", + "require": { + "php": ">=5.5.9", + "league/event": "~2.1", + "zendframework/zend-diactoros": "~1.1" + }, + "require-dev": { + "phpunit/phpunit": "4.8.*", + "mockery/mockery": "0.9.*", + "codeception/codeception": "~2.0", + "flow/jsonpath": "0.2.*" + }, + "repositories": [ + { + "type": "git", + "url": "https://github.com/thephpleague/oauth2-server.git" + } + ], + "keywords": [ + "oauth", + "oauth2", + "oauth 2", + "oauth 2.0", + "server", + "auth", + "authorization", + "authorisation", + "authentication", + "resource", + "api", + "auth", + "protect", + "secure" + ], + "authors": [ + { + "name": "Alex Bilbie", + "email": "hello@alexbilbie.com", + "homepage": "http://www.alexbilbie.com", + "role": "Developer" + } + ], + "replace": { + "lncd/oauth2": "*", + "league/oauth2server": "*" + }, + "autoload": { + "psr-4": { + "League\\OAuth2\\Server\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "LeagueTests\\": "tests/unit/" + } + } } From b95780022a181ed4b2b73d8cbb13f190f1e64793 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 13 Nov 2015 17:40:39 +0000 Subject: [PATCH 075/444] Updated client credentials example --- examples/public/client_credentials.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index db359b92..9259c0b1 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -1,11 +1,17 @@ enableGrantType(new ClientCredentialsGrant($clientRepository, $scopeRepository, $accessTokenRepository)); + +// App +$app = new App([Server::class => $server]); +unset($app->getContainer()['errorHandler']); + +$app->post('/access_token', function (Request $request, Response $response) { + /** @var Server $server */ + $server = $this->getContainer()->get(Server::class); + try { + return $server->respondToRequest($request); + } catch (OAuthException $e) { + return $e->generateHttpResponse(); + } catch (\Exception $e) { + return $response->withStatus(500)->write($e->getMessage()); + } +}); + +$app->run(); From 96a0c34d419c76d9b3468bc6ac31797a32a8535d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 13 Nov 2015 17:40:53 +0000 Subject: [PATCH 076/444] Updated example repositories to match updated interfaces --- .../Repositories/AccessTokenRepository.php | 39 +++++++------------ .../src/Repositories/ClientRepository.php | 11 +----- examples/src/Repositories/ScopeRepository.php | 10 +---- 3 files changed, 17 insertions(+), 43 deletions(-) diff --git a/examples/src/Repositories/AccessTokenRepository.php b/examples/src/Repositories/AccessTokenRepository.php index 71392d9d..16d8dc2b 100644 --- a/examples/src/Repositories/AccessTokenRepository.php +++ b/examples/src/Repositories/AccessTokenRepository.php @@ -9,56 +9,43 @@ class AccessTokenRepository implements AccessTokenRepositoryInterface { /** - * Get an instance of Entity\AccessTokenEntity - * - * @param string $tokenIdentifier The access token identifier - * - * @return \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface + * @inheritdoc */ - public function get($tokenIdentifier) + public function getAccessTokenEntityByTokenString($tokenIdentifier) { // TODO: Implement get() method. } /** - * Get the scopes for an access token - * - * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $token - * - * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] + * @inheritdoc */ - public function getScopes(AccessTokenEntityInterface $token) + public function getScopeEntitiesAssociatedWithAccessToken(AccessTokenEntityInterface $token) { // TODO: Implement getScopes() method. } /** - * Creates a new access token - * - * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessTokenEntity + * @inheritdoc */ - public function create(AccessTokenEntityInterface $accessTokenEntity) + public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity) { // TODO: Implement create() method. } /** - * Associate a scope with an access token - * - * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessTokenEntityInterface - * @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface $scope + * @inheritdoc */ - public function associateScope(AccessTokenEntityInterface $accessTokenEntityInterface, ScopeEntityInterface $scope) - { + public function associateScopeWithAccessToken( + AccessTokenEntityInterface $accessTokenEntityInterface, + ScopeEntityInterface $scope + ) { // TODO: Implement associateScope() method. } /** - * Delete an access token - * - * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken + * @inheritdoc */ - public function delete(AccessTokenEntityInterface $accessToken) + public function deleteAccessToken(AccessTokenEntityInterface $accessToken) { // TODO: Implement delete() method. } diff --git a/examples/src/Repositories/ClientRepository.php b/examples/src/Repositories/ClientRepository.php index 286964ac..1130121e 100644 --- a/examples/src/Repositories/ClientRepository.php +++ b/examples/src/Repositories/ClientRepository.php @@ -7,16 +7,9 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface; class ClientRepository implements ClientRepositoryInterface { /** - * Get a client - * - * @param string $clientIdentifier The client's identifier - * @param string $clientSecret The client's secret (default = "null") - * @param string $redirectUri The client's redirect URI (default = "null") - * @param string $grantType The grant type used (default = "null") - * - * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface + * @inheritdoc */ - public function get($clientIdentifier, $clientSecret = null, $redirectUri = null, $grantType = null) + public function getClientEntity($clientIdentifier, $clientSecret = null, $redirectUri = null, $grantType = null) { $clients = [ 'myawesomeapp' => [ diff --git a/examples/src/Repositories/ScopeRepository.php b/examples/src/Repositories/ScopeRepository.php index 942f53c2..ecfadd11 100644 --- a/examples/src/Repositories/ScopeRepository.php +++ b/examples/src/Repositories/ScopeRepository.php @@ -7,15 +7,9 @@ use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; class ScopeRepository implements ScopeRepositoryInterface { /** - * Return information about a scope - * - * @param string $scopeIdentifier The scope identifier - * @param string $grantType The grant type used in the request (default = "null") - * @param string $clientId The client sending the request (default = "null") - * - * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface + * @inheritdoc */ - public function get($scopeIdentifier, $grantType = null, $clientId = null) + public function getScopeEntityByIdentifier($scopeIdentifier, $grantType, $clientId = null) { $scopes = [ 'basic' => [ From 32b451aa21f4ccd6a4ce1d870fa9fe6c73555a11 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 13 Nov 2015 17:41:05 +0000 Subject: [PATCH 077/444] Updates --- src/Grant/AbstractGrant.php | 14 ++--- src/Grant/ClientCredentialsGrant.php | 40 +++++-------- src/Grant/GrantTypeInterface.php | 20 +++---- src/Server.php | 84 +++++++++------------------- 4 files changed, 58 insertions(+), 100 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 3cca9373..a51d18e0 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -11,10 +11,10 @@ namespace League\OAuth2\Server\Grant; -use League\Event\Emitter; +use League\Event\EmitterInterface; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\ScopeEntity; -use League\OAuth2\Server\Exception; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; @@ -102,7 +102,7 @@ abstract class AbstractGrant implements GrantTypeInterface * @param string $redirectUri * * @return \League\OAuth2\Server\Entities\ScopeEntity[] - * @throws \League\OAuth2\Server\Exception\InvalidScopeException + * @throws \League\OAuth2\Server\Exception\OAuthServerException */ public function validateScopes( $scopeParamValue, @@ -119,14 +119,14 @@ abstract class AbstractGrant implements GrantTypeInterface $scopes = []; foreach ($scopesList as $scopeItem) { - $scope = $this->scopeRepository->get( + $scope = $this->scopeRepository->getScopeEntityByIdentifier( $scopeItem, $this->getIdentifier(), $client->getIdentifier() ); if (($scope instanceof ScopeEntity) === false) { - throw new Exception\InvalidScopeException($scopeItem, $redirectUri); + throw OAuthServerException::invalidScope($scopeItem, null, null, $redirectUri); } $scopes[] = $scope; @@ -136,9 +136,9 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @param Emitter $emitter + * @inheritdoc */ - public function setEmitter(Emitter $emitter) + public function setEmitter(EmitterInterface $emitter) { $this->emitter = $emitter; } diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index a6cd7da9..c6972309 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -15,8 +15,8 @@ use DateInterval; use League\Event\Event; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Exception; -use League\OAuth2\Server\TokenTypes\TokenTypeInterface; +use League\OAuth2\Server\Exception\OAuthServerException; +use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\Utils\SecureKey; use Psr\Http\Message\ServerRequestInterface; @@ -33,47 +33,37 @@ class ClientCredentialsGrant extends AbstractGrant protected $identifier = 'client_credentials'; /** - * Return an access token - * - * @param \Psr\Http\Message\ServerRequestInterface $request - * @param \League\OAuth2\Server\TokenTypes\TokenTypeInterface $tokenType - * @param \DateInterval $accessTokenTTL - * @param string $scopeDelimiter - * - * @return \League\OAuth2\Server\TokenTypes\TokenTypeInterface - * @throws \League\OAuth2\Server\Exception\InvalidClientException - * @throws \League\OAuth2\Server\Exception\InvalidRequestException - * @throws \League\OAuth2\Server\Exception\InvalidScopeException + * @inheritdoc */ public function respondToRequest( ServerRequestInterface $request, - TokenTypeInterface $tokenType, + ResponseTypeInterface $responseType, DateInterval $accessTokenTTL, $scopeDelimiter = ' ' ) { // Get the required params $clientId = isset($request->getParsedBody()['client_id']) ? $request->getParsedBody()['client_id'] // $_POST['client_id'] - : isset($request->getServerParams()['PHP_AUTH_USER']) + : (isset($request->getServerParams()['PHP_AUTH_USER']) ? $request->getServerParams()['PHP_AUTH_USER'] // $_SERVER['PHP_AUTH_USER'] - : null; + : null); if (is_null($clientId)) { - throw new Exception\InvalidRequestException('client_id'); + throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); } $clientSecret = isset($request->getParsedBody()['client_secret']) ? $request->getParsedBody()['client_secret'] // $_POST['client_id'] - : isset($request->getServerParams()['PHP_AUTH_PW']) + : (isset($request->getServerParams()['PHP_AUTH_PW']) ? $request->getServerParams()['PHP_AUTH_PW'] // $_SERVER['PHP_AUTH_USER'] - : null; + : null); if (is_null($clientSecret)) { - throw new Exception\InvalidRequestException('client_secret'); + throw OAuthServerException::invalidRequest('client_secret', null, '`%s` parameter is missing'); } // Validate client ID and client secret - $client = $this->clientRepository->get( + $client = $this->clientRepository->getClientEntity( $clientId, $clientSecret, null, @@ -82,7 +72,7 @@ class ClientCredentialsGrant extends AbstractGrant if (($client instanceof ClientEntityInterface) === false) { $this->emitter->emit(new Event('client.authentication.failed', $request)); - throw new Exception\InvalidClientException(); + throw OAuthServerException::invalidClient(); } // Validate any scopes that are in the request @@ -104,12 +94,12 @@ class ClientCredentialsGrant extends AbstractGrant } // Save the token - $this->accessTokenRepository->create($accessToken); + $this->accessTokenRepository->persistNewAccessToken($accessToken); // Inject access token into token type - $tokenType->setAccessToken($accessToken); + $responseType->setAccessToken($accessToken); - return $tokenType; + return $responseType; } /** diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index c553b093..5f17437f 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -12,8 +12,8 @@ namespace League\OAuth2\Server\Grant; use DateInterval; -use League\Event\Emitter; -use League\OAuth2\Server\TokenTypes\TokenTypeInterface; +use League\Event\EmitterInterface; +use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ServerRequestInterface; /** @@ -38,16 +38,16 @@ interface GrantTypeInterface /** * Return an access token * - * @param \Psr\Http\Message\ServerRequestInterface $request - * @param \League\OAuth2\Server\TokenTypes\TokenTypeInterface $tokenType - * @param \DateInterval $accessTokenTTL - * @param string $scopeDelimiter + * @param \Psr\Http\Message\ServerRequestInterface $request + * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $tokenType + * @param \DateInterval $accessTokenTTL + * @param string $scopeDelimiter * - * @return \League\OAuth2\Server\TokenTypes\TokenTypeInterface + * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface */ public function respondToRequest( ServerRequestInterface $request, - TokenTypeInterface $tokenType, + ResponseTypeInterface $tokenType, DateInterval $accessTokenTTL, $scopeDelimiter = ' ' ); @@ -69,7 +69,7 @@ interface GrantTypeInterface /** * Set the event emitter * - * @param \League\Event\Emitter $emitter + * @param \League\Event\EmitterInterface $emitter */ - public function setEmitter(Emitter $emitter); + public function setEmitter(EmitterInterface $emitter); } diff --git a/src/Server.php b/src/Server.php index 87beb38c..b4e6625b 100644 --- a/src/Server.php +++ b/src/Server.php @@ -5,15 +5,10 @@ namespace League\OAuth2\Server; use DateInterval; use League\Event\EmitterAwareInterface; use League\Event\EmitterAwareTrait; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\GrantTypeInterface; -//use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; -//use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; -//use League\OAuth2\Server\Repositories\ClientRepositoryInterface; -use League\OAuth2\Server\Repositories\RepositoryInterface; -//use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; -//use League\OAuth2\Server\Repositories\UserRepositoryInterface; -use League\OAuth2\Server\TokenTypes\BearerTokenType; -use League\OAuth2\Server\TokenTypes\TokenTypeInterface; +use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; +use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ServerRequestInterface; use Zend\Diactoros\ServerRequestFactory; @@ -27,9 +22,9 @@ class Server implements EmitterAwareInterface protected $enabledGrantTypes = []; /** - * @var TokenTypeInterface[] + * @var ResponseTypeInterface[] */ - protected $grantTypeTokenTypes = []; + protected $grantResponseTypes = []; /** * @var DateInterval[] @@ -37,9 +32,9 @@ class Server implements EmitterAwareInterface protected $grantTypeAccessTokenTTL = []; /** - * @var TokenTypeInterface + * @var ResponseTypeInterface */ - protected $defaultTokenType; + protected $defaultResponseType; /** * @var DateInterval @@ -51,28 +46,23 @@ class Server implements EmitterAwareInterface */ protected $scopeDelimiterString = ' '; - /** - * @var RepositoryInterface[] - */ -// protected $repositories = []; - /** * New server instance */ public function __construct() { - $this->setDefaultTokenType(new BearerTokenType()); - $this->setDefaultAccessTokenTTL(new DateInterval('PT01H')); // default of 1 hour + $this->setDefaultResponseType(new BearerTokenResponse()); + $this->setDefaultAccessTokenTTL(new DateInterval('PT01H')); // default token TTL of 1 hour } /** * Set the default token type that grants will return * - * @param TokenTypeInterface $defaultTokenType + * @param ResponseTypeInterface $defaultTokenType */ - public function setDefaultTokenType(TokenTypeInterface $defaultTokenType) + public function setDefaultResponseType(ResponseTypeInterface $defaultTokenType) { - $this->defaultTokenType = $defaultTokenType; + $this->defaultResponseType = $defaultTokenType; } /** @@ -99,22 +89,22 @@ class Server implements EmitterAwareInterface * Enable a grant type on the server * * @param \League\OAuth2\Server\Grant\GrantTypeInterface $grantType - * @param TokenTypeInterface $tokenType + * @param ResponseTypeInterface $responseType * @param DateInterval $accessTokenTTL */ public function enableGrantType( GrantTypeInterface $grantType, - TokenTypeInterface $tokenType = null, + ResponseTypeInterface $responseType = null, DateInterval $accessTokenTTL = null ) { $grantType->setEmitter($this->getEmitter()); $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; // Set grant response type - if ($tokenType instanceof TokenTypeInterface) { - $this->grantTypeTokenTypes[$grantType->getIdentifier()] = $tokenType; + if ($responseType instanceof ResponseTypeInterface) { + $this->grantResponseTypes[$grantType->getIdentifier()] = $responseType; } else { - $this->grantTypeTokenTypes[$grantType->getIdentifier()] = $this->defaultTokenType; + $this->grantResponseTypes[$grantType->getIdentifier()] = $this->defaultResponseType; } // Set grant access token TTL @@ -130,8 +120,8 @@ class Server implements EmitterAwareInterface * * @param \Psr\Http\Message\ServerRequestInterface $request * - * @return \League\OAuth2\Server\TokenTypes\TokenTypeInterface - * @throws \League\OAuth2\Server\Exception\InvalidGrantException + * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface + * @throws \League\OAuth2\Server\Exception\OAuthServerException */ public function respondToRequest(ServerRequestInterface $request = null) { @@ -139,46 +129,24 @@ class Server implements EmitterAwareInterface $request = ServerRequestFactory::fromGlobals(); } - $response = null; + $tokenResponse = null; foreach ($this->enabledGrantTypes as $grantType) { if ($grantType->canRespondToRequest($request)) { - $response = $grantType->respondToRequest( + $tokenResponse = $grantType->respondToRequest( $request, - $this->grantTypeTokenTypes[$grantType->getIdentifier()], + $this->grantResponseTypes[$grantType->getIdentifier()], $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()], $this->scopeDelimiterString ); } } - if ($response === null) { - // do something here + if ($tokenResponse instanceof ResponseTypeInterface) { + return $tokenResponse->generateHttpResponse(); + } else { + $response = OAuthServerException::unsupportedGrantType()->generateHttpResponse(); } return $response; } - - /** - * @param \League\OAuth2\Server\Repositories\RepositoryInterface $repository - */ - /*public function addRepository(RepositoryInterface $repository) - { - switch ($repository) { - case ($repository instanceof AccessTokenRepositoryInterface): - $this->repositories[AccessTokenRepositoryInterface::class] = $repository; - break; - case ($repository instanceof ClientRepositoryInterface): - $this->repositories[ClientRepositoryInterface::class] = $repository; - break; - case ($repository instanceof ScopeRepositoryInterface): - $this->repositories[ScopeRepositoryInterface::class] = $repository; - break; - case ($repository instanceof UserRepositoryInterface): - $this->repositories[UserRepositoryInterface::class] = $repository; - break; - case ($repository instanceof AuthCodeRepositoryInterface): - $this->repositories[AuthCodeRepositoryInterface::class] = $repository; - break; - } - }*/ } From c0bdd2215480c42d079dd3225650f22c20b12f17 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 16 Nov 2015 09:27:49 +0000 Subject: [PATCH 078/444] Updated exception reference --- examples/public/client_credentials.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index 9259c0b1..8486d31e 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -1,6 +1,6 @@ enableGrantType(new ClientCredentialsGrant($clientRepository, $scopeRep // App $app = new App([Server::class => $server]); -unset($app->getContainer()['errorHandler']); $app->post('/access_token', function (Request $request, Response $response) { /** @var Server $server */ $server = $this->getContainer()->get(Server::class); try { return $server->respondToRequest($request); - } catch (OAuthException $e) { + } catch (OAuthServerException $e) { return $e->generateHttpResponse(); } catch (\Exception $e) { return $response->withStatus(500)->write($e->getMessage()); From b7ba59385618f19f11248c18c48d042a747ac39e Mon Sep 17 00:00:00 2001 From: Vincent Klaiber Date: Mon, 16 Nov 2015 12:33:58 +0100 Subject: [PATCH 079/444] Add branch alias for version 5.0 To let us start testing this version for Laravel OAuth server package. --- composer.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/composer.json b/composer.json index 8fcad77f..bb83055a 100644 --- a/composer.json +++ b/composer.json @@ -57,5 +57,10 @@ "psr-4": { "LeagueTests\\": "tests/unit/" } + }, + "extra": { + "branch-alias": { + "dev-V5-WIP": "5.0-dev" + } } } From 6f2e2a0071c9344045db9c0b233daa4236ee93c2 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 16 Nov 2015 12:57:59 +0000 Subject: [PATCH 080/444] Updated exceptions --- src/Exception/InvalidCredentialsException.php | 36 ---- src/Exception/OAuthServerException.php | 199 ++++++++++-------- 2 files changed, 107 insertions(+), 128 deletions(-) delete mode 100644 src/Exception/InvalidCredentialsException.php diff --git a/src/Exception/InvalidCredentialsException.php b/src/Exception/InvalidCredentialsException.php deleted file mode 100644 index 40c4ce7e..00000000 --- a/src/Exception/InvalidCredentialsException.php +++ /dev/null @@ -1,36 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Exception; - -/** - * Exception class - */ -class InvalidCredentialsException extends OAuthException -{ - /** - * {@inheritdoc} - */ - public $httpStatusCode = 401; - - /** - * {@inheritdoc} - */ - public $errorType = 'invalid_credentials'; - - /** - * {@inheritdoc} - */ - public function __construct() - { - parent::__construct('The user credentials were incorrect.'); - } -} diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index c0ea5ec1..953f8499 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -47,98 +47,6 @@ class OAuthServerException extends \Exception $this->redirectUri = $redirectUri; } - /** - * @return int - */ - public function getHttpStatusCode() - { - return $this->httpStatusCode; - } - - - /** - * @return string - */ - public function getErrorType() - { - return $this->errorType; - } - - /** - * 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' - ]; - - // Add "WWW-Authenticate" header - // - // RFC 6749, section 5.2.: - // "If the client attempted to authenticate via the 'Authorization' - // request header field, the authorization server MUST - // respond with an HTTP 401 (Unauthorized) status code and - // include the "WWW-Authenticate" response header field - // matching the authentication scheme used by the client. - // @codeCoverageIgnoreStart - if ($this->errorType === 'invalid_client') { - $authScheme = null; - $request = new ServerRequest(); - if ($request->getServerParams()['PHP_AUTH_USER'] !== null) { - $authScheme = 'Basic'; - } else { - $authHeader = $request->getHeader('authorization'); - if ($authHeader !== null) { - if (strpos($authHeader, 'Bearer') === 0) { - $authScheme = 'Bearer'; - } elseif (strpos($authHeader, 'Basic') === 0) { - $authScheme = 'Basic'; - } - } - } - if ($authScheme !== null) { - $headers[] = 'WWW-Authenticate: ' . $authScheme . ' realm="OAuth"'; - } - } - - // @codeCoverageIgnoreEnd - return $headers; - } - - /** - * Generate a HTTP response - * @return ResponseInterface - */ - public function generateHttpResponse() - { - $headers = $this->getHttpHeaders(); - - $payload = [ - 'error' => $this->errorType, - 'message' => $this->getMessage() - ]; - - if ($this->hint !== null) { - $payload['hint'] = $this->hint; - } - - if ($this->redirectUri !== null) { - $headers['Location'] = RedirectUri::make($this->redirectUri, $payload); - } - - $response = new Response( - 'php://memory', - $this->getHttpStatusCode(), - $headers - ); - $response->getBody()->write(json_encode($payload)); - - return $response; - } - /** * Invalid grant type error * @@ -244,4 +152,111 @@ class OAuthServerException extends \Exception return new static($errorMessage, '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 string + */ + public function getErrorType() + { + return $this->errorType; + } + + /** + * Generate a HTTP response + * + * @return ResponseInterface + */ + public function generateHttpResponse() + { + $headers = $this->getHttpHeaders(); + + $payload = [ + 'error' => $this->errorType, + 'message' => $this->getMessage() + ]; + + if ($this->hint !== null) { + $payload['hint'] = $this->hint; + } + + if ($this->redirectUri !== null) { + $headers['Location'] = RedirectUri::make($this->redirectUri, $payload); + } + + $response = new Response( + 'php://memory', + $this->getHttpStatusCode(), + $headers + ); + $response->getBody()->write(json_encode($payload)); + + return $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' + ]; + + // Add "WWW-Authenticate" header + // + // RFC 6749, section 5.2.: + // "If the client attempted to authenticate via the 'Authorization' + // request header field, the authorization server MUST + // respond with an HTTP 401 (Unauthorized) status code and + // include the "WWW-Authenticate" response header field + // matching the authentication scheme used by the client. + // @codeCoverageIgnoreStart + if ($this->errorType === 'invalid_client') { + $authScheme = null; + $request = new ServerRequest(); + if ( + isset($request->getServerParams()['PHP_AUTH_USER']) && + $request->getServerParams()['PHP_AUTH_USER'] !== null + ) { + $authScheme = 'Basic'; + } else { + $authHeader = $request->getHeader('authorization'); + if ($authHeader !== []) { + if (strpos($authHeader[0], 'Bearer') === 0) { + $authScheme = 'Bearer'; + } elseif (strpos($authHeader[0], 'Basic') === 0) { + $authScheme = 'Basic'; + } + } + } + if ($authScheme !== null) { + $headers[] = 'WWW-Authenticate: ' . $authScheme . ' realm="OAuth"'; + } + } + + // @codeCoverageIgnoreEnd + return $headers; + } + + /** + * Returns the HTTP status code to send when the exceptions is output + * + * @return int + */ + public function getHttpStatusCode() + { + return $this->httpStatusCode; + } } From 46648f3e80207e7670617fd1662627f050197e82 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 16 Nov 2015 12:58:11 +0000 Subject: [PATCH 081/444] Updated password grant --- src/Grant/PasswordGrant.php | 167 +++++++++++++++++------------------- 1 file changed, 77 insertions(+), 90 deletions(-) diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index e50f4708..dc27f212 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -12,105 +12,77 @@ namespace League\OAuth2\Server\Grant; use DateInterval; -use League\Event\Emitter; use League\Event\Event; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; -use League\OAuth2\Server\Exception; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; -use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; -use League\OAuth2\Server\TokenTypes\TokenTypeInterface; +use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\Utils\SecureKey; -use Symfony\Component\HttpFoundation\Request; +use Psr\Http\Message\ServerRequestInterface; /** * Password grant class */ class PasswordGrant extends AbstractGrant { - /** - * Grant identifier - * - * @var string - */ - protected $identifier = 'password'; - - /** - * Callback to authenticate a user's name and password - * - * @var callable - */ - protected $callback; - /** * @var \League\OAuth2\Server\Repositories\UserRepositoryInterface */ - protected $userRepository; + private $userRepository; /** - * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface - */ - protected $refreshTokenRepository; - - /** - * @param \League\Event\Emitter $emitter - * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository - * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository - * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository - * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository - * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository + * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository + * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository + * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository + * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository */ public function __construct( - Emitter $emitter, + UserRepositoryInterface $userRepository, ClientRepositoryInterface $clientRepository, ScopeRepositoryInterface $scopeRepository, - AccessTokenRepositoryInterface $accessTokenRepository, - UserRepositoryInterface $userRepository, - RefreshTokenRepositoryInterface $refreshTokenRepository = null + AccessTokenRepositoryInterface $accessTokenRepository ) { $this->userRepository = $userRepository; - $this->refreshTokenRepository = $refreshTokenRepository; - parent::__construct($emitter, $clientRepository, $scopeRepository, $accessTokenRepository); + parent::__construct($clientRepository, $scopeRepository, $accessTokenRepository); } /** - * Return an access token - * - * @param \Symfony\Component\HttpFoundation\Request $request - * @param \League\OAuth2\Server\TokenTypes\TokenTypeInterface $tokenType - * @param \DateInterval $accessTokenTTL - * @param string $scopeDelimiter - * - * @return \League\OAuth2\Server\TokenTypes\TokenTypeInterface - * @throws \League\OAuth2\Server\Exception\InvalidClientException - * @throws \League\OAuth2\Server\Exception\InvalidCredentialsException - * @throws \League\OAuth2\Server\Exception\InvalidRequestException - * @throws \League\OAuth2\Server\Exception\InvalidScopeException + * @inheritdoc */ - public function getAccessTokenAsType( - Request $request, - TokenTypeInterface $tokenType, + public function respondToRequest( + ServerRequestInterface $request, + ResponseTypeInterface $responseType, DateInterval $accessTokenTTL, $scopeDelimiter = ' ' ) { // Get the required params - $clientId = $request->request->get('client_id', $request->getUser()); + $clientId = isset($request->getParsedBody()['client_id']) + ? $request->getParsedBody()['client_id'] // $_POST['client_id'] + : (isset($request->getServerParams()['PHP_AUTH_USER']) + ? $request->getServerParams()['PHP_AUTH_USER'] // $_SERVER['PHP_AUTH_USER'] + : null); + if (is_null($clientId)) { - throw new Exception\InvalidRequestException('client_id'); + throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); } - $clientSecret = $request->request->get('client_secret', - $request->getPassword()); + $clientSecret = isset($request->getParsedBody()['client_secret']) + ? $request->getParsedBody()['client_secret'] // $_POST['client_id'] + : (isset($request->getServerParams()['PHP_AUTH_PW']) + ? $request->getServerParams()['PHP_AUTH_PW'] // $_SERVER['PHP_AUTH_USER'] + : null); + if (is_null($clientSecret)) { - throw new Exception\InvalidRequestException('client_secret'); + throw OAuthServerException::invalidRequest('client_secret', null, '`%s` parameter is missing'); } // Validate client ID and client secret - $client = $this->clientRepository->get( + $client = $this->clientRepository->getClientEntity( $clientId, $clientSecret, null, @@ -119,62 +91,77 @@ class PasswordGrant extends AbstractGrant if (($client instanceof ClientEntityInterface) === false) { $this->emitter->emit(new Event('client.authentication.failed', $request)); - throw new Exception\InvalidClientException(); + throw OAuthServerException::invalidClient(); } - $username = $request->request->get('username', null); + // Username + $username = isset($request->getParsedBody()['username']) + ? $request->getParsedBody()['username'] // $_POST['username'] + : (isset($request->getServerParams()['PHP_AUTH_USER']) + ? $request->getServerParams()['PHP_AUTH_USER'] // $_SERVER['PHP_AUTH_USER'] + : null); + if (is_null($username)) { - throw new Exception\InvalidRequestException('username'); + throw OAuthServerException::invalidRequest('username', null, '`%s` parameter is missing'); } - $password = $request->request->get('password', null); + // Password + $password = isset($request->getParsedBody()['password']) + ? $request->getParsedBody()['password'] // $_POST['password'] + : (isset($request->getServerParams()['PHP_AUTH_USER']) + ? $request->getServerParams()['PHP_AUTH_USER'] // $_SERVER['PHP_AUTH_USER'] + : null); + if (is_null($password)) { - throw new Exception\InvalidRequestException('password'); + throw OAuthServerException::invalidRequest('password', null, '`%s` parameter is missing'); } - // Check if user's username and password are correct - $user = $this->userRepository->getByCredentials($username, $password); - - if (($user instanceof UserEntityInterface) === false) { + // Verify user's username and password + $userEntity = $this->userRepository->getUserEntityByUserCredentials($username, $password); + if (($userEntity instanceof UserEntityInterface) === false) { $this->emitter->emit(new Event('user.authentication.failed', $request)); - throw new Exception\InvalidCredentialsException(); + throw OAuthServerException::invalidCredentials(); } // Validate any scopes that are in the request - $scopeParamValue = $request->request->get('scope', ''); - $scopes = $this->validateScopes($scopeParamValue, $scopeDelimiter, $client); + $scopeParam = isset($request->getParsedBody()['scope']) + ? $request->getParsedBody()['scope'] // $_POST['scope'] + : ''; + $scopes = $this->validateScopes($scopeParam, $scopeDelimiter, $client); // Generate an access token $accessToken = new AccessTokenEntity(); $accessToken->setIdentifier(SecureKey::generate()); - $expirationDateTime = (new \DateTime())->add($accessTokenTTL); - $accessToken->setExpiryDateTime($expirationDateTime); - $accessToken->setOwner('user', $user->getIdentifier()); + $accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL)); $accessToken->setClient($client); + $accessToken->setOwner('user', $userEntity->getIdentifier()); - // Associate scopes with the access token + // Associate scopes with the session and access token foreach ($scopes as $scope) { $accessToken->addScope($scope); } - $tokenType->setAccessToken($accessToken); + // Save the token + $this->accessTokenRepository->persistNewAccessToken($accessToken); - // Associate a refresh token if set - if ($this->refreshTokenRepository instanceof RefreshTokenRepositoryInterface) { -// $refreshToken = new RefreshTokenEntity($this->server); -// $refreshToken->setId(SecureKey::generate()); -// $refreshToken->setExpireTime($this->server->getGrantType('refresh_token')->getRefreshTokenTTL() + time()); -// $refreshToken->setAccessToken($accessToken); -// $this->server->getTokenType()->setParam('refresh_token', $refreshToken->getId()); -// $tokenType->setParam('refresh_token', $refreshToken); + // Inject access token into token type + $responseType->setAccessToken($accessToken); + + return $responseType; + } + + /** + * @inheritdoc + */ + public function canRespondToRequest(ServerRequestInterface $request) + { + if ( + isset($request->getParsedBody()['grant_type']) + && $request->getParsedBody()['grant_type'] === 'password' + ) { + return true; } - // Save the access token - $this->accessTokenRepository->create($accessToken); - - // Inject the access token into token type - $tokenType->setAccessToken($accessToken); - - return $tokenType; + return false; } } From e7e4892408a784bf48a3f4f42703c633edbf1bc4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 16 Nov 2015 12:58:38 +0000 Subject: [PATCH 082/444] Fixed method parameter name --- src/Grant/GrantTypeInterface.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 5f17437f..f521452f 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -39,7 +39,7 @@ interface GrantTypeInterface * Return an access token * * @param \Psr\Http\Message\ServerRequestInterface $request - * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $tokenType + * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType * @param \DateInterval $accessTokenTTL * @param string $scopeDelimiter * @@ -47,7 +47,7 @@ interface GrantTypeInterface */ public function respondToRequest( ServerRequestInterface $request, - ResponseTypeInterface $tokenType, + ResponseTypeInterface $responseType, DateInterval $accessTokenTTL, $scopeDelimiter = ' ' ); From bb17abfe26b19f8ceb0ecb427dd2f1dfb342173e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 16 Nov 2015 12:58:50 +0000 Subject: [PATCH 083/444] Updated password grant example --- examples/public/password.php | 46 +++++++++++++------- examples/src/Repositories/UserRepository.php | 13 +++--- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/examples/public/password.php b/examples/public/password.php index fff4717b..efeed2f0 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -1,34 +1,50 @@ addRepository(new ClientRepository()); -$server->addRepository(new ScopeRepository()); -$server->addRepository(new AccessTokenRepository()); -$server->addRepository(new UserRepository()); -// Enable the password grant -$server->enableGrantType('PasswordGrant'); +// Init our repositories +$clientRepository = new ClientRepository(); +$scopeRepository = new ScopeRepository(); +$accessTokenRepository = new AccessTokenRepository(); +$userRepository = new UserRepository(); -// Setup app + routing -$application = new \Proton\Application(); -$application->post('/access_token', function (Request $request) use ($server) { +// Enable the client credentials grant on the server +$server->enableGrantType(new PasswordGrant( + $userRepository, + $clientRepository, + $scopeRepository, + $accessTokenRepository +)); + +// App +$app = new App([Server::class => $server]); + +$app->post('/access_token', function (Request $request, Response $response) { + /** @var Server $server */ + $server = $this->getContainer()->get(Server::class); try { - return $server->getAccessTokenResponse($request); - } catch (OAuthException $e) { + return $server->respondToRequest($request); + } catch (OAuthServerException $e) { return $e->generateHttpResponse(); + } catch (\Exception $e) { + return $response->withStatus(500)->write($e->getMessage()); } }); -// Run the app -$application->run(); +$app->run(); diff --git a/examples/src/Repositories/UserRepository.php b/examples/src/Repositories/UserRepository.php index d006dab1..1ad9914d 100644 --- a/examples/src/Repositories/UserRepository.php +++ b/examples/src/Repositories/UserRepository.php @@ -1,22 +1,25 @@ Date: Wed, 2 Dec 2015 17:02:54 +0100 Subject: [PATCH 084/444] Add files to attributes Added more files to the .gitattributes file. --- .gitattributes | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/.gitattributes b/.gitattributes index cae05a90..815391c2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,14 @@ -tests/ export-ignore -phpunit.xml export-ignore +* text=auto + +/examples export-ignore +/tests export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.travis.yml export-ignore .travis.yml export-ignore -.scrutinizer.yml export-ignore \ No newline at end of file +.scrutinizer.yml export-ignore +/codeception.yml export-ignore +/phpunit.xml export-ignore +/CHANGELOG.md export-ignore +/CONTRIBUTING.md export-ignore +/README.md export-ignore From 6c054dbf35b528a5d99c12fba79acfc4ff7be825 Mon Sep 17 00:00:00 2001 From: Vincent Klaiber Date: Thu, 3 Dec 2015 14:30:37 +0100 Subject: [PATCH 085/444] Rename license file --- license.txt => LICENSE | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename license.txt => LICENSE (100%) diff --git a/license.txt b/LICENSE similarity index 100% rename from license.txt rename to LICENSE From 5ab91d7345d66d91bae6d22b869e2f49bc600044 Mon Sep 17 00:00:00 2001 From: Vincent Klaiber Date: Thu, 3 Dec 2015 14:33:05 +0100 Subject: [PATCH 086/444] Rename phpunit.xml file --- .gitattributes | 2 +- .gitignore | 3 ++- phpunit.xml => phpunit.xml.dist | 0 3 files changed, 3 insertions(+), 2 deletions(-) rename phpunit.xml => phpunit.xml.dist (100%) diff --git a/.gitattributes b/.gitattributes index 815391c2..58a5e5e6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,7 +8,7 @@ .travis.yml export-ignore .scrutinizer.yml export-ignore /codeception.yml export-ignore -/phpunit.xml export-ignore +/phpunit.xml.dist export-ignore /CHANGELOG.md export-ignore /CONTRIBUTING.md export-ignore /README.md export-ignore diff --git a/.gitignore b/.gitignore index dd33e3eb..1bfc2315 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /vendor /composer.lock +phpunit.xml .idea /examples/vendor -/tests/_output \ No newline at end of file +/tests/_output diff --git a/phpunit.xml b/phpunit.xml.dist similarity index 100% rename from phpunit.xml rename to phpunit.xml.dist From 8e04868320f472a1051042b6e8260aa69c6e933c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Jan 2016 13:15:17 +0000 Subject: [PATCH 087/444] Added bin/generate-crypto-key --- bin/generate-crypto-key | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 bin/generate-crypto-key diff --git a/bin/generate-crypto-key b/bin/generate-crypto-key new file mode 100644 index 00000000..3e2bbb2e --- /dev/null +++ b/bin/generate-crypto-key @@ -0,0 +1,14 @@ +#!/bin/env php + Date: Sun, 10 Jan 2016 13:15:43 +0000 Subject: [PATCH 088/444] Made generate-crypto-key executable --- bin/generate-crypto-key | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 bin/generate-crypto-key diff --git a/bin/generate-crypto-key b/bin/generate-crypto-key old mode 100644 new mode 100755 From 59080a831926d6291fbc7854ff8d25427c374263 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Jan 2016 13:15:52 +0000 Subject: [PATCH 089/444] New dependencies --- composer.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index bb83055a..015f92fb 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,10 @@ "require": { "php": ">=5.5.9", "league/event": "~2.1", - "zendframework/zend-diactoros": "~1.1" + "zendframework/zend-diactoros": "~1.1", + "namshi/jose": "^6.0", + "defuse/php-encryption": "^1.2" + }, "require-dev": { "phpunit/phpunit": "4.8.*", @@ -48,6 +51,9 @@ "lncd/oauth2": "*", "league/oauth2server": "*" }, + "bin": [ + "bin/generate-crypto-key" + ], "autoload": { "psr-4": { "League\\OAuth2\\Server\\": "src/" From a9313e76d4d6e38dad14b99d51a989e43f4a2ba0 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 22:56:10 +0000 Subject: [PATCH 090/444] Removed old JsonWebTokenType response as all tokens are JWTs now --- src/ResponseTypes/JsonWebTokenType.php | 125 ------------------------- 1 file changed, 125 deletions(-) delete mode 100644 src/ResponseTypes/JsonWebTokenType.php diff --git a/src/ResponseTypes/JsonWebTokenType.php b/src/ResponseTypes/JsonWebTokenType.php deleted file mode 100644 index 7ea5051a..00000000 --- a/src/ResponseTypes/JsonWebTokenType.php +++ /dev/null @@ -1,125 +0,0 @@ - $this->accessToken->getIdentifier(), - 'token_type' => 'Bearer', - 'expires_in' => $this->accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp() - ]; - - if (!is_null($this->getParam('refresh_token'))) { - $return['refresh_token'] = $this->getParam('refresh_token'); - } - - $return['id_token'] = $this->generateJWT(); - - return $return; - } - - /** - * Generate an JWT - * @return string - */ - public function generateJWT() - { - $now = new \DateTime(); - - $token = [ - 'iss' => self::$issuer, - 'aud' => self::$audience, - 'sub' => $this->accessToken->getOwnerIdentifier(), - 'exp' => $this->accessToken->getExpiryDateTime()->getTimestamp(), - 'nbf' => $now->getTimestamp(), - 'iat' => $now->getTimestamp(), - 'jti' => SecureKey::generate() - ]; - - return JWT::encode($token, self::$encryptionKey); - } - - /** - * @return \Symfony\Component\HttpFoundation\Response - */ - public function generateHttpResponse() - { - return new Response( - json_encode([ - $this->generateResponse() - ]), - 200, - [ - 'Content-type' => 'application/json', - 'Cache-Control' => 'no-store', - 'Pragma' => 'no-cache' - ] - ); - } - - /** - * Determine the access token in the authorization header - * - * @param \Symfony\Component\HttpFoundation\Request $request - * - * @return string - */ - public function determineAccessTokenInHeader(Request $request) - { - // TODO: Implement determineAccessTokenInHeader() method. - } -} From f9c0cb08e0489ccaf56bc19ce54bda8caf7d6ee4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 22:58:25 +0000 Subject: [PATCH 091/444] Removed unused code --- bin/generate-crypto-key | 14 -------------- examples/public/jwt.php | 40 ---------------------------------------- 2 files changed, 54 deletions(-) delete mode 100755 bin/generate-crypto-key delete mode 100644 examples/public/jwt.php diff --git a/bin/generate-crypto-key b/bin/generate-crypto-key deleted file mode 100755 index 3e2bbb2e..00000000 --- a/bin/generate-crypto-key +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/env php -addRepository(new ClientRepository()); -$server->addRepository(new ScopeRepository()); -$server->addRepository(new AccessTokenRepository()); -$server->addRepository(new UserRepository()); - -// Enable the password grant, respond with JWTs -$server->enableGrantType('PasswordGrant', new JsonWebTokenType()); - -// Setup JWT params -JsonWebTokenType::setIssuer('http://example.com/'); -JsonWebTokenType::setAudience('http://myawesomeapp.com/'); -JsonWebTokenType::setEncryptionKey('foobar123'); - -// Setup app + routing -$application = new \Proton\Application(); -$application->post('/access_token', function (Request $request) use ($server) { - try { - return $server->getAccessTokenResponse($request); - } catch (OAuthException $e) { - return $e->generateHttpResponse(); - } -}); - -// Run the app -$application->run(); From 3fcba9339dd6f302ffe996a421492037682ada6f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 22:58:45 +0000 Subject: [PATCH 092/444] Updated composer.json --- composer.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 015f92fb..ba45b8a6 100644 --- a/composer.json +++ b/composer.json @@ -8,8 +8,7 @@ "league/event": "~2.1", "zendframework/zend-diactoros": "~1.1", "namshi/jose": "^6.0", - "defuse/php-encryption": "^1.2" - + "lcobucci/jwt": "^3.1" }, "require-dev": { "phpunit/phpunit": "4.8.*", @@ -51,9 +50,6 @@ "lncd/oauth2": "*", "league/oauth2server": "*" }, - "bin": [ - "bin/generate-crypto-key" - ], "autoload": { "psr-4": { "League\\OAuth2\\Server\\": "src/" From 758471ec16f2040672a9b6d11af88e5aee7adb90 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 22:59:00 +0000 Subject: [PATCH 093/444] Fixed docblock --- src/Grant/GrantTypeInterface.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index f521452f..fbaa88a1 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -36,11 +36,11 @@ interface GrantTypeInterface public function respondsWith(); /** - * Return an access token + * Respond to an incoming request * * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType - * @param \DateInterval $accessTokenTTL + * @param \DateInterval $tokenTTL * @param string $scopeDelimiter * * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface @@ -48,7 +48,7 @@ interface GrantTypeInterface public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - DateInterval $accessTokenTTL, + DateInterval $tokenTTL, $scopeDelimiter = ' ' ); From 9958e1bf806225e54b2a22755836dc75f3418405 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 22:59:14 +0000 Subject: [PATCH 094/444] Added serverError exception --- src/Exception/OAuthServerException.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 953f8499..a4575a10 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -163,6 +163,18 @@ class OAuthServerException extends \Exception return new static('The user credentials were incorrect.', 'invalid_credentials', 401); } + /** + * Server error + * + * @param $hint + * + * @return static + */ + public static function serverError($hint) + { + return new static('\'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.', 'server_errror', 500, $hint); + } + /** * @return string */ From 5f9feda80c3cfb7e44b1ddfe5bc067a03becfb55 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 22:59:33 +0000 Subject: [PATCH 095/444] ScopeEntity is JsonSerializable --- src/Entities/Interfaces/ScopeEntityInterface.php | 2 +- src/Entities/ScopeEntity.php | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Entities/Interfaces/ScopeEntityInterface.php b/src/Entities/Interfaces/ScopeEntityInterface.php index b1c40537..b4ce04ac 100644 --- a/src/Entities/Interfaces/ScopeEntityInterface.php +++ b/src/Entities/Interfaces/ScopeEntityInterface.php @@ -1,7 +1,7 @@ getIdentifier(); + } } From 6339524c866af82e208dc9441b32d59c265f506e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 23:00:05 +0000 Subject: [PATCH 096/444] Updated RefreshToken methods --- .../RefreshTokenEntityInterface.php | 33 +++++++++++++-- src/Entities/RefreshTokenEntity.php | 2 +- src/Entities/Traits/RefreshTokenTrait.php | 41 +++++++++++++++---- 3 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/Entities/Interfaces/RefreshTokenEntityInterface.php b/src/Entities/Interfaces/RefreshTokenEntityInterface.php index f6c91b97..a095d4a1 100644 --- a/src/Entities/Interfaces/RefreshTokenEntityInterface.php +++ b/src/Entities/Interfaces/RefreshTokenEntityInterface.php @@ -1,17 +1,42 @@ originalAccessToken = $accessToken; + $this->accessToken = $accessToken; } /** - * Get the access token that the refresh token was originally associated with - * @return \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface + * @inheritdoc */ - public function getOriginalAccessToken() + public function getAccessToken() { - return $this->originalAccessToken; + return $this->accessToken; + } + + /** + * Get the token's expiry date time + * @return DateTime + */ + public function getExpiryDateTime() + { + return $this->expiryDateTime; + } + + /** + * Set the date time when the token expires + * + * @param DateTime $dateTime + */ + public function setExpiryDateTime(DateTime $dateTime) + { + $this->expiryDateTime = $dateTime; } } \ No newline at end of file From fd47712060f77051ab361f33bd048431f8b71708 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 23:01:19 +0000 Subject: [PATCH 097/444] Removed unused methods --- src/ResponseTypes/ResponseTypeInterface.php | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/ResponseTypes/ResponseTypeInterface.php b/src/ResponseTypes/ResponseTypeInterface.php index 039cf342..fef9cb59 100644 --- a/src/ResponseTypes/ResponseTypeInterface.php +++ b/src/ResponseTypes/ResponseTypeInterface.php @@ -12,6 +12,7 @@ namespace League\OAuth2\Server\ResponseTypes; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -23,21 +24,9 @@ interface ResponseTypeInterface public function setAccessToken(AccessTokenEntityInterface $accessToken); /** - * Set a key/value response pair - * - * @param string $key - * @param mixed $value + * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshToken */ - public function setParam($key, $value); - - /** - * Get a key from the response array - * - * @param string $key - * - * @return mixed - */ - public function getParam($key); + public function setRefreshToken(RefreshTokenEntityInterface $refreshToken); /** * Determine the access token in the authorization header From 1bdad3ad143342f2ebe54355c7b194523a351878 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 23:01:55 +0000 Subject: [PATCH 098/444] Updated AbstractResponseType with interface methods --- src/ResponseTypes/AbstractResponseType.php | 28 ++++++++++++---------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/ResponseTypes/AbstractResponseType.php b/src/ResponseTypes/AbstractResponseType.php index ed85c1c4..bed080fd 100644 --- a/src/ResponseTypes/AbstractResponseType.php +++ b/src/ResponseTypes/AbstractResponseType.php @@ -12,15 +12,14 @@ namespace League\OAuth2\Server\ResponseTypes; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; abstract class AbstractResponseType implements ResponseTypeInterface { /** - * Response array for JSON serialization - * - * @var array + * @var string */ - protected $response = []; + protected $pathToPrivateKey; /** * @var \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface @@ -28,19 +27,16 @@ abstract class AbstractResponseType implements ResponseTypeInterface protected $accessToken; /** - * {@inheritdoc} + * @var \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface */ - public function setParam($key, $value) - { - $this->response[$key] = $value; - } + protected $refreshToken; /** - * {@inheritdoc} + * @param string $pathToPrivateKey */ - public function getParam($key) + public function __construct($pathToPrivateKey) { - return isset($this->response[$key]) ? $this->response[$key] : null; + $this->pathToPrivateKey = $pathToPrivateKey; } /** @@ -50,4 +46,12 @@ abstract class AbstractResponseType implements ResponseTypeInterface { $this->accessToken = $accessToken; } + + /** + * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshToken + */ + public function setRefreshToken(RefreshTokenEntityInterface $refreshToken) + { + $this->refreshToken = $refreshToken; + } } From b8732a2f8382c0611fb47b7cf9a649afa36f41a5 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 23:02:45 +0000 Subject: [PATCH 099/444] BearerTokenResponse now outputs JWTs. Fixes #209 --- src/ResponseTypes/BearerTokenResponse.php | 38 ++++++++++++++++++----- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index 3ee5671f..4bded1a7 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -11,6 +11,10 @@ namespace League\OAuth2\Server\ResponseTypes; +use Lcobucci\JWT\Builder; +use Lcobucci\JWT\Signer\Key; +use Lcobucci\JWT\Signer\Rsa\Sha256; +use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use Psr\Http\Message\ServerRequestInterface; use Zend\Diactoros\Response; @@ -21,14 +25,34 @@ class BearerTokenResponse extends AbstractResponseType */ public function generateHttpResponse() { - $values = [ - 'access_token' => $this->accessToken->getIdentifier(), + $jwtAccessToken = (new Builder())->setAudience($this->accessToken->getClient()->getIdentifier()) + ->setId($this->accessToken->getIdentifier(), true) + ->setIssuedAt(time()) + ->setNotBefore(time()) + ->setExpiration($this->accessToken->getExpiryDateTime()->getTimestamp()) + ->set('uid', $this->accessToken->getUserIdentifier()) + ->set('scopes', $this->accessToken->getScopes()) + ->sign(new Sha256(), new Key($this->pathToPrivateKey)) + ->getToken(); + + $responseParams = [ 'token_type' => 'Bearer', - 'expires_in' => $this->accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp() + 'expires_in' => $this->accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp(), + 'access_token' => (string) $jwtAccessToken, ]; - if (!is_null($this->getParam('refresh_token'))) { - $values['refresh_token'] = $this->getParam('refresh_token'); + if ($this->refreshToken instanceof RefreshTokenEntityInterface) { + $jwtRefreshToken = (new Builder())->setAudience($this->accessToken->getClient()->getIdentifier()) + ->setId($this->refreshToken->getIdentifier()) + ->setIssuedAt(time()) + ->setNotBefore(time()) + ->setExpiration($this->refreshToken->getExpiryDateTime()->getTimestamp()) + ->set('accessToken', $this->accessToken->getIdentifier()) + ->set('scopes', $this->accessToken->getScopes()) + ->sign(new Sha256(), new Key($this->pathToPrivateKey)) + ->getToken(); + + $responseParams['refresh_token'] = (string) $jwtRefreshToken; } $response = new Response( @@ -40,7 +64,7 @@ class BearerTokenResponse extends AbstractResponseType 'content-type' => 'application/json;charset=UTF-8' ] ); - $response->getBody()->write(json_encode($values)); + $response->getBody()->write(json_encode($responseParams)); return $response; } @@ -53,8 +77,6 @@ class BearerTokenResponse extends AbstractResponseType $header = $request->getHeader('authorization'); $accessToken = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header)); - // ^(?:\s+)?Bearer\s([a-zA-Z0-9-._~+/=]*) - return ($accessToken === 'Bearer') ? '' : $accessToken; } } From 2a20de991bb331bb008cd4c8a671f7a538381f6c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 23:02:54 +0000 Subject: [PATCH 100/444] Docblock update --- src/Repositories/AccessTokenRepositoryInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Repositories/AccessTokenRepositoryInterface.php b/src/Repositories/AccessTokenRepositoryInterface.php index 13d0c5da..26ccb5a6 100644 --- a/src/Repositories/AccessTokenRepositoryInterface.php +++ b/src/Repositories/AccessTokenRepositoryInterface.php @@ -38,7 +38,7 @@ interface AccessTokenRepositoryInterface extends RepositoryInterface public function getScopeEntitiesAssociatedWithAccessToken(AccessTokenEntityInterface $token); /** - * Persists a new access token to storage + * Persists a new access token to permanent storage * * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessTokenEntity */ From e03ad0d52f5300b38a8eeef7882ef7110c985587 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 23:03:24 +0000 Subject: [PATCH 101/444] Server constructor expects path to private key --- src/Server.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Server.php b/src/Server.php index b4e6625b..b18bddf4 100644 --- a/src/Server.php +++ b/src/Server.php @@ -48,10 +48,12 @@ class Server implements EmitterAwareInterface /** * New server instance + * + * @param string $pathToPrivateKey */ - public function __construct() + public function __construct($pathToPrivateKey) { - $this->setDefaultResponseType(new BearerTokenResponse()); + $this->setDefaultResponseType(new BearerTokenResponse($pathToPrivateKey)); $this->setDefaultAccessTokenTTL(new DateInterval('PT01H')); // default token TTL of 1 hour } @@ -89,7 +91,7 @@ class Server implements EmitterAwareInterface * Enable a grant type on the server * * @param \League\OAuth2\Server\Grant\GrantTypeInterface $grantType - * @param ResponseTypeInterface $responseType + * @param ResponseTypeInterface $responseType * @param DateInterval $accessTokenTTL */ public function enableGrantType( From de89a6bc89f433d39c0fde4ecd789c22312c4bdc Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 23:03:38 +0000 Subject: [PATCH 102/444] Code tidy --- src/Grant/PasswordGrant.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index dc27f212..2bce9d03 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -155,13 +155,9 @@ class PasswordGrant extends AbstractGrant */ public function canRespondToRequest(ServerRequestInterface $request) { - if ( + return ( isset($request->getParsedBody()['grant_type']) && $request->getParsedBody()['grant_type'] === 'password' - ) { - return true; - } - - return false; + ); } } From 6358be90c27a56570cf87a4af31bf357c5d6e07a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 23:04:03 +0000 Subject: [PATCH 103/444] Token is now linked to a user identifier instead of owner concept --- src/Entities/Traits/TokenEntityTrait.php | 40 +++++++++--------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/src/Entities/Traits/TokenEntityTrait.php b/src/Entities/Traits/TokenEntityTrait.php index e55cc2eb..d16e6f8d 100644 --- a/src/Entities/Traits/TokenEntityTrait.php +++ b/src/Entities/Traits/TokenEntityTrait.php @@ -17,15 +17,10 @@ trait TokenEntityTrait */ protected $expiryDateTime; - /** - * @var string - */ - protected $ownerType; - /** * @var string|int */ - protected $ownerIdentifier; + protected $userIdentifier; /** * @var ClientEntityInterface @@ -34,6 +29,7 @@ trait TokenEntityTrait /** * Associate a scope with the token + * * @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface $scope */ public function addScope(ScopeEntityInterface $scope) @@ -43,7 +39,9 @@ trait TokenEntityTrait /** * Get an associated scope by the scope's identifier + * * @param string $identifier + * * @return ScopeEntityInterface|null The scope or null if not found */ public function getScopeWithIdentifier($identifier) @@ -57,7 +55,7 @@ trait TokenEntityTrait */ public function getScopes() { - return $this->scopes; + return array_values($this->scopes); } /** @@ -71,6 +69,7 @@ trait TokenEntityTrait /** * Set the date time when the token expires + * * @param DateTime $dateTime */ public function setExpiryDateTime(DateTime $dateTime) @@ -79,32 +78,22 @@ trait TokenEntityTrait } /** - * Set the token's owner - * @param string $type The type of the owner (e.g. "user", "client" or something more specific) - * @param string|int $identifier The identifier of the owner + * Set the identifier of the user associated with the token + * + * @param string|int $identifier The identifier of the user */ - public function setOwner($type, $identifier) + public function setUserIdentifier($identifier) { - $this->ownerType = $type; - $this->ownerIdentifier = $identifier; + $this->userIdentifier = $identifier; } /** - * Get the token owner's type - * @return string The type of owner (e.g. "user", "client" or something more specific) - */ - public function getOwnerType() - { - return $this->ownerType; - } - - /** - * Get the token owner's identifier + * Get the token user's identifier * @return string|int */ - public function getOwnerIdentifier() + public function getUserIdentifier() { - return $this->ownerIdentifier; + return $this->userIdentifier; } /** @@ -118,6 +107,7 @@ trait TokenEntityTrait /** * Set the client that the token was issued to + * * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client */ public function setClient(ClientEntityInterface $client) From 13a1ea6db8aa5b5ab3ecbab4a6c581710e00ab5b Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 23:04:33 +0000 Subject: [PATCH 104/444] Updated token interface to drop owner concept for simple user identifier --- src/Entities/Interfaces/TokenInterface.php | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/Entities/Interfaces/TokenInterface.php b/src/Entities/Interfaces/TokenInterface.php index 89e223ac..12183c8e 100644 --- a/src/Entities/Interfaces/TokenInterface.php +++ b/src/Entities/Interfaces/TokenInterface.php @@ -28,23 +28,17 @@ interface TokenInterface public function setExpiryDateTime(\DateTime $dateTime); /** - * Set the token's owner - * @param string $type The type of the owner (e.g. "user", "client" or something more specific) - * @param string|int $identifier The identifier of the owner + * Set the identifier of the user associated with the token + * + * @param string|int $identifier The identifier of the user */ - public function setOwner($type, $identifier); + public function setUserIdentifier($identifier); /** - * Get the token owner's type - * @return string The type of owner (e.g. "user", "client" or something more specific) - */ - public function getOwnerType(); - - /** - * Get the token owner's identifier + * Get the token user's identifier * @return string|int */ - public function getOwnerIdentifier(); + public function getUserIdentifier(); /** * Get the client that the token was issued to From d565665ccb7acc3f496de76d899fbfb418314081 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 23:05:07 +0000 Subject: [PATCH 105/444] Code tidy --- src/Grant/ClientCredentialsGrant.php | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index c6972309..7ae88aa7 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -86,7 +86,7 @@ class ClientCredentialsGrant extends AbstractGrant $accessToken->setIdentifier(SecureKey::generate()); $accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL)); $accessToken->setClient($client); - $accessToken->setOwner('client', $client->getIdentifier()); + $accessToken->setUserIdentifier($client->getIdentifier()); // Associate scopes with the session and access token foreach ($scopes as $scope) { @@ -103,26 +103,13 @@ class ClientCredentialsGrant extends AbstractGrant } /** - * The grant type should return true if it is able to respond to this request. - * - * For example most grant types will check that the $_POST['grant_type'] property matches it's identifier property. - * - * Some grants, such as the authorization code grant can respond to multiple requests - * - i.e. a client requesting an authorization code and requesting an access token - * - * @param \Psr\Http\Message\ServerRequestInterface $request - * - * @return boolean + * @inheritdoc */ public function canRespondToRequest(ServerRequestInterface $request) { - if ( - isset($request->getParsedBody()['grant_type']) + return ( + array_key_exists('grant_type', $request->getParsedBody()) && $request->getParsedBody()['grant_type'] === 'client_credentials' - ) { - return true; - } - - return false; + ); } } From 3135f1796e0bbbe4d24900b1f3164f390d80b651 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 23:05:19 +0000 Subject: [PATCH 106/444] Generate a refresh token in password grant --- src/Grant/PasswordGrant.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 2bce9d03..759f337f 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -16,6 +16,7 @@ use League\Event\Event; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -134,18 +135,25 @@ class PasswordGrant extends AbstractGrant $accessToken->setIdentifier(SecureKey::generate()); $accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL)); $accessToken->setClient($client); - $accessToken->setOwner('user', $userEntity->getIdentifier()); + $accessToken->setUserIdentifier($userEntity->getIdentifier()); // Associate scopes with the session and access token foreach ($scopes as $scope) { $accessToken->addScope($scope); } - // Save the token + // Persist the token $this->accessTokenRepository->persistNewAccessToken($accessToken); - // Inject access token into token type + // Generate a refresh token + $refreshToken = new RefreshTokenEntity(); + $refreshToken->setIdentifier(SecureKey::generate()); + $refreshToken->setExpiryDateTime((new \DateTime())->add(new DateInterval('P1M'))); + $refreshToken->setAccessToken($accessToken); + + // Inject tokens into response $responseType->setAccessToken($accessToken); + $responseType->setRefreshToken($refreshToken); return $responseType; } From a2bbb17483d7134b0193375bde3614e24e35cd0f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 23:52:08 +0000 Subject: [PATCH 107/444] Updated repository method names --- .../AccessTokenRepositoryInterface.php | 37 ++++--------------- .../RefreshTokenRepositoryInterface.php | 32 +++++++--------- 2 files changed, 22 insertions(+), 47 deletions(-) diff --git a/src/Repositories/AccessTokenRepositoryInterface.php b/src/Repositories/AccessTokenRepositoryInterface.php index 26ccb5a6..f39351ff 100644 --- a/src/Repositories/AccessTokenRepositoryInterface.php +++ b/src/Repositories/AccessTokenRepositoryInterface.php @@ -12,31 +12,12 @@ namespace League\OAuth2\Server\Repositories; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; /** * Access token interface */ interface AccessTokenRepositoryInterface extends RepositoryInterface { - /** - * Get an instance of Entity\AccessTokenEntity - * - * @param string $token The access token identifier - * - * @return \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface - */ - public function getAccessTokenEntityByTokenString($token); - - /** - * Get the scopes for an access token - * - * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $token - * - * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] - */ - public function getScopeEntitiesAssociatedWithAccessToken(AccessTokenEntityInterface $token); - /** * Persists a new access token to permanent storage * @@ -45,20 +26,18 @@ interface AccessTokenRepositoryInterface extends RepositoryInterface public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity); /** - * Associate a scope with an access token + * Revoke an access token * - * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessTokenEntityInterface - * @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface $scope + * @param string $tokenId */ - public function associateScopeWithAccessToken( - AccessTokenEntityInterface $accessTokenEntityInterface, - ScopeEntityInterface $scope - ); + public function revokeAccessToken($tokenId); /** - * Delete an access token + * Check if the access token has been revoked * - * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken + * @param string $tokenId + * + * @return bool Return true if this token has been revoked */ - public function deleteAccessToken(AccessTokenEntityInterface $accessToken); + public function isAccessTokenRevoked($tokenId); } diff --git a/src/Repositories/RefreshTokenRepositoryInterface.php b/src/Repositories/RefreshTokenRepositoryInterface.php index bf3e2c8e..1ac9a0d1 100644 --- a/src/Repositories/RefreshTokenRepositoryInterface.php +++ b/src/Repositories/RefreshTokenRepositoryInterface.php @@ -18,30 +18,26 @@ use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; */ interface RefreshTokenRepositoryInterface extends RepositoryInterface { - /** - * Return a new instance of \League\OAuth2\Server\Entity\RefreshTokenEntity - * - * @param string $token Refresh token string - * - * @return \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface - */ - public function getRefreshTokenEntityByTokenString($token); - /** * Create a new refresh token_name * - * @param string $token - * @param integer $expireTime - * @param string $accessToken - * - * @return \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface + * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshTokenEntityInterface */ - public function persistNewRefreshTokenEntity($token, $expireTime, $accessToken); + public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntityInterface); /** - * Delete the refresh token + * Revoke the refresh token * - * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $token + * @param string $tokenId */ - public function deleteRefreshTokenEntity(RefreshTokenEntityInterface $token); + public function revokeRefreshToken($tokenId); + + /** + * Check if the refresh token has been revoked + * + * @param string $tokenId + * + * @return bool Return true if this token has been revoked + */ + public function isRefreshTokenRevoked($tokenId); } From 6fb3fb5110a5d34a0c2a0d6a3643f52899316c49 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Jan 2016 23:53:03 +0000 Subject: [PATCH 108/444] Updated refresh token grant --- src/Grant/RefreshTokenGrant.php | 234 ++++++++++++++++---------------- 1 file changed, 117 insertions(+), 117 deletions(-) diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 3357ed5d..f8e5779b 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -11,12 +11,23 @@ namespace League\OAuth2\Server\Grant; -use League\OAuth2\Server\Entity\AccessTokenEntity; -use League\OAuth2\Server\Entity\ClientEntity; -use League\OAuth2\Server\Entity\RefreshTokenEntity; -use League\OAuth2\Server\Event; -use League\OAuth2\Server\Exception; -use League\OAuth2\Server\Util\SecureKey; +use DateInterval; +use Lcobucci\JWT\Parser; +use Lcobucci\JWT\Signer\Key; +use Lcobucci\JWT\Signer\Rsa\Sha256; +use Lcobucci\JWT\ValidationData; +use League\OAuth2\Server\Entities\AccessTokenEntity; +use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntity; +use League\OAuth2\Server\Exception\OAuthServerException; +use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; +use League\OAuth2\Server\Utils\SecureKey; +use Psr\Http\Message\ServerRequestInterface; +use Symfony\Component\EventDispatcher\Event; /** * Refresh token grant @@ -24,120 +35,105 @@ use League\OAuth2\Server\Util\SecureKey; class RefreshTokenGrant extends AbstractGrant { /** - * {@inheritdoc} + * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface */ - protected $identifier = 'refresh_token'; + private $refreshTokenRepository; + /** + * @var string + */ + private $pathToPublicKey; /** - * Refresh token TTL (default = 604800 | 1 week) - * - * @var integer + * @param string $pathToPublicKey + * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository + * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository + * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository + * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository */ - protected $refreshTokenTTL = 604800; - - /** - * Rotate token (default = true) - * - * @var integer - */ - protected $refreshTokenRotate = true; - - /** - * Set the TTL of the refresh token - * - * @param int $refreshTokenTTL - * - * @return void - */ - public function setRefreshTokenTTL($refreshTokenTTL) - { - $this->refreshTokenTTL = $refreshTokenTTL; + public function __construct( + $pathToPublicKey, + ClientRepositoryInterface $clientRepository, + ScopeRepositoryInterface $scopeRepository, + AccessTokenRepositoryInterface $accessTokenRepository, + RefreshTokenRepositoryInterface $refreshTokenRepository + ) { + $this->pathToPublicKey = $pathToPublicKey; + $this->refreshTokenRepository = $refreshTokenRepository; + parent::__construct($clientRepository, $scopeRepository, $accessTokenRepository); } /** - * Get the TTL of the refresh token - * - * @return int + * @inheritdoc */ - public function getRefreshTokenTTL() - { - return $this->refreshTokenTTL; - } + public function respondToRequest( + ServerRequestInterface $request, + ResponseTypeInterface $responseType, + DateInterval $tokenTTL, + $scopeDelimiter = ' ' + ) { + // Get the required params + $clientId = isset($request->getParsedBody()['client_id']) + ? $request->getParsedBody()['client_id'] // $_POST['client_id'] + : (isset($request->getServerParams()['PHP_AUTH_USER']) + ? $request->getServerParams()['PHP_AUTH_USER'] // $_SERVER['PHP_AUTH_USER'] + : null); - /** - * Set the rotation boolean of the refresh token - * @param bool $refreshTokenRotate - */ - public function setRefreshTokenRotation($refreshTokenRotate = true) - { - $this->refreshTokenRotate = $refreshTokenRotate; - } - - /** - * Get rotation boolean of the refresh token - * - * @return bool - */ - public function shouldRotateRefreshTokens() - { - return $this->refreshTokenRotate; - } - - /** - * {@inheritdoc} - */ - public function completeFlow() - { - $clientId = $this->server->getRequest()->request->get('client_id', $this->server->getRequest()->getUser()); if (is_null($clientId)) { - throw new Exception\InvalidRequestException('client_id'); + throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); } - $clientSecret = $this->server->getRequest()->request->get('client_secret', - $this->server->getRequest()->getPassword()); + $clientSecret = isset($request->getParsedBody()['client_secret']) + ? $request->getParsedBody()['client_secret'] // $_POST['client_id'] + : (isset($request->getServerParams()['PHP_AUTH_PW']) + ? $request->getServerParams()['PHP_AUTH_PW'] // $_SERVER['PHP_AUTH_USER'] + : null); + if (is_null($clientSecret)) { - throw new Exception\InvalidRequestException('client_secret'); + throw OAuthServerException::invalidRequest('client_secret', null, '`%s` parameter is missing'); + } + + $refreshTokenJwt = isset($request->getParsedBody()['refresh_token']) + ? $request->getParsedBody()['refresh_token'] + : null; + + if ($refreshTokenJwt === null) { + throw OAuthServerException::invalidRequest('refresh_token', null, '`%s` parameter is missing'); } // Validate client ID and client secret - $client = $this->server->getClientStorage()->get( + $client = $this->clientRepository->getClientEntity( $clientId, $clientSecret, null, $this->getIdentifier() ); - if (($client instanceof ClientEntity) === false) { - $this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($this->server->getRequest())); - throw new Exception\InvalidClientException(); - } - - $oldRefreshTokenParam = $this->server->getRequest()->request->get('refresh_token', null); - if ($oldRefreshTokenParam === null) { - throw new Exception\InvalidRequestException('refresh_token'); + if (($client instanceof ClientEntityInterface) === false) { + $this->emitter->emit(new Event('client.authentication.failed', $request)); + throw OAuthServerException::invalidClient(); } // Validate refresh token - $oldRefreshToken = $this->server->getRefreshTokenStorage()->get($oldRefreshTokenParam); - - if (($oldRefreshToken instanceof RefreshTokenEntity) === false) { - throw new Exception\InvalidRefreshException(); + $oldRefreshToken = (new Parser())->parse($refreshTokenJwt); + if ($oldRefreshToken->verify(new Sha256(), new Key($this->pathToPublicKey)) === false) { + throw OAuthServerException::invalidRefreshToken(); } - // Ensure the old refresh token hasn't expired - if ($oldRefreshToken->isExpired() === true) { - throw new Exception\InvalidRefreshException(); + $validation = new ValidationData(); + $validation->setAudience($client->getIdentifier()); + $validation->setCurrentTime(time()); + if ($oldRefreshToken->validate($validation) === false) { + throw OAuthServerException::invalidRefreshToken(); } - $oldAccessToken = $oldRefreshToken->getAccessToken(); - // Get the scopes for the original session - $session = $oldAccessToken->getSession(); - $scopes = $this->formatScopes($session->getScopes()); + $scopes = $oldRefreshToken->getClaim('scopes'); // Get and validate any requested scopes - $requestedScopesString = $this->server->getRequest()->request->get('scope', ''); - $requestedScopes = $this->validateScopes($requestedScopesString, $client); + $scopeParam = isset($request->getParsedBody()['scope']) + ? $request->getParsedBody()['scope'] // $_POST['scope'] + : ''; + $requestedScopes = $this->validateScopes($scopeParam, $scopeDelimiter, $client); // If no new scopes are requested then give the access token the original session scopes if (count($requestedScopes) === 0) { @@ -146,48 +142,52 @@ class RefreshTokenGrant extends AbstractGrant // 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 foreach ($requestedScopes as $requestedScope) { - if (!isset($scopes[$requestedScope->getId()])) { - throw new Exception\InvalidScopeException($requestedScope->getId()); + if (!isset($scopes[$requestedScope->getIdentifier()])) { + throw OAuthServerException::invalidScope($requestedScope->getIdentifier()); } } $newScopes = $requestedScopes; } - // Generate a new access token and assign it the correct sessions - $newAccessToken = new AccessTokenEntity($this->server); - $newAccessToken->setId(SecureKey::generate()); - $newAccessToken->setExpireTime($this->getAccessTokenTTL() + time()); - $newAccessToken->setSession($session); - - foreach ($newScopes as $newScope) { - $newAccessToken->associateScope($newScope); + // Generate a new access token + $accessToken = new AccessTokenEntity(); + $accessToken->setIdentifier(SecureKey::generate()); + $accessToken->setExpiryDateTime((new \DateTime())->add($tokenTTL)); + $accessToken->setClient($client); + $accessToken->setUserIdentifier($oldRefreshToken->getClaim('uid')); + foreach ($newScopes as $scope) { + $accessToken->addScope($scope); } // Expire the old token and save the new one - $oldAccessToken->expire(); - $newAccessToken->save(); + $this->accessTokenRepository->revokeAccessToken($oldRefreshToken->getClaim('accessToken')); - $this->server->getTokenType()->setSession($session); - $this->server->getTokenType()->setParam('access_token', $newAccessToken->getId()); - $this->server->getTokenType()->setParam('expires_in', $this->getAccessTokenTTL()); + // Generate a new refresh token + $refreshToken = new RefreshTokenEntity(); + $refreshToken->setIdentifier(SecureKey::generate()); + $refreshToken->setExpiryDateTime((new \DateTime())->add(new DateInterval('P1M'))); + $refreshToken->setAccessToken($accessToken); - if ($this->shouldRotateRefreshTokens()) { - // Expire the old refresh token - $oldRefreshToken->expire(); + // Persist the tokens + $this->accessTokenRepository->persistNewAccessToken($accessToken); + $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); - // Generate a new refresh token - $newRefreshToken = new RefreshTokenEntity($this->server); - $newRefreshToken->setId(SecureKey::generate()); - $newRefreshToken->setExpireTime($this->getRefreshTokenTTL() + time()); - $newRefreshToken->setAccessToken($newAccessToken); - $newRefreshToken->save(); + // Inject tokens into response + $responseType->setAccessToken($accessToken); + $responseType->setRefreshToken($refreshToken); - $this->server->getTokenType()->setParam('refresh_token', $newRefreshToken->getId()); - } else { - $this->server->getTokenType()->setParam('refresh_token', $oldRefreshToken->getId()); - } + return $responseType; + } - return $this->server->getTokenType()->generateResponse(); + /** + * @inheritdoc + */ + public function canRespondToRequest(ServerRequestInterface $request) + { + return ( + isset($request->getParsedBody()['grant_type']) + && $request->getParsedBody()['grant_type'] === 'refresh_token' + ); } } From eef5cf39d4605d6d6884638855a9dcdb7ec26b18 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 13 Jan 2016 00:12:10 +0000 Subject: [PATCH 109/444] Fixes to refresh grant --- src/Grant/RefreshTokenGrant.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index f8e5779b..e3ba3029 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -114,9 +114,13 @@ class RefreshTokenGrant extends AbstractGrant } // Validate refresh token - $oldRefreshToken = (new Parser())->parse($refreshTokenJwt); + try { + $oldRefreshToken = (new Parser())->parse($refreshTokenJwt); + } catch (\InvalidArgumentException $e) { + throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token'); + } if ($oldRefreshToken->verify(new Sha256(), new Key($this->pathToPublicKey)) === false) { - throw OAuthServerException::invalidRefreshToken(); + throw OAuthServerException::invalidRefreshToken('Cannot validate refresh token signature'); } $validation = new ValidationData(); @@ -142,7 +146,7 @@ class RefreshTokenGrant extends AbstractGrant // 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 foreach ($requestedScopes as $requestedScope) { - if (!isset($scopes[$requestedScope->getIdentifier()])) { + if (in_array($requestedScope->getIdentifier(), $scopes) === false) { throw OAuthServerException::invalidScope($requestedScope->getIdentifier()); } } From 0efa7cd7eab83c39b722d150b9d90d55c78b9443 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 13 Jan 2016 00:13:16 +0000 Subject: [PATCH 110/444] Set the uid on the refresh token --- src/ResponseTypes/BearerTokenResponse.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index 4bded1a7..cd23b8dd 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -47,8 +47,9 @@ class BearerTokenResponse extends AbstractResponseType ->setIssuedAt(time()) ->setNotBefore(time()) ->setExpiration($this->refreshToken->getExpiryDateTime()->getTimestamp()) - ->set('accessToken', $this->accessToken->getIdentifier()) + ->set('uid', $this->accessToken->getUserIdentifier()) ->set('scopes', $this->accessToken->getScopes()) + ->set('accessToken', $this->accessToken->getIdentifier()) ->sign(new Sha256(), new Key($this->pathToPrivateKey)) ->getToken(); From 79791e5848fdf192374269d9f0505c5351005f89 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 13 Jan 2016 00:13:29 +0000 Subject: [PATCH 111/444] Code tidy --- src/Grant/PasswordGrant.php | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 759f337f..fee9d798 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -20,6 +20,7 @@ use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; @@ -37,18 +38,26 @@ class PasswordGrant extends AbstractGrant private $userRepository; /** - * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository - * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository - * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository - * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository + * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface + */ + private $refreshTokenRepository; + + /** + * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository + * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository + * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository + * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository + * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository */ public function __construct( UserRepositoryInterface $userRepository, ClientRepositoryInterface $clientRepository, ScopeRepositoryInterface $scopeRepository, - AccessTokenRepositoryInterface $accessTokenRepository + AccessTokenRepositoryInterface $accessTokenRepository, + RefreshTokenRepositoryInterface $refreshTokenRepository ) { $this->userRepository = $userRepository; + $this->refreshTokenRepository = $refreshTokenRepository; parent::__construct($clientRepository, $scopeRepository, $accessTokenRepository); } @@ -58,7 +67,7 @@ class PasswordGrant extends AbstractGrant public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - DateInterval $accessTokenTTL, + DateInterval $tokenTTL, $scopeDelimiter = ' ' ) { // Get the required params @@ -133,7 +142,7 @@ class PasswordGrant extends AbstractGrant // Generate an access token $accessToken = new AccessTokenEntity(); $accessToken->setIdentifier(SecureKey::generate()); - $accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL)); + $accessToken->setExpiryDateTime((new \DateTime())->add($tokenTTL)); $accessToken->setClient($client); $accessToken->setUserIdentifier($userEntity->getIdentifier()); @@ -142,15 +151,16 @@ class PasswordGrant extends AbstractGrant $accessToken->addScope($scope); } - // Persist the token - $this->accessTokenRepository->persistNewAccessToken($accessToken); - // Generate a refresh token $refreshToken = new RefreshTokenEntity(); $refreshToken->setIdentifier(SecureKey::generate()); $refreshToken->setExpiryDateTime((new \DateTime())->add(new DateInterval('P1M'))); $refreshToken->setAccessToken($accessToken); + // Persist the tokens + $this->accessTokenRepository->persistNewAccessToken($accessToken); + $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); + // Inject tokens into response $responseType->setAccessToken($accessToken); $responseType->setRefreshToken($refreshToken); From 70e9d7b699c429ce4ecc05c740e31447b9877064 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 13 Jan 2016 00:28:52 +0000 Subject: [PATCH 112/444] Updated examples --- .gitignore | 2 + examples/README.md | 53 +++++++++++++++++- examples/public/refresh_token.php | 56 +++++++++++++++++++ .../Repositories/AccessTokenRepository.php | 54 +++++++----------- .../Repositories/RefreshTokenRepository.php | 42 ++++++++++++++ 5 files changed, 173 insertions(+), 34 deletions(-) create mode 100644 examples/public/refresh_token.php create mode 100644 examples/src/Repositories/RefreshTokenRepository.php diff --git a/.gitignore b/.gitignore index 1bfc2315..3b5992e5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ phpunit.xml .idea /examples/vendor /tests/_output +examples/public.key +examples/private.key diff --git a/examples/README.md b/examples/README.md index 884da28b..e4a30a73 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,3 +1,54 @@ # Example implementations -Just run `composer install --no-dev` in this directory to get started. \ No newline at end of file +## Installation + +0. Run `composer install --no-dev` in this directory to install dependencies +0. Create a private key `openssl genrsa -out private.key 1024` +0. Create a public key `openssl rsa -in private.key -pubout > public.key` +0. `cd` into the public directory +0. Start a PHP server `php -S localhost:4444` + +## Testing the client credentials grant example + +Send the following cURL request: + +``` +curl -X "POST" "http://localhost:4444/client_credentials.php/access_token" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -H "Accept: 1.0" \ + --data-urlencode "client_id=myawesomeapp" \ + --data-urlencode "scope=basic email" \ + --data-urlencode "client_secret=abc123" \ + --data-urlencode "grant_type=client_credentials" +``` + +## Testing the password grant example + +Send the following cURL request: + +``` +curl -X "POST" "http://localhost:4444/password.php/access_token" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -H "Accept: 1.0" \ + --data-urlencode "client_id=myawesomeapp" \ + --data-urlencode "scope=basic email" \ + --data-urlencode "username=alex" \ + --data-urlencode "password=whisky" \ + --data-urlencode "client_secret=abc123" \ + --data-urlencode "grant_type=password" +``` + +## Testing the refresh token grant example + +Send the following cURL request. Replace `{{REFRESH_TOKEN}}` with a refresh token from another grant above: + +``` +curl -X "POST" "http://localhost:4444/refresh_token.php/access_token" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -H "Accept: 1.0" \ + --data-urlencode "grant_type=refresh_token" \ + --data-urlencode "client_id=myawesomeapp" \ + --data-urlencode "client_secret=abc123" \ + --data-urlencode "refresh_token={{REFRESH_TOKEN}}" +``` + diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php new file mode 100644 index 00000000..75c08139 --- /dev/null +++ b/examples/public/refresh_token.php @@ -0,0 +1,56 @@ +enableGrantType($refreshTokenGrant); + +// App +$app = new App([Server::class => $server]); + +$app->post('/access_token', function (Request $request, Response $response) { + /** @var Server $server */ + $server = $this->get(Server::class); + try { + return $server->respondToRequest($request); + } catch (OAuthServerException $e) { + return $e->generateHttpResponse(); + } catch (\Exception $e) { + return $response->withStatus(500)->write( + sprintf('

%s

%s

', get_class($e), $e->getMessage()) + ); + } +}); + +$app->run(); diff --git a/examples/src/Repositories/AccessTokenRepository.php b/examples/src/Repositories/AccessTokenRepository.php index 16d8dc2b..bc8ada68 100644 --- a/examples/src/Repositories/AccessTokenRepository.php +++ b/examples/src/Repositories/AccessTokenRepository.php @@ -2,51 +2,39 @@ namespace OAuth2ServerExamples\Repositories; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; class AccessTokenRepository implements AccessTokenRepositoryInterface { - /** - * @inheritdoc - */ - public function getAccessTokenEntityByTokenString($tokenIdentifier) - { - // TODO: Implement get() method. - } - - /** - * @inheritdoc - */ - public function getScopeEntitiesAssociatedWithAccessToken(AccessTokenEntityInterface $token) - { - // TODO: Implement getScopes() method. - } - - /** - * @inheritdoc + * Persists a new access token to permanent storage + * + * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessTokenEntity */ public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity) { - // TODO: Implement create() method. + // TODO: Implement persistNewAccessToken() method. } /** - * @inheritdoc + * Revoke an access token + * + * @param string $tokenId */ - public function associateScopeWithAccessToken( - AccessTokenEntityInterface $accessTokenEntityInterface, - ScopeEntityInterface $scope - ) { - // TODO: Implement associateScope() method. - } - - /** - * @inheritdoc - */ - public function deleteAccessToken(AccessTokenEntityInterface $accessToken) + public function revokeAccessToken($tokenId) { - // TODO: Implement delete() method. + // TODO: Implement revokeAccessToken() method. + } + + /** + * Check if the access token has been revoked + * + * @param string $tokenId + * + * @return bool Return true if this token has been revoked + */ + public function isAccessTokenRevoked($tokenId) + { + // TODO: Implement isAccessTokenRevoked() method. } } diff --git a/examples/src/Repositories/RefreshTokenRepository.php b/examples/src/Repositories/RefreshTokenRepository.php new file mode 100644 index 00000000..a7a4e079 --- /dev/null +++ b/examples/src/Repositories/RefreshTokenRepository.php @@ -0,0 +1,42 @@ + Date: Wed, 13 Jan 2016 00:38:08 +0000 Subject: [PATCH 113/444] Uset sub instead of uid --- src/ResponseTypes/BearerTokenResponse.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index cd23b8dd..3e5dc7f9 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -30,7 +30,7 @@ class BearerTokenResponse extends AbstractResponseType ->setIssuedAt(time()) ->setNotBefore(time()) ->setExpiration($this->accessToken->getExpiryDateTime()->getTimestamp()) - ->set('uid', $this->accessToken->getUserIdentifier()) + ->setSubject($this->accessToken->getUserIdentifier()) ->set('scopes', $this->accessToken->getScopes()) ->sign(new Sha256(), new Key($this->pathToPrivateKey)) ->getToken(); @@ -47,7 +47,8 @@ class BearerTokenResponse extends AbstractResponseType ->setIssuedAt(time()) ->setNotBefore(time()) ->setExpiration($this->refreshToken->getExpiryDateTime()->getTimestamp()) - ->set('uid', $this->accessToken->getUserIdentifier()) + ->set('type', 'refreshToken') + ->setSubject($this->accessToken->getUserIdentifier()) ->set('scopes', $this->accessToken->getScopes()) ->set('accessToken', $this->accessToken->getIdentifier()) ->sign(new Sha256(), new Key($this->pathToPrivateKey)) From 936b8f93ecc84e2e90fbb3c34ce765aa4327a166 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 13 Jan 2016 00:38:23 +0000 Subject: [PATCH 114/444] Addititonal refresh token validation --- src/Grant/RefreshTokenGrant.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index e3ba3029..d84de59d 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -124,10 +124,14 @@ class RefreshTokenGrant extends AbstractGrant } $validation = new ValidationData(); - $validation->setAudience($client->getIdentifier()); - $validation->setCurrentTime(time()); + $validation->setAudience($client->getIdentifier()); // Validates refresh token hasn't expired + $validation->setCurrentTime(time()); // Validates token hasn't expired if ($oldRefreshToken->validate($validation) === false) { - throw OAuthServerException::invalidRefreshToken(); + throw OAuthServerException::invalidRefreshToken('Token has expired or is not linked to client'); + } + + if ($oldRefreshToken->getClaim('type') !== 'refreshToken') { + throw OAuthServerException::invalidRefreshToken('Token is not a refresh token'); } // Get the scopes for the original session @@ -159,7 +163,7 @@ class RefreshTokenGrant extends AbstractGrant $accessToken->setIdentifier(SecureKey::generate()); $accessToken->setExpiryDateTime((new \DateTime())->add($tokenTTL)); $accessToken->setClient($client); - $accessToken->setUserIdentifier($oldRefreshToken->getClaim('uid')); + $accessToken->setUserIdentifier($oldRefreshToken->getClaim('sub')); foreach ($newScopes as $scope) { $accessToken->addScope($scope); } From dc2919710cdaca5e71c4c37fb183ee6ec1ba5d09 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 13 Jan 2016 00:46:08 +0000 Subject: [PATCH 115/444] Updated README --- README.md | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 0f79c2fb..eed4d78c 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,7 @@ [![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) - -A standards compliant [OAuth 2.0](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-v2/) authorization server and resource 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. +`league/oauth2-server` is a a standards compliant implementation of an [OAuth 2.0](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-v2/) 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: @@ -19,29 +18,26 @@ It supports out of the box the following grants: You can also define your own grants. -In addition it supports the following token types: +In addition it supports the following token response types: -* Bearer tokens +* Bearer (JWT) tokens * MAC tokens -* JSON web tokens (coming soon) You can also create you own tokens. - ## Requirements The following versions of PHP are supported: -* PHP 5.4 -* PHP 5.5 +* PHP 5.5 (>=5.5.9) * PHP 5.6 +* PHP 7.0 * HHVM ## Documentation -This library has [full documentation](http://oauth2.thephpleague.com), powered by [Jekyll](http://jekyllrb.com/). - -Contribute to this documentation in the [gh-pages branch](https://github.com/thephpleague/oauth2-server/tree/gh-pages/). +The library documentation can be found at [http://oauth2.thephpleague.com)(http://oauth2.thephpleague.com). +You can contribute to this documentation in the [gh-pages branch](https://github.com/thephpleague/oauth2-server/tree/gh-pages/). ## Changelog @@ -49,7 +45,7 @@ Contribute to this documentation in the [gh-pages branch](https://github.com/the ## Contributing -Please see [CONTRIBUTING](https://github.com/thephpleague/oauth2-server/blob/master/CONTRIBUTING.md) for details. +Please see [CONTRIBUTING.md](https://github.com/thephpleague/oauth2-server/blob/master/CONTRIBUTING.md) and [CONDUCT.md](https://github.com/thephpleague/oauth2-server/blob/master/CONDUCT.md) for details. ## Support @@ -67,12 +63,6 @@ This package is released under the MIT License. See the bundled [LICENSE](https: This code is principally developed and maintained by [Alex Bilbie](https://twitter.com/alexbilbie). -Special thanks to: - -* [Dan Horrigan](https://github.com/dandoescode) -* [Nick Jackson](https://github.com/jacksonj04) -* [Michael Gooden](https://github.com/MichaelGooden) -* [Phil Sturgeon](https://github.com/philsturgeon) -* [and all the other contributors](https://github.com/thephpleague/oauth2-server/contributors) +Special thanks to [all of these awesome contributors](https://github.com/thephpleague/oauth2-server/contributors) The initial code was developed as part of the [Linkey](http://linkey.blogs.lincoln.ac.uk) project which was funded by [JISC](http://jisc.ac.uk) under the Access and Identity Management programme. From e95a22812836a38575e3258eaf7f04853097fc27 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 13 Jan 2016 00:46:18 +0000 Subject: [PATCH 116/444] Added code of conduct --- CONDUCT.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 CONDUCT.md diff --git a/CONDUCT.md b/CONDUCT.md new file mode 100644 index 00000000..ea00abfc --- /dev/null +++ b/CONDUCT.md @@ -0,0 +1,22 @@ +# Contributor Code of Conduct + +As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. + +We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other's private information, such as physical or electronic addresses, without explicit permission +* Other unethical or unprofessional conduct. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. + +This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community in a direct capacity. Personal views, beliefs and values of individuals do not necessarily reflect those of the organisation or affiliated individuals and organisations. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. + +This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) \ No newline at end of file From 20ad5d251c42e3406a6fe0a3bba2ff7e020e7820 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 13 Jan 2016 00:47:27 +0000 Subject: [PATCH 117/444] Updated link to OAuth 2 spec --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eed4d78c..84be9e67 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![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) -`league/oauth2-server` is a a standards compliant implementation of an [OAuth 2.0](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-v2/) 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. +`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: From 94b221c8a1f06c467f2cc089dace2c7c111f29ec Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 13 Jan 2016 00:47:41 +0000 Subject: [PATCH 118/444] Updated examples --- examples/composer.json | 4 +- examples/composer.lock | 251 +++++++++++++++++++++++-- examples/public/client_credentials.php | 4 +- examples/public/password.php | 16 +- 4 files changed, 248 insertions(+), 27 deletions(-) diff --git a/examples/composer.json b/examples/composer.json index 9c745658..0b85ac70 100644 --- a/examples/composer.json +++ b/examples/composer.json @@ -6,8 +6,8 @@ } ], "require": { - "slim/slim": "3.0.0-RC2", - "league/oauth2-server": "dev-v5-one" + "slim/slim": "3.0.*", + "league/oauth2-server": "dev-V5-WIP" }, "autoload": { "psr-4": { diff --git a/examples/composer.lock b/examples/composer.lock index d2326f41..747b7649 100644 --- a/examples/composer.lock +++ b/examples/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "bf607d2626a69ff12f1099d3853c138b", - "content-hash": "38198bbba51d99684b5d1b50e08b3019", + "hash": "ff6f832d21c141662627622e68079ca5", + "content-hash": "f08d5c7c3ede910150d75ad3c56d1b46", "packages": [ { "name": "container-interop/container-interop", @@ -34,6 +34,64 @@ "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", "time": "2014-12-30 15:22:37" }, + { + "name": "lcobucci/jwt", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "31499db4e692b343cec7ff345932899f98fde1cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/31499db4e692b343cec7ff345932899f98fde1cf", + "reference": "31499db4e692b343cec7ff345932899f98fde1cf", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">=5.5" + }, + "require-dev": { + "mdanter/ecc": "~0.3", + "mikey179/vfsstream": "~1.5", + "phpmd/phpmd": "~2.2", + "phpunit/php-invoker": "~1.1", + "phpunit/phpunit": "~4.5", + "squizlabs/php_codesniffer": "~2.3" + }, + "suggest": { + "mdanter/ecc": "Required to use Elliptic Curves based algorithms." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Luís Otávio Cobucci Oblonczyk", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "keywords": [ + "JWS", + "jwt" + ], + "time": "2015-11-15 01:42:47" + }, { "name": "league/event", "version": "2.1.2", @@ -86,15 +144,17 @@ }, { "name": "league/oauth2-server", - "version": "dev-v5-one", + "version": "dev-V5-WIP", "dist": { "type": "path", "url": "../", - "reference": "82413513e8002dc197a2fd9f13059eb88cd78ac1", + "reference": "59080a831926d6291fbc7854ff8d25427c374263", "shasum": null }, "require": { + "lcobucci/jwt": "^3.1", "league/event": "~2.1", + "namshi/jose": "^6.0", "php": ">=5.5.9", "zendframework/zend-diactoros": "~1.1" }, @@ -108,7 +168,15 @@ "mockery/mockery": "0.9.*", "phpunit/phpunit": "4.8.*" }, + "bin": [ + "bin/generate-crypto-key" + ], "type": "library", + "extra": { + "branch-alias": { + "dev-V5-WIP": "5.0-dev" + } + }, "autoload": { "psr-4": { "League\\OAuth2\\Server\\": "src/" @@ -149,6 +217,62 @@ "server" ] }, + { + "name": "namshi/jose", + "version": "6.0.3", + "source": { + "type": "git", + "url": "https://github.com/namshi/jose.git", + "reference": "e214c25ce0deed923ef6b299fbad87a822b51b2c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/namshi/jose/zipball/e214c25ce0deed923ef6b299fbad87a822b51b2c", + "reference": "e214c25ce0deed923ef6b299fbad87a822b51b2c", + "shasum": "" + }, + "require": { + "ext-date": "*", + "ext-hash": "*", + "ext-json": "*", + "ext-openssl": "*", + "ext-pcre": "*", + "ext-spl": "*", + "php": ">=5.4.8", + "phpseclib/phpseclib": "1.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.5", + "satooshi/php-coveralls": "dev-master" + }, + "type": "library", + "autoload": { + "psr-0": { + "Namshi\\JOSE": "src/", + "Namshi\\JOSE\\Test": "test/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Nadalin", + "email": "alessandro.nadalin@gmail.com" + } + ], + "description": "JSON Object Signing and Encryption library for PHP.", + "keywords": [ + "JSON Web Signature", + "JSON Web Token", + "JWS", + "json", + "jwt", + "token" + ], + "time": "2015-11-13 08:01:01" + }, { "name": "nikic/fast-route", "version": "v0.6.0", @@ -192,6 +316,100 @@ ], "time": "2015-06-18 19:15:47" }, + { + "name": "phpseclib/phpseclib", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "844134df95e42b93ed5506a2d11ca5accda99412" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/844134df95e42b93ed5506a2d11ca5accda99412", + "reference": "844134df95e42b93ed5506a2d11ca5accda99412", + "shasum": "" + }, + "require": { + "php": ">=5.0.0" + }, + "require-dev": { + "phing/phing": "~2.7", + "phpunit/phpunit": "~4.0", + "sami/sami": "~2.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "suggest": { + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations.", + "pear-pear/PHP_Compat": "Install PHP_Compat to get phpseclib working on PHP < 5.0.0." + }, + "type": "library", + "autoload": { + "psr-0": { + "Crypt": "phpseclib/", + "File": "phpseclib/", + "Math": "phpseclib/", + "Net": "phpseclib/", + "System": "phpseclib/" + }, + "files": [ + "phpseclib/Crypt/Random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "phpseclib/" + ], + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "time": "2015-08-04 02:22:12" + }, { "name": "pimple/pimple", "version": "v3.0.2", @@ -289,16 +507,16 @@ }, { "name": "slim/slim", - "version": "3.0.0-RC2", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/slimphp/Slim.git", - "reference": "c181a3a7666677fcf5dee2c03c504d5731262745" + "reference": "3b06f0f2d84dabbe81b6cea46ace46a3e883253e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim/zipball/c181a3a7666677fcf5dee2c03c504d5731262745", - "reference": "c181a3a7666677fcf5dee2c03c504d5731262745", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/3b06f0f2d84dabbe81b6cea46ace46a3e883253e", + "reference": "3b06f0f2d84dabbe81b6cea46ace46a3e883253e", "shasum": "" }, "require": { @@ -351,20 +569,20 @@ "micro", "router" ], - "time": "2015-11-09 10:57:43" + "time": "2015-12-07 14:11:09" }, { "name": "zendframework/zend-diactoros", - "version": "1.1.4", + "version": "1.3.3", "source": { "type": "git", "url": "https://github.com/zendframework/zend-diactoros.git", - "reference": "3f0ce6c0ba2106e018fb514a9f09dbb91eb6bfd0" + "reference": "4d54fde709664562eb63356f0250d527824d05de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/3f0ce6c0ba2106e018fb514a9f09dbb91eb6bfd0", - "reference": "3f0ce6c0ba2106e018fb514a9f09dbb91eb6bfd0", + "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/4d54fde709664562eb63356f0250d527824d05de", + "reference": "4d54fde709664562eb63356f0250d527824d05de", "shasum": "" }, "require": { @@ -381,8 +599,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev", - "dev-develop": "1.1-dev" + "dev-master": "1.3-dev", + "dev-develop": "1.4-dev" } }, "autoload": { @@ -401,14 +619,13 @@ "psr", "psr-7" ], - "time": "2015-10-16 15:24:05" + "time": "2016-01-04 21:37:32" } ], "packages-dev": [], "aliases": [], "minimum-stability": "stable", "stability-flags": { - "slim/slim": 5, "league/oauth2-server": 20 }, "prefer-stable": false, diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index 8486d31e..ca43fafb 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -15,7 +15,7 @@ use Slim\Http\Response; include(__DIR__ . '/../vendor/autoload.php'); // Setup the authorization server -$server = new Server(); +$server = new Server('file://' . __DIR__ . '/../private.key'); // Init our repositories $clientRepository = new ClientRepository(); @@ -30,7 +30,7 @@ $app = new App([Server::class => $server]); $app->post('/access_token', function (Request $request, Response $response) { /** @var Server $server */ - $server = $this->getContainer()->get(Server::class); + $server = $this->get(Server::class); try { return $server->respondToRequest($request); } catch (OAuthServerException $e) { diff --git a/examples/public/password.php b/examples/public/password.php index efeed2f0..d9ff5f8b 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -6,6 +6,7 @@ use League\OAuth2\Server\Server; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; +use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; use OAuth2ServerExamples\Repositories\UserRepository; @@ -16,28 +17,31 @@ use Slim\Http\Response; include(__DIR__ . '/../vendor/autoload.php'); // Setup the authorization server -$server = new Server(); +$server = new Server('file://' . __DIR__ . '/../private.key'); // Init our repositories +$userRepository = new UserRepository(); $clientRepository = new ClientRepository(); $scopeRepository = new ScopeRepository(); $accessTokenRepository = new AccessTokenRepository(); -$userRepository = new UserRepository(); +$refreshTokenRepository = new RefreshTokenRepository(); // Enable the client credentials grant on the server -$server->enableGrantType(new PasswordGrant( +$passwordGrant = new PasswordGrant( $userRepository, $clientRepository, $scopeRepository, - $accessTokenRepository -)); + $accessTokenRepository, + $refreshTokenRepository +); +$server->enableGrantType($passwordGrant); // App $app = new App([Server::class => $server]); $app->post('/access_token', function (Request $request, Response $response) { /** @var Server $server */ - $server = $this->getContainer()->get(Server::class); + $server = $this->get(Server::class); try { return $server->respondToRequest($request); } catch (OAuthServerException $e) { From 633746b02ee28f683615c58c80c111bd2c93e880 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 14 Jan 2016 23:44:39 +0000 Subject: [PATCH 119/444] Added KeyCrypt class --- src/Utils/KeyCrypt.php | 81 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/Utils/KeyCrypt.php diff --git a/src/Utils/KeyCrypt.php b/src/Utils/KeyCrypt.php new file mode 100644 index 00000000..d5e5e2c4 --- /dev/null +++ b/src/Utils/KeyCrypt.php @@ -0,0 +1,81 @@ + + * @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 + * + * @param string $unencryptedData + * @param string $pathToPrivateKey + * + * @return string + */ + public static function encrypt($unencryptedData, $pathToPrivateKey) + { + $privateKey = openssl_pkey_get_private($pathToPrivateKey); + $privateKeyDetails = @openssl_pkey_get_details($privateKey); + if ($privateKeyDetails === null) { + throw new \LogicException(sprintf('Could not get details of private key: %s', $pathToPrivateKey)); + } + + $chunkSize = ceil($privateKeyDetails['bits'] / 8) - 11; + $output = ''; + + while ($unencryptedData) { + $chunk = substr($unencryptedData, 0, $chunkSize); + $unencryptedData = substr($unencryptedData, $chunkSize); + if (openssl_private_encrypt($chunk, $encrypted, $privateKey) === false) { + throw new \LogicException('Failed to encrypt data'); + } + $output .= $encrypted; + } + openssl_free_key($privateKey); + + return base64_encode($output); + } + + /** + * Decrypt data with a public key + * + * @param string $encryptedData + * @param string $pathToPublicKey + * + * @return string + */ + public static function decrypt($encryptedData, $pathToPublicKey) + { + $publicKey = openssl_pkey_get_public($pathToPublicKey); + $publicKeyDetails = @openssl_pkey_get_details($publicKey); + if ($publicKeyDetails === null) { + throw new \LogicException(sprintf('Could not get details of public key: %s', $pathToPublicKey)); + } + + $chunkSize = ceil($publicKeyDetails['bits'] / 8); + $output = ''; + + $encryptedData = base64_decode($encryptedData); + + while ($encryptedData) { + $chunk = substr($encryptedData, 0, $chunkSize); + $encryptedData = substr($encryptedData, $chunkSize); + if (openssl_public_decrypt($chunk, $decrypted, $publicKey) === false) { + throw new \LogicException('Failed to decrypt data'); + } + $output .= $decrypted; + } + openssl_free_key($publicKey); + + return $output; + } +} From 56060b2c16839a7bc51cf1fca39dcee2fe8b3ce9 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 14 Jan 2016 23:45:36 +0000 Subject: [PATCH 120/444] Code tidy --- src/ResponseTypes/BearerTokenResponse.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index 3e5dc7f9..4b02a67b 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -25,7 +25,8 @@ class BearerTokenResponse extends AbstractResponseType */ public function generateHttpResponse() { - $jwtAccessToken = (new Builder())->setAudience($this->accessToken->getClient()->getIdentifier()) + $jwtAccessToken = (new Builder()) + ->setAudience($this->accessToken->getClient()->getIdentifier()) ->setId($this->accessToken->getIdentifier(), true) ->setIssuedAt(time()) ->setNotBefore(time()) From 304ea2baf48d391dff8e04223514c33cf1b4e3c9 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 14 Jan 2016 23:46:24 +0000 Subject: [PATCH 121/444] Encrypt refresh token parameters instead of using JWT --- src/ResponseTypes/BearerTokenResponse.php | 27 +++++++++++++---------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index 4b02a67b..85b5c235 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -15,6 +15,7 @@ use Lcobucci\JWT\Builder; use Lcobucci\JWT\Signer\Key; use Lcobucci\JWT\Signer\Rsa\Sha256; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Utils\KeyCrypt; use Psr\Http\Message\ServerRequestInterface; use Zend\Diactoros\Response; @@ -43,19 +44,21 @@ class BearerTokenResponse extends AbstractResponseType ]; if ($this->refreshToken instanceof RefreshTokenEntityInterface) { - $jwtRefreshToken = (new Builder())->setAudience($this->accessToken->getClient()->getIdentifier()) - ->setId($this->refreshToken->getIdentifier()) - ->setIssuedAt(time()) - ->setNotBefore(time()) - ->setExpiration($this->refreshToken->getExpiryDateTime()->getTimestamp()) - ->set('type', 'refreshToken') - ->setSubject($this->accessToken->getUserIdentifier()) - ->set('scopes', $this->accessToken->getScopes()) - ->set('accessToken', $this->accessToken->getIdentifier()) - ->sign(new Sha256(), new Key($this->pathToPrivateKey)) - ->getToken(); + $refreshToken = KeyCrypt::encrypt( + json_encode( + [ + 'client_id' => $this->accessToken->getClient()->getIdentifier(), + 'refresh_token_id' => $this->refreshToken->getIdentifier(), + 'access_token_id' => $this->accessToken->getIdentifier(), + 'scopes' => $this->accessToken->getScopes(), + 'user_id' => $this->accessToken->getUserIdentifier(), + 'expire_time' => $this->refreshToken->getExpiryDateTime()->getTimestamp(), + ] + ), + $this->pathToPrivateKey + ); - $responseParams['refresh_token'] = (string) $jwtRefreshToken; + $responseParams['refresh_token'] = $refreshToken; } $response = new Response( From 0b061e30863f385e221cc60f2d1499337d70975c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 14 Jan 2016 23:47:06 +0000 Subject: [PATCH 122/444] Refresh token is encrypted payload now instead of JWT --- src/Grant/RefreshTokenGrant.php | 37 +++++++++++++++------------------ 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index d84de59d..0933d000 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -25,6 +25,7 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; +use League\OAuth2\Server\Utils\KeyCrypt; use League\OAuth2\Server\Utils\SecureKey; use Psr\Http\Message\ServerRequestInterface; use Symfony\Component\EventDispatcher\Event; @@ -92,11 +93,11 @@ class RefreshTokenGrant extends AbstractGrant throw OAuthServerException::invalidRequest('client_secret', null, '`%s` parameter is missing'); } - $refreshTokenJwt = isset($request->getParsedBody()['refresh_token']) + $encryptedRefreshToken = isset($request->getParsedBody()['refresh_token']) ? $request->getParsedBody()['refresh_token'] : null; - if ($refreshTokenJwt === null) { + if ($encryptedRefreshToken === null) { throw OAuthServerException::invalidRequest('refresh_token', null, '`%s` parameter is missing'); } @@ -115,27 +116,23 @@ class RefreshTokenGrant extends AbstractGrant // Validate refresh token try { - $oldRefreshToken = (new Parser())->parse($refreshTokenJwt); - } catch (\InvalidArgumentException $e) { - throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token'); - } - if ($oldRefreshToken->verify(new Sha256(), new Key($this->pathToPublicKey)) === false) { - throw OAuthServerException::invalidRefreshToken('Cannot validate refresh token signature'); + $oldRefreshToken = KeyCrypt::decrypt($encryptedRefreshToken, $this->pathToPublicKey); + } catch (\LogicException $e) { + throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: ' . $e->getMessage()); } - $validation = new ValidationData(); - $validation->setAudience($client->getIdentifier()); // Validates refresh token hasn't expired - $validation->setCurrentTime(time()); // Validates token hasn't expired - if ($oldRefreshToken->validate($validation) === false) { - throw OAuthServerException::invalidRefreshToken('Token has expired or is not linked to client'); + $oldRefreshTokenData = json_decode($oldRefreshToken, true); + if ($oldRefreshTokenData['client_id'] !== $client->getIdentifier()) { + throw OAuthServerException::invalidRefreshToken('Token is not linked to client' . ' got: ' . $client->getIdentifier() . ' expected: '. $oldRefreshTokenData['client_id']); } - if ($oldRefreshToken->getClaim('type') !== 'refreshToken') { - throw OAuthServerException::invalidRefreshToken('Token is not a refresh token'); + if ($oldRefreshTokenData['expire_time'] < time()) { + throw OAuthServerException::invalidRefreshToken('Token has expired'); } - // Get the scopes for the original session - $scopes = $oldRefreshToken->getClaim('scopes'); + if ($this->refreshTokenRepository->isRefreshTokenRevoked($oldRefreshTokenData['refresh_token_id']) === true) { + throw OAuthServerException::invalidRefreshToken('Token has been revoked'); + } // Get and validate any requested scopes $scopeParam = isset($request->getParsedBody()['scope']) @@ -145,12 +142,12 @@ class RefreshTokenGrant extends AbstractGrant // If no new scopes are requested then give the access token the original session scopes if (count($requestedScopes) === 0) { - $newScopes = $scopes; + $newScopes = $oldRefreshTokenData['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 foreach ($requestedScopes as $requestedScope) { - if (in_array($requestedScope->getIdentifier(), $scopes) === false) { + if (in_array($requestedScope->getIdentifier(), $oldRefreshTokenData['scopes']) === false) { throw OAuthServerException::invalidScope($requestedScope->getIdentifier()); } } @@ -163,7 +160,7 @@ class RefreshTokenGrant extends AbstractGrant $accessToken->setIdentifier(SecureKey::generate()); $accessToken->setExpiryDateTime((new \DateTime())->add($tokenTTL)); $accessToken->setClient($client); - $accessToken->setUserIdentifier($oldRefreshToken->getClaim('sub')); + $accessToken->setUserIdentifier($oldRefreshTokenData['user_id']); foreach ($newScopes as $scope) { $accessToken->addScope($scope); } From b57b497cb79d691799f05bd94224c53af7a3878a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 14 Jan 2016 23:47:19 +0000 Subject: [PATCH 123/444] Revoke both refresh token and access token --- src/Grant/RefreshTokenGrant.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 0933d000..a78ab177 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -165,8 +165,9 @@ class RefreshTokenGrant extends AbstractGrant $accessToken->addScope($scope); } - // Expire the old token and save the new one - $this->accessTokenRepository->revokeAccessToken($oldRefreshToken->getClaim('accessToken')); + // Expire the old tokens and save the new one + $this->accessTokenRepository->revokeAccessToken($oldRefreshTokenData['access_token_id']); + $this->refreshTokenRepository->revokeRefreshToken($oldRefreshTokenData['refresh_token_id']); // Generate a new refresh token $refreshToken = new RefreshTokenEntity(); From 5e6f0fc6a342e7bdd4548996b025d92c61ba0475 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 14 Jan 2016 23:47:41 +0000 Subject: [PATCH 124/444] Code tidy --- src/Exception/OAuthServerException.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index a4575a10..0047cfec 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -172,7 +172,14 @@ class OAuthServerException extends \Exception */ public static function serverError($hint) { - return new static('\'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.', 'server_errror', 500, $hint); + return new static( + 'The authorization server encountered an unexpected condition which prevented it from fulfilling' + . 'the request.', + 'server_error', + 500, + $hint + ); + } } /** From a88c30cb537b4d26a9637ba7f8690f8462086911 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 14 Jan 2016 23:47:49 +0000 Subject: [PATCH 125/444] Added invalid refresh token exception --- src/Exception/OAuthServerException.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 0047cfec..28c9b799 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -180,6 +180,15 @@ class OAuthServerException extends \Exception $hint ); } + + /** + * Invalid refresh token + * + * @return static + */ + public static function invalidRefreshToken($hint = null) + { + return new static('The refresh token is invalid.', 'invalid_request', 400, $hint); } /** From f7b3c018c53fdfec50d6932226655c28c1b2c2cd Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 15 Jan 2016 00:05:59 +0000 Subject: [PATCH 126/444] Removed old authorization server --- src/AbstractServer.php | 107 ------------- src/AuthorizationServer.php | 295 ------------------------------------ 2 files changed, 402 deletions(-) delete mode 100644 src/AbstractServer.php delete mode 100644 src/AuthorizationServer.php diff --git a/src/AbstractServer.php b/src/AbstractServer.php deleted file mode 100644 index 28b3d23a..00000000 --- a/src/AbstractServer.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server; - -use League\Container\Container; -use League\Container\ContainerAwareInterface; -use League\Container\ContainerAwareTrait; -use League\Event\EmitterAwareInterface; -use League\Event\EmitterTrait; -use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; -use League\OAuth2\Server\Repositories\ClientRepositoryInterface; -use League\OAuth2\Server\Repositories\RepositoryInterface; -use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; -use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; -use League\OAuth2\Server\Repositories\UserRepositoryInterface; -use Symfony\Component\HttpFoundation\Request; - -/** - * OAuth 2.0 Resource Server - */ -abstract class AbstractServer implements ContainerAwareInterface, EmitterAwareInterface -{ - use EmitterTrait, ContainerAwareTrait; - - /** - * The request object - * - * @var \Symfony\Component\HttpFoundation\Request - */ - protected $request; - - /** - * Setup the server - */ - public function __construct() - { - $this->setContainer(new Container()); - $this->getContainer()->singleton('emitter', $this->getEmitter()); - $this->getContainer()->addServiceProvider('League\OAuth2\Server\ServiceProviders\ClientCredentialsGrantProvider'); - $this->getContainer()->addServiceProvider('League\OAuth2\Server\ServiceProviders\PasswordGrantProvider'); - } - - /** - * Sets the Request Object - * - * @param \Symfony\Component\HttpFoundation\Request The Request Object - * - * @return self - * @deprecated - */ - public function setRequest($request) - { - $this->request = $request; - - return $this; - } - - /** - * Gets the Request object. It will create one from the globals if one is not set. - * - * @return \Symfony\Component\HttpFoundation\Request - * @deprecated - */ - public function getRequest() - { - if ($this->request === null) { - $this->request = Request::createFromGlobals(); - } - - return $this->request; - } - - /** - * Add a repository to the server - * - * @param RepositoryInterface $repository - */ - public function addRepository(RepositoryInterface $repository) - { - switch ($repository) { - case ($repository instanceof AccessTokenRepositoryInterface): - $this->getContainer()->add('AccessTokenRepository', $repository); - break; - case ($repository instanceof ClientRepositoryInterface): - $this->getContainer()->add('ClientRepository', $repository); - break; - case ($repository instanceof ScopeRepositoryInterface): - $this->getContainer()->add('ScopeRepository', $repository); - break; - case ($repository instanceof UserRepositoryInterface): - $this->getContainer()->add('UserRepository', $repository); - break; - case ($repository instanceof AuthCodeRepositoryInterface): - $this->getContainer()->add('AuthCodeRepository', $repository); - break; - } - } -} diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php deleted file mode 100644 index d75213e9..00000000 --- a/src/AuthorizationServer.php +++ /dev/null @@ -1,295 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server; - -use League\OAuth2\Server\Grant\GrantTypeInterface; -use League\OAuth2\Server\TokenType\Bearer; - -/** - * OAuth 2.0 authorization server class - */ -class AuthorizationServer extends AbstractServer -{ - /** - * The delimiter between scopes specified in the scope query string parameter - * The OAuth 2 specification states it should be a space but most use a comma - * - * @var string - */ - protected $scopeDelimiter = ' '; - - /** - * The TTL (time to live) of an access token in seconds (default: 3600) - * - * @var integer - */ - protected $accessTokenTTL = 3600; - - /** - * The registered grant response types - * - * @var array - */ - protected $responseTypes = []; - - /** - * The registered grant types - * - * @var array - */ - protected $grantTypes = []; - - /** - * Require the "scope" parameter to be in checkAuthoriseParams() - * - * @var boolean - */ - protected $requireScopeParam = false; - - /** - * Default scope(s) to be used if none is provided - * - * @var string|array - */ - protected $defaultScope; - - /** - * Require the "state" parameter to be in checkAuthoriseParams() - * - * @var boolean - */ - protected $requireStateParam = false; - - /** - * Create a new OAuth2 authorization server - * - * @return self - */ - public function __construct() - { - // Set Bearer as the default token type - $this->setTokenType(new Bearer()); - - parent::__construct(); - - return $this; - } - - /** - * Enable support for a grant - * - * @param GrantTypeInterface $grantType A grant class which conforms to Interface/GrantTypeInterface - * @param null|string $identifier An identifier for the grant (autodetected if not passed) - * - * @return self - */ - public function addGrantType(GrantTypeInterface $grantType, $identifier = null) - { - if (is_null($identifier)) { - $identifier = $grantType->getIdentifier(); - } - - // Inject server into grant - $grantType->setAuthorizationServer($this); - - $this->grantTypes[$identifier] = $grantType; - - if (!is_null($grantType->getResponseType())) { - $this->responseTypes[] = $grantType->getResponseType(); - } - - return $this; - } - - /** - * Check if a grant type has been enabled - * - * @param string $identifier The grant type identifier - * - * @return boolean Returns "true" if enabled, "false" if not - */ - public function hasGrantType($identifier) - { - return (array_key_exists($identifier, $this->grantTypes)); - } - - /** - * Returns response types - * - * @return array - */ - public function getResponseTypes() - { - return $this->responseTypes; - } - - /** - * Require the "scope" parameter in checkAuthoriseParams() - * - * @param boolean $require - * - * @return self - */ - public function requireScopeParam($require = true) - { - $this->requireScopeParam = $require; - - return $this; - } - - /** - * Is the scope parameter required? - * - * @return bool - */ - public function scopeParamRequired() - { - return $this->requireScopeParam; - } - - /** - * Default scope to be used if none is provided and requireScopeParam() is false - * - * @param string $default Name of the default scope - * - * @return self - */ - public function setDefaultScope($default = null) - { - $this->defaultScope = $default; - - return $this; - } - - /** - * Default scope to be used if none is provided and requireScopeParam is false - * - * @return string|null - */ - public function getDefaultScope() - { - return $this->defaultScope; - } - - /** - * Require the "state" parameter in checkAuthoriseParams() - * - * @return bool - */ - public function stateParamRequired() - { - return $this->requireStateParam; - } - - /** - * Require the "state" parameter in checkAuthoriseParams() - * - * @param boolean $require - * - * @return self - */ - public function requireStateParam($require = true) - { - $this->requireStateParam = $require; - - return $this; - } - - /** - * Get the scope delimiter - * - * @return string The scope delimiter (default: ",") - */ - public function getScopeDelimiter() - { - return $this->scopeDelimiter; - } - - /** - * Set the scope delimiter - * - * @param string $scopeDelimiter - * - * @return self - */ - public function setScopeDelimiter($scopeDelimiter = ' ') - { - $this->scopeDelimiter = $scopeDelimiter; - - return $this; - } - - /** - * Get the TTL for an access token - * - * @return int The TTL - */ - public function getAccessTokenTTL() - { - return $this->accessTokenTTL; - } - - /** - * Set the TTL for an access token - * - * @param int $accessTokenTTL The new TTL - * - * @return self - */ - public function setAccessTokenTTL($accessTokenTTL = 3600) - { - $this->accessTokenTTL = $accessTokenTTL; - - return $this; - } - - /** - * Issue an access token - * - * @return array Authorise request parameters - * - * @throws - */ - public function issueAccessToken() - { - $grantType = $this->getRequest()->request->get('grant_type'); - if (is_null($grantType)) { - throw new Exception\InvalidRequestException('grant_type'); - } - - // Ensure grant type is one that is recognised and is enabled - if (!in_array($grantType, array_keys($this->grantTypes))) { - throw new Exception\UnsupportedGrantTypeException($grantType); - } - - // Complete the flow - return $this->getGrantType($grantType)->completeFlow(); - } - - /** - * Return a grant type class - * - * @param string $grantType The grant type identifier - * - * @return Grant\GrantTypeInterface - * - * @throws - */ - public function getGrantType($grantType) - { - if (isset($this->grantTypes[$grantType])) { - return $this->grantTypes[$grantType]; - } - - throw new Exception\InvalidGrantException($grantType); - } -} From 84a9802a672d75fa23f4effbd2c79beb4f0531e1 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 15 Jan 2016 00:14:41 +0000 Subject: [PATCH 127/444] Removed ServerAwareTrait --- src/Utils/ServerAwareTrait.php | 38 ---------------------------------- 1 file changed, 38 deletions(-) delete mode 100644 src/Utils/ServerAwareTrait.php diff --git a/src/Utils/ServerAwareTrait.php b/src/Utils/ServerAwareTrait.php deleted file mode 100644 index b25f6379..00000000 --- a/src/Utils/ServerAwareTrait.php +++ /dev/null @@ -1,38 +0,0 @@ -server = $server; - - return $this; - } - - /** - * Return the server - * - * @return \League\OAuth2\Server\AbstractServer - */ - protected function getServer() - { - return $this->server; - } -} \ No newline at end of file From 0fbe44786235e9a4e1cb5beea32ea02eedb0f876 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 15 Jan 2016 00:17:13 +0000 Subject: [PATCH 128/444] Removed old exceptions --- src/Exception/InvalidRefreshException.php | 36 ---------------------- src/Exception/ServerErrorException.php | 37 ----------------------- 2 files changed, 73 deletions(-) delete mode 100644 src/Exception/InvalidRefreshException.php delete mode 100644 src/Exception/ServerErrorException.php diff --git a/src/Exception/InvalidRefreshException.php b/src/Exception/InvalidRefreshException.php deleted file mode 100644 index 5ca3d921..00000000 --- a/src/Exception/InvalidRefreshException.php +++ /dev/null @@ -1,36 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Exception; - -/** - * Exception class - */ -class InvalidRefreshException extends OAuthException -{ - /** - * {@inheritdoc} - */ - public $httpStatusCode = 400; - - /** - * {@inheritdoc} - */ - public $errorType = 'invalid_request'; - - /** - * {@inheritdoc} - */ - public function __construct() - { - parent::__construct('The refresh token is invalid.'); - } -} diff --git a/src/Exception/ServerErrorException.php b/src/Exception/ServerErrorException.php deleted file mode 100644 index fe5a7df1..00000000 --- a/src/Exception/ServerErrorException.php +++ /dev/null @@ -1,37 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Exception; - -/** - * Exception class - */ -class ServerErrorException extends OAuthException -{ - /** - * {@inheritdoc} - */ - public $httpStatusCode = 500; - - /** - * {@inheritdoc} - */ - public $errorType = 'server_error'; - - /** - * {@inheritdoc} - */ - public function __construct($parameter = null) - { - $parameter = is_null($parameter) ? 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.' : $parameter; - parent::__construct($parameter); - } -} From 3de1b5917a6ebd8991fe905ce905b0f99f33f99b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Fri, 15 Jan 2016 12:41:48 +0100 Subject: [PATCH 129/444] deferred default objects creation --- src/Server.php | 71 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/src/Server.php b/src/Server.php index b18bddf4..0a158a6d 100644 --- a/src/Server.php +++ b/src/Server.php @@ -2,7 +2,6 @@ namespace League\OAuth2\Server; -use DateInterval; use League\Event\EmitterAwareInterface; use League\Event\EmitterAwareTrait; use League\OAuth2\Server\Exception\OAuthServerException; @@ -31,6 +30,11 @@ class Server implements EmitterAwareInterface */ protected $grantTypeAccessTokenTTL = []; + /** + * @var string + */ + protected $defaultPrivateKeyPath; + /** * @var ResponseTypeInterface */ @@ -49,12 +53,13 @@ class Server implements EmitterAwareInterface /** * New server instance * - * @param string $pathToPrivateKey + * @param string $defaultPrivateKeyPath + * @param DateInterval $defaultAccessTokenTTL */ - public function __construct($pathToPrivateKey) + public function __construct($defaultPrivateKeyPath, \DateInterval $defaultAccessTokenTTL = null) { - $this->setDefaultResponseType(new BearerTokenResponse($pathToPrivateKey)); - $this->setDefaultAccessTokenTTL(new DateInterval('PT01H')); // default token TTL of 1 hour + $this->defaultPrivateKeyPath = $defaultPrivateKeyPath; + $this->defaultAccessTokenTTL = $defaultAccessTokenTTL; } /** @@ -67,6 +72,44 @@ class Server implements EmitterAwareInterface $this->defaultResponseType = $defaultTokenType; } + /** + * Get the default token type that grants will return + * + * @return ResponseTypeInterface + */ + protected function getDefaultResponseType() + { + if (!$this->defaultResponseType instanceof ResponseTypeInterface) { + $this->defaultResponseType = new BearerTokenResponse($this->defaultPrivateKeyPath); + } + + return $this->defaultResponseType; + } + + /** + * Set the default TTL of access tokens + * + * @param DateInterval $defaultAccessTokenTTL + */ + public function setDefaultAccessTokenTTL(\DateInterval $defaultAccessTokenTTL) + { + $this->defaultAccessTokenTTL = $defaultAccessTokenTTL; + } + + /** + * Get the default TTL of access tokens + * + * @return DateInterval + */ + protected function getDefaultAccessTokenTTL() + { + if (!$this->defaultAccessTokenTTL instanceof \DateInterval) { + $this->defaultAccessTokenTTL = new \DateInterval('PT01H'); // default token TTL of 1 hour + } + + return $this->defaultAccessTokenTTL; + } + /** * Set the delimiter string used to separate scopes in a request * @@ -78,13 +121,13 @@ class Server implements EmitterAwareInterface } /** - * Set the default TTL of access tokens + * Get the delimiter string used to separate scopes in a request * - * @param DateInterval $defaultAccessTokenTTL + * @return string */ - public function setDefaultAccessTokenTTL(DateInterval $defaultAccessTokenTTL) + protected function getScopeDelimiterString() { - $this->defaultAccessTokenTTL = $defaultAccessTokenTTL; + return $this->scopeDelimiterString; } /** @@ -97,7 +140,7 @@ class Server implements EmitterAwareInterface public function enableGrantType( GrantTypeInterface $grantType, ResponseTypeInterface $responseType = null, - DateInterval $accessTokenTTL = null + \DateInterval $accessTokenTTL = null ) { $grantType->setEmitter($this->getEmitter()); $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; @@ -106,14 +149,14 @@ class Server implements EmitterAwareInterface if ($responseType instanceof ResponseTypeInterface) { $this->grantResponseTypes[$grantType->getIdentifier()] = $responseType; } else { - $this->grantResponseTypes[$grantType->getIdentifier()] = $this->defaultResponseType; + $this->grantResponseTypes[$grantType->getIdentifier()] = $this->getDefaultResponseType(); } // Set grant access token TTL - if ($accessTokenTTL instanceof DateInterval) { + if ($accessTokenTTL instanceof \DateInterval) { $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL; } else { - $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $this->defaultAccessTokenTTL; + $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $this->getDefaultAccessTokenTTL(); } } @@ -138,7 +181,7 @@ class Server implements EmitterAwareInterface $request, $this->grantResponseTypes[$grantType->getIdentifier()], $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()], - $this->scopeDelimiterString + $this->getScopeDelimiterString() ); } } From 65d981ad32ed7013bbaea698c433de9ba4e3c08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Fri, 15 Jan 2016 14:02:47 +0100 Subject: [PATCH 130/444] allow middleware use --- examples/public/client_credentials.php | 4 +- examples/public/password.php | 4 +- examples/public/refresh_token.php | 4 +- src/Exception/OAuthServerException.php | 22 ++++++----- src/ResponseTypes/BearerTokenResponse.php | 19 ++++------ src/ResponseTypes/ResponseTypeInterface.php | 4 +- src/Server.php | 41 +++++++++++++++++---- 7 files changed, 63 insertions(+), 35 deletions(-) diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index ca43fafb..1e671d3a 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -32,9 +32,9 @@ $app->post('/access_token', function (Request $request, Response $response) { /** @var Server $server */ $server = $this->get(Server::class); try { - return $server->respondToRequest($request); + return $server->respondToRequest($request, $response); } catch (OAuthServerException $e) { - return $e->generateHttpResponse(); + return $e->generateHttpResponse($response); } catch (\Exception $e) { return $response->withStatus(500)->write($e->getMessage()); } diff --git a/examples/public/password.php b/examples/public/password.php index d9ff5f8b..de73d63d 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -43,9 +43,9 @@ $app->post('/access_token', function (Request $request, Response $response) { /** @var Server $server */ $server = $this->get(Server::class); try { - return $server->respondToRequest($request); + return $server->respondToRequest($request, $response); } catch (OAuthServerException $e) { - return $e->generateHttpResponse(); + return $e->generateHttpResponse($response); } catch (\Exception $e) { return $response->withStatus(500)->write($e->getMessage()); } diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index 75c08139..d41e940b 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -43,9 +43,9 @@ $app->post('/access_token', function (Request $request, Response $response) { /** @var Server $server */ $server = $this->get(Server::class); try { - return $server->respondToRequest($request); + return $server->respondToRequest($request, $response); } catch (OAuthServerException $e) { - return $e->generateHttpResponse(); + return $e->generateHttpResponse($response); } catch (\Exception $e) { return $response->withStatus(500)->write( sprintf('

%s

%s

', get_class($e), $e->getMessage()) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 28c9b799..f97e3b5a 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -204,8 +204,12 @@ class OAuthServerException extends \Exception * * @return ResponseInterface */ - public function generateHttpResponse() + public function generateHttpResponse(ResponseInterface $response = null) { + if (!$response instanceof ResponseInterface) { + $response = new Response(); + } + $headers = $this->getHttpHeaders(); $payload = [ @@ -221,12 +225,13 @@ class OAuthServerException extends \Exception $headers['Location'] = RedirectUri::make($this->redirectUri, $payload); } - $response = new Response( - 'php://memory', - $this->getHttpStatusCode(), - $headers - ); - $response->getBody()->write(json_encode($payload)); + foreach ($headers as $header => $content) { + $response->withHeader($header, $content); + } + + $response + ->withStatus($this->getHttpStatusCode()) + ->getBody()->write(json_encode($payload)); return $response; } @@ -254,8 +259,7 @@ class OAuthServerException extends \Exception if ($this->errorType === 'invalid_client') { $authScheme = null; $request = new ServerRequest(); - if ( - isset($request->getServerParams()['PHP_AUTH_USER']) && + if (isset($request->getServerParams()['PHP_AUTH_USER']) && $request->getServerParams()['PHP_AUTH_USER'] !== null ) { $authScheme = 'Basic'; diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index 85b5c235..2397286e 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -16,6 +16,7 @@ use Lcobucci\JWT\Signer\Key; use Lcobucci\JWT\Signer\Rsa\Sha256; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Utils\KeyCrypt; +use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Zend\Diactoros\Response; @@ -24,7 +25,7 @@ class BearerTokenResponse extends AbstractResponseType /** * {@inheritdoc} */ - public function generateHttpResponse() + public function generateHttpResponse(ResponseInterface $response) { $jwtAccessToken = (new Builder()) ->setAudience($this->accessToken->getClient()->getIdentifier()) @@ -61,16 +62,12 @@ class BearerTokenResponse extends AbstractResponseType $responseParams['refresh_token'] = $refreshToken; } - $response = new Response( - 'php://memory', - 200, - [ - 'pragma' => 'no-cache', - 'cache-control' => 'no-store', - 'content-type' => 'application/json;charset=UTF-8' - ] - ); - $response->getBody()->write(json_encode($responseParams)); + $response + ->withStatus(200) + ->withHeader('pragma', 'no-cache') + ->withHeader('cache-control', 'no-store') + ->withHeader('content-type', 'application/json;charset=UTF-8') + ->getBody()->write(json_encode($responseParams)); return $response; } diff --git a/src/ResponseTypes/ResponseTypeInterface.php b/src/ResponseTypes/ResponseTypeInterface.php index fef9cb59..00c3ed14 100644 --- a/src/ResponseTypes/ResponseTypeInterface.php +++ b/src/ResponseTypes/ResponseTypeInterface.php @@ -38,7 +38,9 @@ interface ResponseTypeInterface public function determineAccessTokenInHeader(ServerRequestInterface $request); /** + * @param ResponseInterface $response + * * @return ResponseInterface */ - public function generateHttpResponse(); + public function generateHttpResponse(ResponseInterface $response); } diff --git a/src/Server.php b/src/Server.php index b18bddf4..cd7e6e46 100644 --- a/src/Server.php +++ b/src/Server.php @@ -9,7 +9,9 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\GrantTypeInterface; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; +use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequestFactory; class Server implements EmitterAwareInterface @@ -121,16 +123,21 @@ class Server implements EmitterAwareInterface * Return an access token response * * @param \Psr\Http\Message\ServerRequestInterface $request + * @param \Psr\Http\Message\ResponseInterface $response * - * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface + * @return \Psr\Http\Message\ResponseInterface * @throws \League\OAuth2\Server\Exception\OAuthServerException */ - public function respondToRequest(ServerRequestInterface $request = null) + public function respondToRequest(ServerRequestInterface $request = null, ResponseInterface $response = null) { - if ($request === null) { + if (!$request instanceof ServerRequestInterface) { $request = ServerRequestFactory::fromGlobals(); } + if (!$response instanceof ResponseInterface) { + $response = new Response(); + } + $tokenResponse = null; foreach ($this->enabledGrantTypes as $grantType) { if ($grantType->canRespondToRequest($request)) { @@ -143,12 +150,30 @@ class Server implements EmitterAwareInterface } } - if ($tokenResponse instanceof ResponseTypeInterface) { - return $tokenResponse->generateHttpResponse(); - } else { - $response = OAuthServerException::unsupportedGrantType()->generateHttpResponse(); + if (!$tokenResponse instanceof ResponseTypeInterface) { + return OAuthServerException::unsupportedGrantType()->generateHttpResponse($response); } - return $response; + return $tokenResponse->generateHttpResponse($response); + } + + /** + * PSR7 middleware callable + * + * @param \Psr\Http\Message\ServerRequestInterface $request + * @param \Psr\Http\Message\ResponseInterface $response + * + * @return \Psr\Http\Message\ResponseInterface + * @throws \League\OAuth2\Server\Exception\OAuthServerException + */ + public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) + { + $response = $this->respondToRequest($request, $response); + + if (in_array($response->getStatusCode(), [400, 401, 500])) { + return $response; + } + + return $next($request, $response); } } From c4830608a2d01a303dda46cbe10f553e45877d21 Mon Sep 17 00:00:00 2001 From: Hannes Van De Vreken Date: Fri, 15 Jan 2016 16:08:10 +0100 Subject: [PATCH 131/444] Fix markdown syntax --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 84be9e67..8c3c3ca1 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ The following versions of PHP are supported: ## Documentation -The library documentation can be found at [http://oauth2.thephpleague.com)(http://oauth2.thephpleague.com). +The library documentation can be found at [http://oauth2.thephpleague.com](http://oauth2.thephpleague.com). You can contribute to this documentation in the [gh-pages branch](https://github.com/thephpleague/oauth2-server/tree/gh-pages/). ## Changelog From 8f724bb7208093cd1580c3858a8c4d066a789fa7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 15 Jan 2016 18:32:53 +0000 Subject: [PATCH 132/444] Fix immutability issues --- src/Exception/OAuthServerException.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index f97e3b5a..982c8f73 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -226,14 +226,12 @@ class OAuthServerException extends \Exception } foreach ($headers as $header => $content) { - $response->withHeader($header, $content); + $response = $response->withHeader($header, $content); } - $response + return $response ->withStatus($this->getHttpStatusCode()) ->getBody()->write(json_encode($payload)); - - return $response; } /** From 748ae15376eaa405861549f3fc051ea37f75bcad Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 15 Jan 2016 18:36:34 +0000 Subject: [PATCH 133/444] Updated docblock --- src/Server.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Server.php b/src/Server.php index cd7e6e46..1f3ffd2f 100644 --- a/src/Server.php +++ b/src/Server.php @@ -122,8 +122,8 @@ class Server implements EmitterAwareInterface /** * Return an access token response * - * @param \Psr\Http\Message\ServerRequestInterface $request - * @param \Psr\Http\Message\ResponseInterface $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 From bcd84320daabf2e9f06d93a0801d09755b0a6970 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 15 Jan 2016 18:37:26 +0000 Subject: [PATCH 134/444] Updated docblocks --- src/Server.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Server.php b/src/Server.php index 03246c61..1c46a0eb 100644 --- a/src/Server.php +++ b/src/Server.php @@ -2,6 +2,7 @@ namespace League\OAuth2\Server; +use DateInterval; use League\Event\EmitterAwareInterface; use League\Event\EmitterAwareTrait; use League\OAuth2\Server\Exception\OAuthServerException; @@ -93,7 +94,7 @@ class Server implements EmitterAwareInterface * * @param DateInterval $defaultAccessTokenTTL */ - public function setDefaultAccessTokenTTL(\DateInterval $defaultAccessTokenTTL) + public function setDefaultAccessTokenTTL(DateInterval $defaultAccessTokenTTL) { $this->defaultAccessTokenTTL = $defaultAccessTokenTTL; } @@ -205,9 +206,9 @@ class Server implements EmitterAwareInterface * * @param \Psr\Http\Message\ServerRequestInterface $request * @param \Psr\Http\Message\ResponseInterface $response + * @param callable $next * * @return \Psr\Http\Message\ResponseInterface - * @throws \League\OAuth2\Server\Exception\OAuthServerException */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { From dce1620f60d9f1a44a9ec99b6168810a8030c20c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 15 Jan 2016 18:37:46 +0000 Subject: [PATCH 135/444] Removed unused imports --- src/Entities/RefreshTokenEntity.php | 1 - src/Grant/RefreshTokenGrant.php | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/Entities/RefreshTokenEntity.php b/src/Entities/RefreshTokenEntity.php index 1f6c6d07..dfb9239a 100644 --- a/src/Entities/RefreshTokenEntity.php +++ b/src/Entities/RefreshTokenEntity.php @@ -4,7 +4,6 @@ namespace League\OAuth2\Server\Entities; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\Traits\EntityTrait; use League\OAuth2\Server\Entities\Traits\RefreshTokenTrait; -use League\OAuth2\Server\Entities\Traits\TokenEntityTrait; /** * Class RefreshTokenEntity diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index a78ab177..37684489 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -12,10 +12,6 @@ namespace League\OAuth2\Server\Grant; use DateInterval; -use Lcobucci\JWT\Parser; -use Lcobucci\JWT\Signer\Key; -use Lcobucci\JWT\Signer\Rsa\Sha256; -use Lcobucci\JWT\ValidationData; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntity; From 6108c06e34e1f1a37da80c2475820245a735d325 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 15 Jan 2016 18:43:02 +0000 Subject: [PATCH 136/444] Updated examples/composer.lock --- examples/composer.lock | 53 +++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/examples/composer.lock b/examples/composer.lock index 747b7649..466319f3 100644 --- a/examples/composer.lock +++ b/examples/composer.lock @@ -148,7 +148,7 @@ "dist": { "type": "path", "url": "../", - "reference": "59080a831926d6291fbc7854ff8d25427c374263", + "reference": "dce1620f60d9f1a44a9ec99b6168810a8030c20c", "shasum": null }, "require": { @@ -168,9 +168,6 @@ "mockery/mockery": "0.9.*", "phpunit/phpunit": "4.8.*" }, - "bin": [ - "bin/generate-crypto-key" - ], "type": "library", "extra": { "branch-alias": { @@ -219,16 +216,16 @@ }, { "name": "namshi/jose", - "version": "6.0.3", + "version": "6.1.0", "source": { "type": "git", "url": "https://github.com/namshi/jose.git", - "reference": "e214c25ce0deed923ef6b299fbad87a822b51b2c" + "reference": "0ae1eae2be4f7e31a649ab9e3b782c3aedf81ebd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/namshi/jose/zipball/e214c25ce0deed923ef6b299fbad87a822b51b2c", - "reference": "e214c25ce0deed923ef6b299fbad87a822b51b2c", + "url": "https://api.github.com/repos/namshi/jose/zipball/0ae1eae2be4f7e31a649ab9e3b782c3aedf81ebd", + "reference": "0ae1eae2be4f7e31a649ab9e3b782c3aedf81ebd", "shasum": "" }, "require": { @@ -238,12 +235,12 @@ "ext-openssl": "*", "ext-pcre": "*", "ext-spl": "*", - "php": ">=5.4.8", - "phpseclib/phpseclib": "1.0.0" + "php": ">=5.5", + "phpseclib/phpseclib": "2.0.*" }, "require-dev": { - "phpunit/phpunit": "~4.5", - "satooshi/php-coveralls": "dev-master" + "phpunit/phpunit": "^4.5|^5.0", + "satooshi/php-coveralls": "^1.0" }, "type": "library", "autoload": { @@ -260,6 +257,10 @@ { "name": "Alessandro Nadalin", "email": "alessandro.nadalin@gmail.com" + }, + { + "name": "Alessandro Cinelli (cirpo)", + "email": "alessandro.cinelli@gmail.com" } ], "description": "JSON Object Signing and Encryption library for PHP.", @@ -271,7 +272,7 @@ "jwt", "token" ], - "time": "2015-11-13 08:01:01" + "time": "2016-01-13 10:17:13" }, { "name": "nikic/fast-route", @@ -318,20 +319,20 @@ }, { "name": "phpseclib/phpseclib", - "version": "1.0.0", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "844134df95e42b93ed5506a2d11ca5accda99412" + "reference": "a74aa9efbe61430fcb60157c8e025a48ec8ff604" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/844134df95e42b93ed5506a2d11ca5accda99412", - "reference": "844134df95e42b93ed5506a2d11ca5accda99412", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/a74aa9efbe61430fcb60157c8e025a48ec8ff604", + "reference": "a74aa9efbe61430fcb60157c8e025a48ec8ff604", "shasum": "" }, "require": { - "php": ">=5.0.0" + "php": ">=5.3.3" }, "require-dev": { "phing/phing": "~2.7", @@ -341,22 +342,16 @@ }, "suggest": { "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations.", "pear-pear/PHP_Compat": "Install PHP_Compat to get phpseclib working on PHP < 5.0.0." }, "type": "library", "autoload": { - "psr-0": { - "Crypt": "phpseclib/", - "File": "phpseclib/", - "Math": "phpseclib/", - "Net": "phpseclib/", - "System": "phpseclib/" - }, - "files": [ - "phpseclib/Crypt/Random.php" - ] + "psr-4": { + "phpseclib\\": "phpseclib/" + } }, "notification-url": "https://packagist.org/downloads/", "include-path": [ @@ -408,7 +403,7 @@ "x.509", "x509" ], - "time": "2015-08-04 02:22:12" + "time": "2015-08-04 04:48:03" }, { "name": "pimple/pimple", From 44ff8692dcf1b6c34790c455251ba93641b2be93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Sun, 17 Jan 2016 00:41:55 +0100 Subject: [PATCH 137/444] abstract common grants tasks --- src/Grant/AbstractGrant.php | 111 ++++++++++++++++ src/Grant/ClientCredentialsGrant.php | 71 +---------- src/Grant/PasswordGrant.php | 137 ++++++-------------- src/Grant/RefreshTokenGrant.php | 182 ++++++++++----------------- 4 files changed, 223 insertions(+), 278 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index a51d18e0..0753b792 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -12,12 +12,16 @@ namespace League\OAuth2\Server\Grant; use League\Event\EmitterInterface; +use League\Event\Event; +use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +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\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use League\OAuth2\Server\Utils\SecureKey; use Psr\Http\Message\ServerRequestInterface; /** @@ -95,6 +99,60 @@ abstract class AbstractGrant implements GrantTypeInterface return $this->respondsWith; } + /** + * @param \Psr\Http\Message\ServerRequestInterface $request + * + * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface + * + * @throws \League\OAuth2\Server\Exception\OAuthServerException + */ + protected function validateClient(ServerRequestInterface $request) + { + $clientId = $this->getRequestParameter(['client_id', 'PHP_AUTH_USER'], $request); + if (is_null($clientId)) { + throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); + } + + $clientSecret = $this->getRequestParameter(['client_secret', 'PHP_AUTH_PW'], $request); + if (is_null($clientSecret)) { + throw OAuthServerException::invalidRequest('client_secret', null, '`%s` parameter is missing'); + } + + $client = $this->clientRepository->getClientEntity( + $clientId, + $clientSecret, + null, + $this->getIdentifier() + ); + + if (!$client instanceof ClientEntityInterface) { + $this->emitter->emit(new Event('client.authentication.failed', $request)); + + throw OAuthServerException::invalidClient(); + } + + return $client; + } + + /** + * Retrieve request parameter. + * + * @param string|array $parameter + * @param \Psr\Http\Message\ServerRequestInterface $request + * + * @return string|null + */ + protected function getRequestParameter($parameter, ServerRequestInterface $request) + { + foreach ((array) $parameter as $param) { + if (isset($request->getParsedBody()[$param])) { + return $request->getParsedBody()[$param]; + } + } + + return null; + } + /** * @param string $scopeParamValue A string containing a delimited set of scope identifiers * @param string $scopeDelimiterString The delimiter between the scopes in the value string @@ -142,4 +200,57 @@ abstract class AbstractGrant implements GrantTypeInterface { $this->emitter = $emitter; } + + /** + * @param \DateInterval $tokenTTL + * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client + * @param string $userIdentifier + * @param array $scopes + * + * @return \League\OAuth2\Server\Entities\AccessTokenEntity + */ + protected function issueAccessToken( + \DateInterval $tokenTTL, + ClientEntityInterface $client, + $userIdentifier, + array $scopes = [] + ) { + $accessToken = new AccessTokenEntity(); + $accessToken->setIdentifier(SecureKey::generate()); + $accessToken->setExpiryDateTime((new \DateTime())->add($tokenTTL)); + $accessToken->setClient($client); + $accessToken->setUserIdentifier($userIdentifier); + + foreach ($scopes as $scope) { + $accessToken->addScope($scope); + } + + return $accessToken; + } + + /** + * @param \League\OAuth2\Server\Entities\AccessTokenEntity $accessToken + * + * @return \League\OAuth2\Server\Entities\RefreshTokenEntity + */ + protected function issueRefreshToken(AccessTokenEntity $accessToken) + { + $refreshToken = new RefreshTokenEntity(); + $refreshToken->setIdentifier(SecureKey::generate()); + $refreshToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('P1M'))); + $refreshToken->setAccessToken($accessToken); + + return $refreshToken; + } + + /** + * @inheritdoc + */ + public function canRespondToRequest(ServerRequestInterface $request) + { + return ( + isset($request->getParsedBody()['grant_type']) + && $request->getParsedBody()['grant_type'] === $this->identifier + ); + } } diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 7ae88aa7..70f70a9c 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -11,13 +11,9 @@ namespace League\OAuth2\Server\Grant; -use DateInterval; -use League\Event\Event; -use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; -use League\OAuth2\Server\Utils\SecureKey; use Psr\Http\Message\ServerRequestInterface; /** @@ -38,62 +34,14 @@ class ClientCredentialsGrant extends AbstractGrant public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - DateInterval $accessTokenTTL, + \DateInterval $tokenTTL, $scopeDelimiter = ' ' ) { - // Get the required params - $clientId = isset($request->getParsedBody()['client_id']) - ? $request->getParsedBody()['client_id'] // $_POST['client_id'] - : (isset($request->getServerParams()['PHP_AUTH_USER']) - ? $request->getServerParams()['PHP_AUTH_USER'] // $_SERVER['PHP_AUTH_USER'] - : null); + $client = $this->validateClient($request); + $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $scopeDelimiter, $client); - if (is_null($clientId)) { - throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); - } + $accessToken = $this->issueAccessToken($tokenTTL, $client, $client->getIdentifier(), $scopes); - $clientSecret = isset($request->getParsedBody()['client_secret']) - ? $request->getParsedBody()['client_secret'] // $_POST['client_id'] - : (isset($request->getServerParams()['PHP_AUTH_PW']) - ? $request->getServerParams()['PHP_AUTH_PW'] // $_SERVER['PHP_AUTH_USER'] - : null); - - if (is_null($clientSecret)) { - throw OAuthServerException::invalidRequest('client_secret', null, '`%s` parameter is missing'); - } - - // Validate client ID and client secret - $client = $this->clientRepository->getClientEntity( - $clientId, - $clientSecret, - null, - $this->getIdentifier() - ); - - if (($client instanceof ClientEntityInterface) === false) { - $this->emitter->emit(new Event('client.authentication.failed', $request)); - throw OAuthServerException::invalidClient(); - } - - // Validate any scopes that are in the request - $scopeParam = isset($request->getParsedBody()['scope']) - ? $request->getParsedBody()['scope'] // $_POST['scope'] - : ''; - $scopes = $this->validateScopes($scopeParam, $scopeDelimiter, $client); - - // Generate an access token - $accessToken = new AccessTokenEntity(); - $accessToken->setIdentifier(SecureKey::generate()); - $accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL)); - $accessToken->setClient($client); - $accessToken->setUserIdentifier($client->getIdentifier()); - - // Associate scopes with the session and access token - foreach ($scopes as $scope) { - $accessToken->addScope($scope); - } - - // Save the token $this->accessTokenRepository->persistNewAccessToken($accessToken); // Inject access token into token type @@ -101,15 +49,4 @@ class ClientCredentialsGrant extends AbstractGrant return $responseType; } - - /** - * @inheritdoc - */ - public function canRespondToRequest(ServerRequestInterface $request) - { - return ( - array_key_exists('grant_type', $request->getParsedBody()) - && $request->getParsedBody()['grant_type'] === 'client_credentials' - ); - } } diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index fee9d798..c948bc6d 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -11,12 +11,9 @@ namespace League\OAuth2\Server\Grant; -use DateInterval; use League\Event\Event; -use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; -use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -24,7 +21,6 @@ use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; -use League\OAuth2\Server\Utils\SecureKey; use Psr\Http\Message\ServerRequestInterface; /** @@ -32,6 +28,13 @@ use Psr\Http\Message\ServerRequestInterface; */ class PasswordGrant extends AbstractGrant { + /** + * Grant identifier + * + * @var string + */ + protected $identifier = 'password'; + /** * @var \League\OAuth2\Server\Repositories\UserRepositoryInterface */ @@ -56,9 +59,10 @@ class PasswordGrant extends AbstractGrant AccessTokenRepositoryInterface $accessTokenRepository, RefreshTokenRepositoryInterface $refreshTokenRepository ) { + parent::__construct($clientRepository, $scopeRepository, $accessTokenRepository); + $this->userRepository = $userRepository; $this->refreshTokenRepository = $refreshTokenRepository; - parent::__construct($clientRepository, $scopeRepository, $accessTokenRepository); } /** @@ -67,97 +71,16 @@ class PasswordGrant extends AbstractGrant public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - DateInterval $tokenTTL, + \DateInterval $tokenTTL, $scopeDelimiter = ' ' ) { - // Get the required params - $clientId = isset($request->getParsedBody()['client_id']) - ? $request->getParsedBody()['client_id'] // $_POST['client_id'] - : (isset($request->getServerParams()['PHP_AUTH_USER']) - ? $request->getServerParams()['PHP_AUTH_USER'] // $_SERVER['PHP_AUTH_USER'] - : null); + $client = $this->validateClient($request); + $user = $this->validateUser($request); + $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $scopeDelimiter, $client); - if (is_null($clientId)) { - throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); - } + $accessToken = $this->issueAccessToken($tokenTTL, $client, $user->getIdentifier(), $scopes); + $refreshToken = $this->issueRefreshToken($accessToken); - $clientSecret = isset($request->getParsedBody()['client_secret']) - ? $request->getParsedBody()['client_secret'] // $_POST['client_id'] - : (isset($request->getServerParams()['PHP_AUTH_PW']) - ? $request->getServerParams()['PHP_AUTH_PW'] // $_SERVER['PHP_AUTH_USER'] - : null); - - if (is_null($clientSecret)) { - throw OAuthServerException::invalidRequest('client_secret', null, '`%s` parameter is missing'); - } - - // Validate client ID and client secret - $client = $this->clientRepository->getClientEntity( - $clientId, - $clientSecret, - null, - $this->getIdentifier() - ); - - if (($client instanceof ClientEntityInterface) === false) { - $this->emitter->emit(new Event('client.authentication.failed', $request)); - throw OAuthServerException::invalidClient(); - } - - // Username - $username = isset($request->getParsedBody()['username']) - ? $request->getParsedBody()['username'] // $_POST['username'] - : (isset($request->getServerParams()['PHP_AUTH_USER']) - ? $request->getServerParams()['PHP_AUTH_USER'] // $_SERVER['PHP_AUTH_USER'] - : null); - - if (is_null($username)) { - throw OAuthServerException::invalidRequest('username', null, '`%s` parameter is missing'); - } - - // Password - $password = isset($request->getParsedBody()['password']) - ? $request->getParsedBody()['password'] // $_POST['password'] - : (isset($request->getServerParams()['PHP_AUTH_USER']) - ? $request->getServerParams()['PHP_AUTH_USER'] // $_SERVER['PHP_AUTH_USER'] - : null); - - if (is_null($password)) { - throw OAuthServerException::invalidRequest('password', null, '`%s` parameter is missing'); - } - - // Verify user's username and password - $userEntity = $this->userRepository->getUserEntityByUserCredentials($username, $password); - if (($userEntity instanceof UserEntityInterface) === false) { - $this->emitter->emit(new Event('user.authentication.failed', $request)); - throw OAuthServerException::invalidCredentials(); - } - - // Validate any scopes that are in the request - $scopeParam = isset($request->getParsedBody()['scope']) - ? $request->getParsedBody()['scope'] // $_POST['scope'] - : ''; - $scopes = $this->validateScopes($scopeParam, $scopeDelimiter, $client); - - // Generate an access token - $accessToken = new AccessTokenEntity(); - $accessToken->setIdentifier(SecureKey::generate()); - $accessToken->setExpiryDateTime((new \DateTime())->add($tokenTTL)); - $accessToken->setClient($client); - $accessToken->setUserIdentifier($userEntity->getIdentifier()); - - // Associate scopes with the session and access token - foreach ($scopes as $scope) { - $accessToken->addScope($scope); - } - - // Generate a refresh token - $refreshToken = new RefreshTokenEntity(); - $refreshToken->setIdentifier(SecureKey::generate()); - $refreshToken->setExpiryDateTime((new \DateTime())->add(new DateInterval('P1M'))); - $refreshToken->setAccessToken($accessToken); - - // Persist the tokens $this->accessTokenRepository->persistNewAccessToken($accessToken); $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); @@ -169,13 +92,31 @@ class PasswordGrant extends AbstractGrant } /** - * @inheritdoc + * @param \Psr\Http\Message\ServerRequestInterface $request + * + * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface + * + * @throws \League\OAuth2\Server\Exception\OAuthServerException */ - public function canRespondToRequest(ServerRequestInterface $request) + protected function validateUser(ServerRequestInterface $request) { - return ( - isset($request->getParsedBody()['grant_type']) - && $request->getParsedBody()['grant_type'] === 'password' - ); + $username = $this->getRequestParameter(['username', 'PHP_AUTH_USER'], $request); + if (is_null($username)) { + throw OAuthServerException::invalidRequest('username', null, '`%s` parameter is missing'); + } + + $password = $this->getRequestParameter(['password', 'PHP_AUTH_PW'], $request); + if (is_null($password)) { + throw OAuthServerException::invalidRequest('password', null, '`%s` parameter is missing'); + } + + $user = $this->userRepository->getUserEntityByUserCredentials($username, $password); + if (!$user instanceof UserEntityInterface) { + $this->emitter->emit(new Event('user.authentication.failed', $request)); + + throw OAuthServerException::invalidCredentials(); + } + + return $user; } } diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index a78ab177..a5db9514 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -11,14 +11,8 @@ namespace League\OAuth2\Server\Grant; -use DateInterval; -use Lcobucci\JWT\Parser; -use Lcobucci\JWT\Signer\Key; -use Lcobucci\JWT\Signer\Rsa\Sha256; -use Lcobucci\JWT\ValidationData; -use League\OAuth2\Server\Entities\AccessTokenEntity; +use League\Event\Event; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -26,9 +20,7 @@ use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\Utils\KeyCrypt; -use League\OAuth2\Server\Utils\SecureKey; use Psr\Http\Message\ServerRequestInterface; -use Symfony\Component\EventDispatcher\Event; /** * Refresh token grant @@ -36,14 +28,22 @@ use Symfony\Component\EventDispatcher\Event; class RefreshTokenGrant extends AbstractGrant { /** - * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface + * Grant identifier + * + * @var string */ - private $refreshTokenRepository; + protected $identifier = 'refresh_token'; + /** * @var string */ private $pathToPublicKey; + /** + * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface + */ + private $refreshTokenRepository; + /** * @param string $pathToPublicKey * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository @@ -58,9 +58,10 @@ class RefreshTokenGrant extends AbstractGrant AccessTokenRepositoryInterface $accessTokenRepository, RefreshTokenRepositoryInterface $refreshTokenRepository ) { + parent::__construct($clientRepository, $scopeRepository, $accessTokenRepository); + $this->pathToPublicKey = $pathToPublicKey; $this->refreshTokenRepository = $refreshTokenRepository; - parent::__construct($clientRepository, $scopeRepository, $accessTokenRepository); } /** @@ -69,113 +70,35 @@ class RefreshTokenGrant extends AbstractGrant public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - DateInterval $tokenTTL, + \DateInterval $tokenTTL, $scopeDelimiter = ' ' ) { - // Get the required params - $clientId = isset($request->getParsedBody()['client_id']) - ? $request->getParsedBody()['client_id'] // $_POST['client_id'] - : (isset($request->getServerParams()['PHP_AUTH_USER']) - ? $request->getServerParams()['PHP_AUTH_USER'] // $_SERVER['PHP_AUTH_USER'] - : null); - - if (is_null($clientId)) { - throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); - } - - $clientSecret = isset($request->getParsedBody()['client_secret']) - ? $request->getParsedBody()['client_secret'] // $_POST['client_id'] - : (isset($request->getServerParams()['PHP_AUTH_PW']) - ? $request->getServerParams()['PHP_AUTH_PW'] // $_SERVER['PHP_AUTH_USER'] - : null); - - if (is_null($clientSecret)) { - throw OAuthServerException::invalidRequest('client_secret', null, '`%s` parameter is missing'); - } - - $encryptedRefreshToken = isset($request->getParsedBody()['refresh_token']) - ? $request->getParsedBody()['refresh_token'] - : null; - - if ($encryptedRefreshToken === null) { - throw OAuthServerException::invalidRequest('refresh_token', null, '`%s` parameter is missing'); - } - - // Validate client ID and client secret - $client = $this->clientRepository->getClientEntity( - $clientId, - $clientSecret, - null, - $this->getIdentifier() - ); - - if (($client instanceof ClientEntityInterface) === false) { - $this->emitter->emit(new Event('client.authentication.failed', $request)); - throw OAuthServerException::invalidClient(); - } - - // Validate refresh token - try { - $oldRefreshToken = KeyCrypt::decrypt($encryptedRefreshToken, $this->pathToPublicKey); - } catch (\LogicException $e) { - throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: ' . $e->getMessage()); - } - - $oldRefreshTokenData = json_decode($oldRefreshToken, true); - if ($oldRefreshTokenData['client_id'] !== $client->getIdentifier()) { - throw OAuthServerException::invalidRefreshToken('Token is not linked to client' . ' got: ' . $client->getIdentifier() . ' expected: '. $oldRefreshTokenData['client_id']); - } - - if ($oldRefreshTokenData['expire_time'] < time()) { - throw OAuthServerException::invalidRefreshToken('Token has expired'); - } - - if ($this->refreshTokenRepository->isRefreshTokenRevoked($oldRefreshTokenData['refresh_token_id']) === true) { - throw OAuthServerException::invalidRefreshToken('Token has been revoked'); - } - - // Get and validate any requested scopes - $scopeParam = isset($request->getParsedBody()['scope']) - ? $request->getParsedBody()['scope'] // $_POST['scope'] - : ''; - $requestedScopes = $this->validateScopes($scopeParam, $scopeDelimiter, $client); + $client = $this->validateClient($request); + $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier()); + $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $scopeDelimiter, $client); // If no new scopes are requested then give the access token the original session scopes - if (count($requestedScopes) === 0) { - $newScopes = $oldRefreshTokenData['scopes']; + if (count($scopes) === 0) { + $scopes = $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 - foreach ($requestedScopes as $requestedScope) { - if (in_array($requestedScope->getIdentifier(), $oldRefreshTokenData['scopes']) === false) { - throw OAuthServerException::invalidScope($requestedScope->getIdentifier()); + // the request doesn't include any new scopes + foreach ($scopes as $scope) { + if (in_array($scope->getIdentifier(), $oldRefreshToken['scopes']) === false) { + $this->emitter->emit(new Event('scope.selection.failed', $request)); + + throw OAuthServerException::invalidScope($scope->getIdentifier()); } } - - $newScopes = $requestedScopes; } - // Generate a new access token - $accessToken = new AccessTokenEntity(); - $accessToken->setIdentifier(SecureKey::generate()); - $accessToken->setExpiryDateTime((new \DateTime())->add($tokenTTL)); - $accessToken->setClient($client); - $accessToken->setUserIdentifier($oldRefreshTokenData['user_id']); - foreach ($newScopes as $scope) { - $accessToken->addScope($scope); - } + // Expire old tokens + $this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']); + $this->refreshTokenRepository->revokeRefreshToken($oldRefreshToken['refresh_token_id']); - // Expire the old tokens and save the new one - $this->accessTokenRepository->revokeAccessToken($oldRefreshTokenData['access_token_id']); - $this->refreshTokenRepository->revokeRefreshToken($oldRefreshTokenData['refresh_token_id']); + $accessToken = $this->issueAccessToken($tokenTTL, $client, $oldRefreshToken['user_id'], $scopes); + $refreshToken = $this->issueRefreshToken($accessToken); - // Generate a new refresh token - $refreshToken = new RefreshTokenEntity(); - $refreshToken->setIdentifier(SecureKey::generate()); - $refreshToken->setExpiryDateTime((new \DateTime())->add(new DateInterval('P1M'))); - $refreshToken->setAccessToken($accessToken); - - // Persist the tokens $this->accessTokenRepository->persistNewAccessToken($accessToken); $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); @@ -187,13 +110,46 @@ class RefreshTokenGrant extends AbstractGrant } /** - * @inheritdoc + * @param \Psr\Http\Message\ServerRequestInterface $request + * @param string $clientId + * + * @return array + * + * @throws \League\OAuth2\Server\Exception\OAuthServerException */ - public function canRespondToRequest(ServerRequestInterface $request) + protected function validateOldRefreshToken(ServerRequestInterface $request, $clientId) { - return ( - isset($request->getParsedBody()['grant_type']) - && $request->getParsedBody()['grant_type'] === 'refresh_token' - ); + $encryptedRefreshToken = $this->getRequestParameter('refresh_token', $request); + if (is_null($encryptedRefreshToken)) { + throw OAuthServerException::invalidRequest('refresh_token', null, '`%s` parameter is missing'); + } + + // Validate refresh token + try { + $refreshToken = KeyCrypt::decrypt($encryptedRefreshToken, $this->pathToPublicKey); + } catch (\LogicException $e) { + throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: ' . $e->getMessage()); + } + + $refreshTokenData = json_decode($refreshToken, true); + if ($refreshTokenData['client_id'] !== $clientId) { + $this->emitter->emit(new Event('refresh_token.client.failed', $request)); + + throw OAuthServerException::invalidRefreshToken( + 'Token is not linked to client,' . + ' got: ' . $clientId . + ' expected: '. $refreshTokenData['client_id'] + ); + } + + if ($refreshTokenData['expire_time'] < time()) { + throw OAuthServerException::invalidRefreshToken('Token has expired'); + } + + if ($this->refreshTokenRepository->isRefreshTokenRevoked($refreshTokenData['refresh_token_id']) === true) { + throw OAuthServerException::invalidRefreshToken('Token has been revoked'); + } + + return $refreshTokenData; } } From 9e4fd82763dae86244b61b52b0a7454fb4f2ac64 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 12:56:52 +0000 Subject: [PATCH 138/444] Rewrote RefreshTokenGrant to understand encrypted tokens --- src/Grant/RefreshTokenGrant.php | 177 ++++++++++++-------------------- 1 file changed, 68 insertions(+), 109 deletions(-) diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 37684489..4747811b 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -11,10 +11,6 @@ namespace League\OAuth2\Server\Grant; -use DateInterval; -use League\OAuth2\Server\Entities\AccessTokenEntity; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -22,7 +18,6 @@ use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\Utils\KeyCrypt; -use League\OAuth2\Server\Utils\SecureKey; use Psr\Http\Message\ServerRequestInterface; use Symfony\Component\EventDispatcher\Event; @@ -32,14 +27,22 @@ use Symfony\Component\EventDispatcher\Event; class RefreshTokenGrant extends AbstractGrant { /** - * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface + * Grant identifier + * + * @var string */ - private $refreshTokenRepository; + protected $identifier = 'refresh_token'; + /** * @var string */ private $pathToPublicKey; + /** + * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface + */ + private $refreshTokenRepository; + /** * @param string $pathToPublicKey * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository @@ -54,9 +57,10 @@ class RefreshTokenGrant extends AbstractGrant AccessTokenRepositoryInterface $accessTokenRepository, RefreshTokenRepositoryInterface $refreshTokenRepository ) { + parent::__construct($clientRepository, $scopeRepository, $accessTokenRepository); + $this->pathToPublicKey = $pathToPublicKey; $this->refreshTokenRepository = $refreshTokenRepository; - parent::__construct($clientRepository, $scopeRepository, $accessTokenRepository); } /** @@ -65,113 +69,35 @@ class RefreshTokenGrant extends AbstractGrant public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - DateInterval $tokenTTL, + \DateInterval $tokenTTL, $scopeDelimiter = ' ' ) { - // Get the required params - $clientId = isset($request->getParsedBody()['client_id']) - ? $request->getParsedBody()['client_id'] // $_POST['client_id'] - : (isset($request->getServerParams()['PHP_AUTH_USER']) - ? $request->getServerParams()['PHP_AUTH_USER'] // $_SERVER['PHP_AUTH_USER'] - : null); - - if (is_null($clientId)) { - throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); - } - - $clientSecret = isset($request->getParsedBody()['client_secret']) - ? $request->getParsedBody()['client_secret'] // $_POST['client_id'] - : (isset($request->getServerParams()['PHP_AUTH_PW']) - ? $request->getServerParams()['PHP_AUTH_PW'] // $_SERVER['PHP_AUTH_USER'] - : null); - - if (is_null($clientSecret)) { - throw OAuthServerException::invalidRequest('client_secret', null, '`%s` parameter is missing'); - } - - $encryptedRefreshToken = isset($request->getParsedBody()['refresh_token']) - ? $request->getParsedBody()['refresh_token'] - : null; - - if ($encryptedRefreshToken === null) { - throw OAuthServerException::invalidRequest('refresh_token', null, '`%s` parameter is missing'); - } - - // Validate client ID and client secret - $client = $this->clientRepository->getClientEntity( - $clientId, - $clientSecret, - null, - $this->getIdentifier() - ); - - if (($client instanceof ClientEntityInterface) === false) { - $this->emitter->emit(new Event('client.authentication.failed', $request)); - throw OAuthServerException::invalidClient(); - } - - // Validate refresh token - try { - $oldRefreshToken = KeyCrypt::decrypt($encryptedRefreshToken, $this->pathToPublicKey); - } catch (\LogicException $e) { - throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: ' . $e->getMessage()); - } - - $oldRefreshTokenData = json_decode($oldRefreshToken, true); - if ($oldRefreshTokenData['client_id'] !== $client->getIdentifier()) { - throw OAuthServerException::invalidRefreshToken('Token is not linked to client' . ' got: ' . $client->getIdentifier() . ' expected: '. $oldRefreshTokenData['client_id']); - } - - if ($oldRefreshTokenData['expire_time'] < time()) { - throw OAuthServerException::invalidRefreshToken('Token has expired'); - } - - if ($this->refreshTokenRepository->isRefreshTokenRevoked($oldRefreshTokenData['refresh_token_id']) === true) { - throw OAuthServerException::invalidRefreshToken('Token has been revoked'); - } - - // Get and validate any requested scopes - $scopeParam = isset($request->getParsedBody()['scope']) - ? $request->getParsedBody()['scope'] // $_POST['scope'] - : ''; - $requestedScopes = $this->validateScopes($scopeParam, $scopeDelimiter, $client); + $client = $this->validateClient($request); + $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier()); + $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $scopeDelimiter, $client); // If no new scopes are requested then give the access token the original session scopes - if (count($requestedScopes) === 0) { - $newScopes = $oldRefreshTokenData['scopes']; + if (count($scopes) === 0) { + $scopes = $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 - foreach ($requestedScopes as $requestedScope) { - if (in_array($requestedScope->getIdentifier(), $oldRefreshTokenData['scopes']) === false) { - throw OAuthServerException::invalidScope($requestedScope->getIdentifier()); + // the request doesn't include any new scopes + foreach ($scopes as $scope) { + if (in_array($scope->getIdentifier(), $oldRefreshToken['scopes']) === false) { + $this->emitter->emit(new Event('scope.selection.failed', $request)); + + throw OAuthServerException::invalidScope($scope->getIdentifier()); } } - - $newScopes = $requestedScopes; } - // Generate a new access token - $accessToken = new AccessTokenEntity(); - $accessToken->setIdentifier(SecureKey::generate()); - $accessToken->setExpiryDateTime((new \DateTime())->add($tokenTTL)); - $accessToken->setClient($client); - $accessToken->setUserIdentifier($oldRefreshTokenData['user_id']); - foreach ($newScopes as $scope) { - $accessToken->addScope($scope); - } + // Expire old tokens + $this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']); + $this->refreshTokenRepository->revokeRefreshToken($oldRefreshToken['refresh_token_id']); - // Expire the old tokens and save the new one - $this->accessTokenRepository->revokeAccessToken($oldRefreshTokenData['access_token_id']); - $this->refreshTokenRepository->revokeRefreshToken($oldRefreshTokenData['refresh_token_id']); + $accessToken = $this->issueAccessToken($tokenTTL, $client, $oldRefreshToken['user_id'], $scopes); + $refreshToken = $this->issueRefreshToken($accessToken); - // Generate a new refresh token - $refreshToken = new RefreshTokenEntity(); - $refreshToken->setIdentifier(SecureKey::generate()); - $refreshToken->setExpiryDateTime((new \DateTime())->add(new DateInterval('P1M'))); - $refreshToken->setAccessToken($accessToken); - - // Persist the tokens $this->accessTokenRepository->persistNewAccessToken($accessToken); $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); @@ -183,13 +109,46 @@ class RefreshTokenGrant extends AbstractGrant } /** - * @inheritdoc + * @param \Psr\Http\Message\ServerRequestInterface $request + * @param string $clientId + * + * @return array + * + * @throws \League\OAuth2\Server\Exception\OAuthServerException */ - public function canRespondToRequest(ServerRequestInterface $request) + protected function validateOldRefreshToken(ServerRequestInterface $request, $clientId) { - return ( - isset($request->getParsedBody()['grant_type']) - && $request->getParsedBody()['grant_type'] === 'refresh_token' - ); + $encryptedRefreshToken = $this->getRequestParameter('refresh_token', $request); + if (is_null($encryptedRefreshToken)) { + throw OAuthServerException::invalidRequest('refresh_token', null, '`%s` parameter is missing'); + } + + // Validate refresh token + try { + $refreshToken = KeyCrypt::decrypt($encryptedRefreshToken, $this->pathToPublicKey); + } catch (\LogicException $e) { + throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: ' . $e->getMessage()); + } + + $refreshTokenData = json_decode($refreshToken, true); + if ($refreshTokenData['client_id'] !== $clientId) { + $this->emitter->emit(new Event('refresh_token.client.failed', $request)); + + throw OAuthServerException::invalidRefreshToken( + 'Token is not linked to client,' . + ' got: ' . $clientId . + ' expected: '. $refreshTokenData['client_id'] + ); + } + + if ($refreshTokenData['expire_time'] < time()) { + throw OAuthServerException::invalidRefreshToken('Token has expired'); + } + + if ($this->refreshTokenRepository->isRefreshTokenRevoked($refreshTokenData['refresh_token_id']) === true) { + throw OAuthServerException::invalidRefreshToken('Token has been revoked'); + } + + return $refreshTokenData; } } From f44b618531fc53b11fa2167ca2b08880188af390 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 12:57:50 +0000 Subject: [PATCH 139/444] Docblock tidy --- src/Exception/OAuthServerException.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 982c8f73..f5630c63 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -202,7 +202,9 @@ class OAuthServerException extends \Exception /** * Generate a HTTP response * - * @return ResponseInterface + * @param \Psr\Http\Message\ResponseInterface $response + * + * @return \Psr\Http\Message\ResponseInterface */ public function generateHttpResponse(ResponseInterface $response = null) { From 7242a8db31cbc3e4a6a4724a47308f7c67b93e02 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 12:58:00 +0000 Subject: [PATCH 140/444] Added access denied exception --- src/Exception/OAuthServerException.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index f5630c63..701f1335 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -191,6 +191,18 @@ class OAuthServerException extends \Exception return new static('The refresh token is invalid.', 'invalid_request', 400, $hint); } + /** + * Access denied + * + * @param null|string $hint + * + * @return static + */ + public static function accessDenied($hint = null) + { + return new static('The resource owner or authorization server denied the request.', 401, $hint); + } + /** * @return string */ From 03391e963061907a3993720e9b679178284e1bee Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 12:58:15 +0000 Subject: [PATCH 141/444] Removed old access denied exception --- src/Exception/AccessDeniedException.php | 36 ------------------------- 1 file changed, 36 deletions(-) delete mode 100644 src/Exception/AccessDeniedException.php diff --git a/src/Exception/AccessDeniedException.php b/src/Exception/AccessDeniedException.php deleted file mode 100644 index e5d84b61..00000000 --- a/src/Exception/AccessDeniedException.php +++ /dev/null @@ -1,36 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Exception; - -/** - * Exception class - */ -class AccessDeniedException extends OAuthException -{ - /** - * {@inheritdoc} - */ - public $httpStatusCode = 401; - - /** - * {@inheritdoc} - */ - public $errorType = 'access_denied'; - - /** - * {@inheritdoc} - */ - public function __construct() - { - parent::__construct('The resource owner or authorization server denied the request.'); - } -} From 8d8dbaea0c1e05c667b0d302d80ef8a1ca039dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Sun, 17 Jan 2016 14:35:43 +0100 Subject: [PATCH 142/444] normalize validatescopes --- src/Grant/AbstractGrant.php | 98 ++++++++++++++-------------- src/Grant/ClientCredentialsGrant.php | 2 +- src/Grant/PasswordGrant.php | 2 +- src/Grant/RefreshTokenGrant.php | 2 +- 4 files changed, 53 insertions(+), 51 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index ff7aaced..78e7fce0 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -99,6 +99,14 @@ abstract class AbstractGrant implements GrantTypeInterface return $this->respondsWith; } + /** + * @inheritdoc + */ + public function setEmitter(EmitterInterface $emitter) + { + $this->emitter = $emitter; + } + /** * @param \Psr\Http\Message\ServerRequestInterface $request * @@ -142,6 +150,48 @@ abstract class AbstractGrant implements GrantTypeInterface return $client; } + /** + * @param \Psr\Http\Message\ServerRequestInterface $request + * @param string $scopeDelimiterString + * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client + * @param string $redirectUri + * + * @return \League\OAuth2\Server\Entities\ScopeEntity[] + * + * @throws \League\OAuth2\Server\Exception\OAuthServerException + */ + public function validateScopes( + ServerRequestInterface $request, + $scopeDelimiterString, + ClientEntityInterface $client, + $redirectUri = null + ) { + $requestedScopes = $this->getRequestParameter('scope', $request); + $scopesList = array_filter( + explode($scopeDelimiterString, trim($requestedScopes)), + function ($scope) { + return !empty($scope); + } + ); + + $scopes = []; + foreach ($scopesList as $scopeItem) { + $scope = $this->scopeRepository->getScopeEntityByIdentifier( + $scopeItem, + $this->getIdentifier(), + $client->getIdentifier() + ); + + if (($scope instanceof ScopeEntity) === false) { + throw OAuthServerException::invalidScope($scopeItem, null, null, $redirectUri); + } + + $scopes[] = $scope; + } + + return $scopes; + } + /** * Retrieve request parameter. * @@ -170,54 +220,6 @@ abstract class AbstractGrant implements GrantTypeInterface return (isset($request->getServerParams()[$parameter])) ? $request->getServerParams()[$parameter] : $default; } - /** - * @param string $scopeParamValue A string containing a delimited set of scope identifiers - * @param string $scopeDelimiterString The delimiter between the scopes in the value string - * @param ClientEntityInterface $client - * @param string $redirectUri - * - * @return \League\OAuth2\Server\Entities\ScopeEntity[] - * @throws \League\OAuth2\Server\Exception\OAuthServerException - */ - public function validateScopes( - $scopeParamValue, - $scopeDelimiterString, - ClientEntityInterface $client, - $redirectUri = null - ) { - $scopesList = array_filter( - explode($scopeDelimiterString, trim($scopeParamValue)), - function ($scope) { - return !empty($scope); - } - ); - - $scopes = []; - foreach ($scopesList as $scopeItem) { - $scope = $this->scopeRepository->getScopeEntityByIdentifier( - $scopeItem, - $this->getIdentifier(), - $client->getIdentifier() - ); - - if (($scope instanceof ScopeEntity) === false) { - throw OAuthServerException::invalidScope($scopeItem, null, null, $redirectUri); - } - - $scopes[] = $scope; - } - - return $scopes; - } - - /** - * @inheritdoc - */ - public function setEmitter(EmitterInterface $emitter) - { - $this->emitter = $emitter; - } - /** * @param \DateInterval $tokenTTL * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 1ed22b8d..fb0fafb8 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -39,7 +39,7 @@ class ClientCredentialsGrant extends AbstractGrant ) { // Validate request $client = $this->validateClient($request); - $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $scopeDelimiter, $client); + $scopes = $this->validateScopes($request, $scopeDelimiter, $client); // Issue and persist access token $accessToken = $this->issueAccessToken($tokenTTL, $client, $client->getIdentifier(), $scopes); diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 30702744..60287d64 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -77,7 +77,7 @@ class PasswordGrant extends AbstractGrant // Validate request $client = $this->validateClient($request); $user = $this->validateUser($request); - $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $scopeDelimiter, $client); + $scopes = $this->validateScopes($request, $scopeDelimiter, $client); // Issue and persist new tokens $accessToken = $this->issueAccessToken($tokenTTL, $client, $user->getIdentifier(), $scopes); diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 4747811b..6db2b1c9 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -74,7 +74,7 @@ class RefreshTokenGrant extends AbstractGrant ) { $client = $this->validateClient($request); $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier()); - $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $scopeDelimiter, $client); + $scopes = $this->validateScopes($request, $scopeDelimiter, $client); // If no new scopes are requested then give the access token the original session scopes if (count($scopes) === 0) { From 90d9d7bdd67eb13a2e8c89bcfdbbdec8873ab9c7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 13:47:44 +0000 Subject: [PATCH 143/444] Required repositories are now set by the server --- src/Grant/AbstractGrant.php | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index ff7aaced..ed2404f2 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -69,20 +69,29 @@ abstract class AbstractGrant implements GrantTypeInterface protected $scopeRepository; /** - * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository - * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository - * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository + * @param ClientRepositoryInterface $clientRepository */ - public function __construct( - ClientRepositoryInterface $clientRepository, - ScopeRepositoryInterface $scopeRepository, - AccessTokenRepositoryInterface $accessTokenRepository - ) { + public function setClientRepository(ClientRepositoryInterface $clientRepository) + { $this->clientRepository = $clientRepository; - $this->scopeRepository = $scopeRepository; + } + + /** + * @param AccessTokenRepositoryInterface $accessTokenRepository + */ + public function setAccessTokenRepository(AccessTokenRepositoryInterface $accessTokenRepository) + { $this->accessTokenRepository = $accessTokenRepository; } + /** + * @param ScopeRepositoryInterface $scopeRepository + */ + public function setScopeRepository(ScopeRepositoryInterface $scopeRepository) + { + $this->scopeRepository = $scopeRepository; + } + /** * {@inheritdoc} */ From f74bca33abf58b337c2d5cb7103b4faf8abf1a09 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 13:48:40 +0000 Subject: [PATCH 144/444] Removed parameters that are no longer required --- src/Grant/PasswordGrant.php | 12 ------------ src/Grant/RefreshTokenGrant.php | 11 ----------- 2 files changed, 23 deletions(-) diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 30702744..2ebb5afe 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -12,13 +12,9 @@ namespace League\OAuth2\Server\Grant; use League\Event\Event; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; -use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; -use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; -use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ServerRequestInterface; @@ -47,20 +43,12 @@ class PasswordGrant extends AbstractGrant /** * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository - * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository - * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository - * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository */ public function __construct( UserRepositoryInterface $userRepository, - ClientRepositoryInterface $clientRepository, - ScopeRepositoryInterface $scopeRepository, - AccessTokenRepositoryInterface $accessTokenRepository, RefreshTokenRepositoryInterface $refreshTokenRepository ) { - parent::__construct($clientRepository, $scopeRepository, $accessTokenRepository); - $this->userRepository = $userRepository; $this->refreshTokenRepository = $refreshTokenRepository; } diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 4747811b..f9869b59 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -12,10 +12,7 @@ namespace League\OAuth2\Server\Grant; use League\OAuth2\Server\Exception\OAuthServerException; -use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; -use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; -use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\Utils\KeyCrypt; use Psr\Http\Message\ServerRequestInterface; @@ -45,20 +42,12 @@ class RefreshTokenGrant extends AbstractGrant /** * @param string $pathToPublicKey - * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository - * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository - * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository */ public function __construct( $pathToPublicKey, - ClientRepositoryInterface $clientRepository, - ScopeRepositoryInterface $scopeRepository, - AccessTokenRepositoryInterface $accessTokenRepository, RefreshTokenRepositoryInterface $refreshTokenRepository ) { - parent::__construct($clientRepository, $scopeRepository, $accessTokenRepository); - $this->pathToPublicKey = $pathToPublicKey; $this->refreshTokenRepository = $refreshTokenRepository; } From e6cc6c35ecce1b3be416f97590b75ff3c7632efa Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 13:49:53 +0000 Subject: [PATCH 145/444] Scope delimiter string is now a constant --- src/Grant/AbstractGrant.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index ed2404f2..934456e6 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -29,6 +29,8 @@ use Psr\Http\Message\ServerRequestInterface; */ abstract class AbstractGrant implements GrantTypeInterface { + const SCOPE_DELIMITER_STRING = ' '; + /** * Grant identifier * @@ -181,7 +183,6 @@ abstract class AbstractGrant implements GrantTypeInterface /** * @param string $scopeParamValue A string containing a delimited set of scope identifiers - * @param string $scopeDelimiterString The delimiter between the scopes in the value string * @param ClientEntityInterface $client * @param string $redirectUri * @@ -190,12 +191,11 @@ abstract class AbstractGrant implements GrantTypeInterface */ public function validateScopes( $scopeParamValue, - $scopeDelimiterString, ClientEntityInterface $client, $redirectUri = null ) { $scopesList = array_filter( - explode($scopeDelimiterString, trim($scopeParamValue)), + explode(self::SCOPE_DELIMITER_STRING, trim($scopeParamValue)), function ($scope) { return !empty($scope); } From ad05a5cae6057fc503ce1abc03415dea1c344080 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 13:51:56 +0000 Subject: [PATCH 146/444] Scope delimiter is no longer a required parameter --- src/Grant/ClientCredentialsGrant.php | 5 ++--- src/Grant/GrantTypeInterface.php | 4 +--- src/Grant/PasswordGrant.php | 5 ++--- src/Grant/RefreshTokenGrant.php | 5 ++--- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 1ed22b8d..05f6a917 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -34,12 +34,11 @@ class ClientCredentialsGrant extends AbstractGrant public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - \DateInterval $tokenTTL, - $scopeDelimiter = ' ' + \DateInterval $tokenTTL ) { // Validate request $client = $this->validateClient($request); - $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $scopeDelimiter, $client); + $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client); // Issue and persist access token $accessToken = $this->issueAccessToken($tokenTTL, $client, $client->getIdentifier(), $scopes); diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index fbaa88a1..3b775bfb 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -41,15 +41,13 @@ interface GrantTypeInterface * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType * @param \DateInterval $tokenTTL - * @param string $scopeDelimiter * * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface */ public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - DateInterval $tokenTTL, - $scopeDelimiter = ' ' + DateInterval $tokenTTL ); /** diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 2ebb5afe..e526384d 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -59,13 +59,12 @@ class PasswordGrant extends AbstractGrant public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - \DateInterval $tokenTTL, - $scopeDelimiter = ' ' + \DateInterval $tokenTTL ) { // Validate request $client = $this->validateClient($request); $user = $this->validateUser($request); - $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $scopeDelimiter, $client); + $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client); // Issue and persist new tokens $accessToken = $this->issueAccessToken($tokenTTL, $client, $user->getIdentifier(), $scopes); diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index f9869b59..21fe4f39 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -58,12 +58,11 @@ class RefreshTokenGrant extends AbstractGrant public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - \DateInterval $tokenTTL, - $scopeDelimiter = ' ' + \DateInterval $tokenTTL ) { $client = $this->validateClient($request); $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier()); - $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $scopeDelimiter, $client); + $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client); // If no new scopes are requested then give the access token the original session scopes if (count($scopes) === 0) { From a4ce1e510ecbfd9042ca3ba11e2849c8c027cc99 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 13:53:18 +0000 Subject: [PATCH 147/444] Scope delimiter string is no longer configurable --- src/Server.php | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/src/Server.php b/src/Server.php index 1c46a0eb..535b7d21 100644 --- a/src/Server.php +++ b/src/Server.php @@ -113,26 +113,6 @@ class Server implements EmitterAwareInterface return $this->defaultAccessTokenTTL; } - /** - * Set the delimiter string used to separate scopes in a request - * - * @param string $scopeDelimiterString - */ - public function setScopeDelimiterString($scopeDelimiterString) - { - $this->scopeDelimiterString = $scopeDelimiterString; - } - - /** - * Get the delimiter string used to separate scopes in a request - * - * @return string - */ - protected function getScopeDelimiterString() - { - return $this->scopeDelimiterString; - } - /** * Enable a grant type on the server * @@ -188,8 +168,7 @@ class Server implements EmitterAwareInterface $tokenResponse = $grantType->respondToRequest( $request, $this->grantResponseTypes[$grantType->getIdentifier()], - $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()], - $this->getScopeDelimiterString() + $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] ); } } From e21a13c82c280f2989d4af89ca3e4c24f9db5b1c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 13:54:39 +0000 Subject: [PATCH 148/444] Access token TTL is now configured on a per grant basis --- src/Server.php | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/src/Server.php b/src/Server.php index 535b7d21..ba4efd0d 100644 --- a/src/Server.php +++ b/src/Server.php @@ -43,15 +43,9 @@ class Server implements EmitterAwareInterface */ protected $defaultResponseType; - /** - * @var DateInterval - */ - protected $defaultAccessTokenTTL; - /** * @var string */ - protected $scopeDelimiterString = ' '; /** * New server instance @@ -90,29 +84,6 @@ class Server implements EmitterAwareInterface } /** - * Set the default TTL of access tokens - * - * @param DateInterval $defaultAccessTokenTTL - */ - public function setDefaultAccessTokenTTL(DateInterval $defaultAccessTokenTTL) - { - $this->defaultAccessTokenTTL = $defaultAccessTokenTTL; - } - - /** - * Get the default TTL of access tokens - * - * @return DateInterval - */ - protected function getDefaultAccessTokenTTL() - { - if (!$this->defaultAccessTokenTTL instanceof \DateInterval) { - $this->defaultAccessTokenTTL = new \DateInterval('PT01H'); // default token TTL of 1 hour - } - - return $this->defaultAccessTokenTTL; - } - /** * Enable a grant type on the server * @@ -123,7 +94,7 @@ class Server implements EmitterAwareInterface public function enableGrantType( GrantTypeInterface $grantType, ResponseTypeInterface $responseType = null, - \DateInterval $accessTokenTTL = null + \DateInterval $accessTokenTTL ) { $grantType->setEmitter($this->getEmitter()); $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; From 0cc13630ccf34276add87aa5f86143763aa404f8 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 13:54:55 +0000 Subject: [PATCH 149/444] Cody tidy --- src/Grant/ClientCredentialsGrant.php | 2 -- src/Grant/RefreshTokenGrant.php | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 05f6a917..a52b9385 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -11,8 +11,6 @@ namespace League\OAuth2\Server\Grant; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ServerRequestInterface; diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 21fe4f39..b84c24c7 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -125,7 +125,7 @@ class RefreshTokenGrant extends AbstractGrant throw OAuthServerException::invalidRefreshToken( 'Token is not linked to client,' . ' got: ' . $clientId . - ' expected: '. $refreshTokenData['client_id'] + ' expected: ' . $refreshTokenData['client_id'] ); } From 645f719ee9be904e502d54e610bbc77b8e51aab7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 13:55:12 +0000 Subject: [PATCH 150/444] Added new repository setter methods to GrantTypeInterface --- src/Grant/GrantTypeInterface.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 3b775bfb..4a474af5 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -13,6 +13,9 @@ namespace League\OAuth2\Server\Grant; use DateInterval; use League\Event\EmitterInterface; +use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ServerRequestInterface; @@ -70,4 +73,26 @@ interface GrantTypeInterface * @param \League\Event\EmitterInterface $emitter */ public function setEmitter(EmitterInterface $emitter); + + /** + * Set the client repository + * + * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository + */ + public function setClientRepository(ClientRepositoryInterface $clientRepository); + + /** + * Set the access token repository + * + * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository + */ + public function setAccessTokenRepository(AccessTokenRepositoryInterface $accessTokenRepository); + + /** + * Set the scope repository + * + * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository + */ + public function setScopeRepository(ScopeRepositoryInterface $scopeRepository); + } From 8ee4dc7eb9550481ef9f0f9ec3a60f39f9d542dc Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 13:56:14 +0000 Subject: [PATCH 151/444] Fixed docblock --- src/ResponseTypes/ResponseTypeInterface.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ResponseTypes/ResponseTypeInterface.php b/src/ResponseTypes/ResponseTypeInterface.php index 00c3ed14..6524f049 100644 --- a/src/ResponseTypes/ResponseTypeInterface.php +++ b/src/ResponseTypes/ResponseTypeInterface.php @@ -29,11 +29,12 @@ interface ResponseTypeInterface public function setRefreshToken(RefreshTokenEntityInterface $refreshToken); /** - * Determine the access token in the authorization header + * Determine the access token in the authorization header and append OAUth properties to the request + * as attributes * * @param ServerRequestInterface $request * - * @return string + * @return ServerRequestInterface */ public function determineAccessTokenInHeader(ServerRequestInterface $request); From c7a904ca40ff22454598867f78d7cdce5de7dc1e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 13:56:46 +0000 Subject: [PATCH 152/444] Added access token repository and public key path as required params to response type constructor --- src/ResponseTypes/AbstractResponseType.php | 24 +++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/ResponseTypes/AbstractResponseType.php b/src/ResponseTypes/AbstractResponseType.php index bed080fd..2388582f 100644 --- a/src/ResponseTypes/AbstractResponseType.php +++ b/src/ResponseTypes/AbstractResponseType.php @@ -13,6 +13,7 @@ namespace League\OAuth2\Server\ResponseTypes; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; abstract class AbstractResponseType implements ResponseTypeInterface { @@ -21,6 +22,11 @@ abstract class AbstractResponseType implements ResponseTypeInterface */ protected $pathToPrivateKey; + /** + * @var string + */ + protected $pathToPublicKey; + /** * @var \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface */ @@ -32,11 +38,23 @@ abstract class AbstractResponseType implements ResponseTypeInterface protected $refreshToken; /** - * @param string $pathToPrivateKey + * @var \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface */ - public function __construct($pathToPrivateKey) - { + protected $accessTokenRepository; + + /** + * @param string $pathToPrivateKey + * @param string $pathToPublicKey + * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository + */ + public function __construct( + $pathToPrivateKey, + $pathToPublicKey, + AccessTokenRepositoryInterface $accessTokenRepository + ) { $this->pathToPrivateKey = $pathToPrivateKey; + $this->pathToPublicKey = $pathToPublicKey; + $this->accessTokenRepository = $accessTokenRepository; } /** From d755a8c01ddc5214f4c5964c4181aeafce60b7a8 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 13:57:07 +0000 Subject: [PATCH 153/444] Updated the validation to BearerTokenResponse --- src/ResponseTypes/BearerTokenResponse.php | 25 +++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index 2397286e..d714b5b3 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -12,6 +12,7 @@ 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; @@ -78,8 +79,28 @@ class BearerTokenResponse extends AbstractResponseType public function determineAccessTokenInHeader(ServerRequestInterface $request) { $header = $request->getHeader('authorization'); - $accessToken = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header)); + $jwt = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header)); - return ($accessToken === 'Bearer') ? '' : $accessToken; + try { + // Attempt to parse and validate the JWT + $token = (new Parser())->parse($jwt); + if ($token->verify(new Sha256(), $this->pathToPublicKey) === false) { + return $request; + } + + // Check if token has been revoked + if ($this->accessTokenRepository->isAccessTokenRevoked($token->getClaim('jwt'))) { + return $request; + } + + // Return the request with additional attributes + return $request->withAttribute('oauth_access_token', $token->getClaim('jti')) + ->withAttribute('oauth_client_id', $token->getClaim('aud')) + ->withAttribute('oauth_user_id', $token->getClaim('sub')) + ->withAttribute('oauth_scopes', $token->getClaim('scopes')); + } catch (\InvalidArgumentException $e) { + // JWT couldn't be parsed so return the request as is + return $request; + } } } From e43d95415bd8b69934df7c269b76468cc66c473b Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:03:07 +0000 Subject: [PATCH 154/444] Inject required params into grant type --- src/Server.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Server.php b/src/Server.php index ba4efd0d..f0df7d61 100644 --- a/src/Server.php +++ b/src/Server.php @@ -77,7 +77,11 @@ class Server implements EmitterAwareInterface protected function getDefaultResponseType() { if (!$this->defaultResponseType instanceof ResponseTypeInterface) { - $this->defaultResponseType = new BearerTokenResponse($this->defaultPrivateKeyPath); + $this->defaultResponseType = new BearerTokenResponse( + $this->defaultPrivateKeyPath, + $this->defaultPublicKeyPath, + $this->accessTokenRepository + ); } return $this->defaultResponseType; @@ -96,6 +100,10 @@ class Server implements EmitterAwareInterface ResponseTypeInterface $responseType = null, \DateInterval $accessTokenTTL ) { + $grantType->setAccessTokenRepository($this->accessTokenRepository); + $grantType->setClientRepository($this->clientRepository); + $grantType->setScopeRepository($this->scopeRepository); + $grantType->setEmitter($this->getEmitter()); $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; From 6332ecfa0b7b9ce1147768802ebb5306d4899aa0 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:03:33 +0000 Subject: [PATCH 155/444] Removed default overrides --- src/Server.php | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/Server.php b/src/Server.php index f0df7d61..b9d67e24 100644 --- a/src/Server.php +++ b/src/Server.php @@ -87,17 +87,14 @@ class Server implements EmitterAwareInterface return $this->defaultResponseType; } - /** /** * Enable a grant type on the server * * @param \League\OAuth2\Server\Grant\GrantTypeInterface $grantType - * @param ResponseTypeInterface $responseType * @param DateInterval $accessTokenTTL */ public function enableGrantType( GrantTypeInterface $grantType, - ResponseTypeInterface $responseType = null, \DateInterval $accessTokenTTL ) { $grantType->setAccessTokenRepository($this->accessTokenRepository); @@ -108,18 +105,10 @@ class Server implements EmitterAwareInterface $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; // Set grant response type - if ($responseType instanceof ResponseTypeInterface) { - $this->grantResponseTypes[$grantType->getIdentifier()] = $responseType; - } else { - $this->grantResponseTypes[$grantType->getIdentifier()] = $this->getDefaultResponseType(); - } + $this->grantResponseTypes[$grantType->getIdentifier()] = $this->getDefaultResponseType(); // Set grant access token TTL - if ($accessTokenTTL instanceof \DateInterval) { - $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL; - } else { - $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $this->getDefaultAccessTokenTTL(); - } + $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL; } /** From cd68103267ceb84dcffbbf7277a40319f86b6495 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:03:41 +0000 Subject: [PATCH 156/444] New server constructor --- src/Server.php | 53 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/src/Server.php b/src/Server.php index b9d67e24..dfb61303 100644 --- a/src/Server.php +++ b/src/Server.php @@ -7,6 +7,9 @@ use League\Event\EmitterAwareInterface; use League\Event\EmitterAwareTrait; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\GrantTypeInterface; +use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ResponseInterface; @@ -46,27 +49,47 @@ class Server implements EmitterAwareInterface /** * @var string */ + private $defaultPublicKeyPath; + + /** + * @var \League\OAuth2\Server\Repositories\ClientRepositoryInterface + */ + private $clientRepository; + + /** + * @var \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface + */ + private $accessTokenRepository; + + /** + * @var \League\OAuth2\Server\Repositories\ScopeRepositoryInterface + */ + private $scopeRepository; /** * New server instance * - * @param string $defaultPrivateKeyPath - * @param DateInterval $defaultAccessTokenTTL + * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository + * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository + * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository + * @param string $defaultPrivateKeyPath + * @param string $defaultPublicKeyPath + * @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType */ - public function __construct($defaultPrivateKeyPath, \DateInterval $defaultAccessTokenTTL = null) - { + public function __construct( + ClientRepositoryInterface $clientRepository, + AccessTokenRepositoryInterface $accessTokenRepository, + ScopeRepositoryInterface $scopeRepository, + $defaultPrivateKeyPath, + $defaultPublicKeyPath, + ResponseTypeInterface $responseType = null + ) { $this->defaultPrivateKeyPath = $defaultPrivateKeyPath; - $this->defaultAccessTokenTTL = $defaultAccessTokenTTL; - } - - /** - * Set the default token type that grants will return - * - * @param ResponseTypeInterface $defaultTokenType - */ - public function setDefaultResponseType(ResponseTypeInterface $defaultTokenType) - { - $this->defaultResponseType = $defaultTokenType; + $this->defaultPublicKeyPath = $defaultPublicKeyPath; + $this->clientRepository = $clientRepository; + $this->accessTokenRepository = $accessTokenRepository; + $this->scopeRepository = $scopeRepository; + $this->defaultResponseType = $responseType; } /** From 6c787c374ca82438dc4ecc13155b0b8faca1c3b5 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:08:42 +0000 Subject: [PATCH 157/444] First commit of ResourceServerMiddleware --- src/Middleware/ResourceServerMiddleware.php | 54 +++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/Middleware/ResourceServerMiddleware.php diff --git a/src/Middleware/ResourceServerMiddleware.php b/src/Middleware/ResourceServerMiddleware.php new file mode 100644 index 00000000..b1f26bf2 --- /dev/null +++ b/src/Middleware/ResourceServerMiddleware.php @@ -0,0 +1,54 @@ +server = $server; + } + + /** + * @param \Psr\Http\Message\ServerRequestInterface $request + * @param \Psr\Http\Message\ResponseInterface $response + * @param callable $next + * + * @return \Psr\Http\Message\ResponseInterface + */ + public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) + { + if ($request->hasHeader('authorization') === false) { + $exception = OAuthServerException::accessDenied('Missing authorization header'); + + return $exception->generateHttpResponse($response); + } + + $request = $this->server->getDefaultResponseType()->determineAccessTokenInHeader($request); + + if ($request->getAttribute('oauth_access_token') === null) { + $exception = OAuthServerException::accessDenied('Access token was invalid'); + + return $exception->generateHttpResponse($response); + } + + // Pass the request and response on to the next responder in the chain + return $next($request, $response); + } +} From 19b12cda8e1d7e8372436e044fba5cab57bf7012 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:08:53 +0000 Subject: [PATCH 158/444] Made getDefaultResponseType public --- src/Server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Server.php b/src/Server.php index dfb61303..9c8e21e7 100644 --- a/src/Server.php +++ b/src/Server.php @@ -97,7 +97,7 @@ class Server implements EmitterAwareInterface * * @return ResponseTypeInterface */ - protected function getDefaultResponseType() + public function getDefaultResponseType() { if (!$this->defaultResponseType instanceof ResponseTypeInterface) { $this->defaultResponseType = new BearerTokenResponse( From 5f22ead2871ae7f1d9051f5f52384e09d6c2a7bf Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:11:21 +0000 Subject: [PATCH 159/444] Updated access denied hint --- src/Exception/OAuthServerException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 701f1335..c7a04b9c 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -200,7 +200,7 @@ class OAuthServerException extends \Exception */ public static function accessDenied($hint = null) { - return new static('The resource owner or authorization server denied the request.', 401, $hint); + return new static('The server denied the request.', 401, $hint); } /** From f6664c69178a67f011b996c42a68364948c3c7c2 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:21:35 +0000 Subject: [PATCH 160/444] Private and public key paths are injected into grants now --- src/Grant/AbstractGrant.php | 26 ++++++++++++++++++++++++++ src/Grant/GrantTypeInterface.php | 13 +++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 934456e6..74af64b9 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -70,6 +70,16 @@ abstract class AbstractGrant implements GrantTypeInterface */ protected $scopeRepository; + /** + * @var string + */ + protected $pathToPrivateKey; + + /** + * @var string + */ + protected $pathToPublicKey; + /** * @param ClientRepositoryInterface $clientRepository */ @@ -94,6 +104,22 @@ abstract class AbstractGrant implements GrantTypeInterface $this->scopeRepository = $scopeRepository; } + /** + * @param string $pathToPrivateKey + */ + public function setPathToPrivateKey($pathToPrivateKey) + { + $this->pathToPrivateKey = $pathToPrivateKey; + } + + /** + * @param string $pathToPublicKey + */ + public function setPathToPublicKey($pathToPublicKey) + { + $this->pathToPublicKey = $pathToPublicKey; + } + /** * {@inheritdoc} */ diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 4a474af5..5bc9bf08 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -95,4 +95,17 @@ interface GrantTypeInterface */ public function setScopeRepository(ScopeRepositoryInterface $scopeRepository); + /** + * Set the path to the private key + * + * @param string $pathToPrivateKey + */ + public function setPathToPrivateKey($pathToPrivateKey); + + /** + * Set the path to the public key + * + * @param string $pathToPublicKey + */ + public function setPathToPublicKey($pathToPublicKey); } From 5a8659471c5eb1b681694494aca48283326eb961 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:21:53 +0000 Subject: [PATCH 161/444] Public key is set in abstract grant now --- src/Grant/RefreshTokenGrant.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index b84c24c7..99e32401 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -30,25 +30,17 @@ class RefreshTokenGrant extends AbstractGrant */ protected $identifier = 'refresh_token'; - /** - * @var string - */ - private $pathToPublicKey; - /** * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface */ private $refreshTokenRepository; /** - * @param string $pathToPublicKey * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository */ public function __construct( - $pathToPublicKey, RefreshTokenRepositoryInterface $refreshTokenRepository ) { - $this->pathToPublicKey = $pathToPublicKey; $this->refreshTokenRepository = $refreshTokenRepository; } From 0486d93fa342949841297fc885c3c5d1d202f5aa Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:23:02 +0000 Subject: [PATCH 162/444] Removed default wording as there are no overrides --- src/Server.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Server.php b/src/Server.php index 9c8e21e7..c2d90037 100644 --- a/src/Server.php +++ b/src/Server.php @@ -39,7 +39,7 @@ class Server implements EmitterAwareInterface /** * @var string */ - protected $defaultPrivateKeyPath; + protected $privateKeyPath; /** * @var ResponseTypeInterface @@ -49,7 +49,7 @@ class Server implements EmitterAwareInterface /** * @var string */ - private $defaultPublicKeyPath; + private $publicKeyPath; /** * @var \League\OAuth2\Server\Repositories\ClientRepositoryInterface @@ -72,24 +72,24 @@ class Server implements EmitterAwareInterface * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository - * @param string $defaultPrivateKeyPath - * @param string $defaultPublicKeyPath + * @param string $privateKeyPath + * @param string $publicKeyPath * @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType */ public function __construct( ClientRepositoryInterface $clientRepository, AccessTokenRepositoryInterface $accessTokenRepository, ScopeRepositoryInterface $scopeRepository, - $defaultPrivateKeyPath, - $defaultPublicKeyPath, + $privateKeyPath, + $publicKeyPath, ResponseTypeInterface $responseType = null ) { - $this->defaultPrivateKeyPath = $defaultPrivateKeyPath; - $this->defaultPublicKeyPath = $defaultPublicKeyPath; $this->clientRepository = $clientRepository; $this->accessTokenRepository = $accessTokenRepository; $this->scopeRepository = $scopeRepository; $this->defaultResponseType = $responseType; + $this->privateKeyPath = $privateKeyPath; + $this->publicKeyPath = $publicKeyPath; } /** @@ -123,6 +123,8 @@ class Server implements EmitterAwareInterface $grantType->setAccessTokenRepository($this->accessTokenRepository); $grantType->setClientRepository($this->clientRepository); $grantType->setScopeRepository($this->scopeRepository); + $grantType->setPathToPrivateKey($this->privateKeyPath); + $grantType->setPathToPublicKey($this->publicKeyPath); $grantType->setEmitter($this->getEmitter()); $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; From 3d08051cbbc5186aa20eae3c2a81fbbd97dce9ec Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:23:18 +0000 Subject: [PATCH 163/444] Removed default wording as there is no override --- src/Middleware/ResourceServerMiddleware.php | 2 +- src/Server.php | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Middleware/ResourceServerMiddleware.php b/src/Middleware/ResourceServerMiddleware.php index b1f26bf2..70711b94 100644 --- a/src/Middleware/ResourceServerMiddleware.php +++ b/src/Middleware/ResourceServerMiddleware.php @@ -40,7 +40,7 @@ class ResourceServerMiddleware return $exception->generateHttpResponse($response); } - $request = $this->server->getDefaultResponseType()->determineAccessTokenInHeader($request); + $request = $this->server->getResponseType()->determineAccessTokenInHeader($request); if ($request->getAttribute('oauth_access_token') === null) { $exception = OAuthServerException::accessDenied('Access token was invalid'); diff --git a/src/Server.php b/src/Server.php index c2d90037..034173cc 100644 --- a/src/Server.php +++ b/src/Server.php @@ -44,7 +44,7 @@ class Server implements EmitterAwareInterface /** * @var ResponseTypeInterface */ - protected $defaultResponseType; + protected $responseType; /** * @var string @@ -87,27 +87,27 @@ class Server implements EmitterAwareInterface $this->clientRepository = $clientRepository; $this->accessTokenRepository = $accessTokenRepository; $this->scopeRepository = $scopeRepository; - $this->defaultResponseType = $responseType; $this->privateKeyPath = $privateKeyPath; $this->publicKeyPath = $publicKeyPath; + $this->responseType = $responseType; } /** - * Get the default token type that grants will return + * Get the token type that grants will return in the HTTP response * * @return ResponseTypeInterface */ - public function getDefaultResponseType() + public function getResponseType() { - if (!$this->defaultResponseType instanceof ResponseTypeInterface) { - $this->defaultResponseType = new BearerTokenResponse( - $this->defaultPrivateKeyPath, - $this->defaultPublicKeyPath, + if (!$this->responseType instanceof ResponseTypeInterface) { + $this->responseType = new BearerTokenResponse( + $this->privateKeyPath, + $this->publicKeyPath, $this->accessTokenRepository ); } - return $this->defaultResponseType; + return $this->responseType; } /** @@ -130,7 +130,7 @@ class Server implements EmitterAwareInterface $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; // Set grant response type - $this->grantResponseTypes[$grantType->getIdentifier()] = $this->getDefaultResponseType(); + $this->grantResponseTypes[$grantType->getIdentifier()] = $this->getResponseType(); // Set grant access token TTL $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL; From 168e7640c6e8217b7e961151de522810b3edce6e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:23:42 +0000 Subject: [PATCH 164/444] Updated examples to use new API --- examples/public/client_credentials.php | 38 +++++++++++++------ examples/public/password.php | 52 +++++++++++++++----------- 2 files changed, 57 insertions(+), 33 deletions(-) diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index 1e671d3a..684e3003 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -14,19 +14,33 @@ use Slim\Http\Response; include(__DIR__ . '/../vendor/autoload.php'); -// Setup the authorization server -$server = new Server('file://' . __DIR__ . '/../private.key'); - -// Init our repositories -$clientRepository = new ClientRepository(); -$scopeRepository = new ScopeRepository(); -$accessTokenRepository = new AccessTokenRepository(); - -// Enable the client credentials grant on the server -$server->enableGrantType(new ClientCredentialsGrant($clientRepository, $scopeRepository, $accessTokenRepository)); - // App -$app = new App([Server::class => $server]); +$app = new App([ + Server::class => function () { + + // Init our repositories + $clientRepository = new ClientRepository(); + $scopeRepository = new ScopeRepository(); + $accessTokenRepository = new AccessTokenRepository(); + + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + + // Setup the authorization server + $server = new Server( + $clientRepository, + $accessTokenRepository, + $scopeRepository, + $privateKeyPath, + $publicKeyPath + ); + + // Enable the client credentials grant on the server with a token TTL of 1 hour + $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1H')); + + return $server; + } +]); $app->post('/access_token', function (Request $request, Response $response) { /** @var Server $server */ diff --git a/examples/public/password.php b/examples/public/password.php index de73d63d..1be26880 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -16,28 +16,38 @@ use Slim\Http\Response; include(__DIR__ . '/../vendor/autoload.php'); -// Setup the authorization server -$server = new Server('file://' . __DIR__ . '/../private.key'); - -// Init our repositories -$userRepository = new UserRepository(); -$clientRepository = new ClientRepository(); -$scopeRepository = new ScopeRepository(); -$accessTokenRepository = new AccessTokenRepository(); -$refreshTokenRepository = new RefreshTokenRepository(); - -// Enable the client credentials grant on the server -$passwordGrant = new PasswordGrant( - $userRepository, - $clientRepository, - $scopeRepository, - $accessTokenRepository, - $refreshTokenRepository -); -$server->enableGrantType($passwordGrant); - // App -$app = new App([Server::class => $server]); +$app = new App([ + Server::class => function () { + + // Init our repositories + $clientRepository = new ClientRepository(); + $scopeRepository = new ScopeRepository(); + $accessTokenRepository = new AccessTokenRepository(); + $userRepository = new UserRepository(); + $refreshTokenRepository = new RefreshTokenRepository(); + + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + + // Setup the authorization server + $server = new Server( + $clientRepository, + $accessTokenRepository, + $scopeRepository, + $privateKeyPath, + $publicKeyPath + ); + + // Enable the client credentials grant on the server with a token TTL of 1 hour + $server->enableGrantType( + new PasswordGrant($userRepository, $refreshTokenRepository), + new \DateInterval('PT1H') + ); + + return $server; + } +]); $app->post('/access_token', function (Request $request, Response $response) { /** @var Server $server */ From 3c4347e3859f201ba33272bbaf8de135a6ccf28a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:25:44 +0000 Subject: [PATCH 165/444] Updated refresh token example --- examples/public/refresh_token.php | 44 +++++++++++++++++-------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index d41e940b..ad9bf0cb 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -8,7 +8,6 @@ use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; -use OAuth2ServerExamples\Repositories\UserRepository; use Slim\App; use Slim\Http\Request; @@ -16,28 +15,33 @@ use Slim\Http\Response; include(__DIR__ . '/../vendor/autoload.php'); -// Setup the authorization server -$server = new Server('file://' . __DIR__ . '/../private.key'); -// Init our repositories -$userRepository = new UserRepository(); -$clientRepository = new ClientRepository(); -$scopeRepository = new ScopeRepository(); -$accessTokenRepository = new AccessTokenRepository(); -$refreshTokenRepository = new RefreshTokenRepository(); - -// Enable the client credentials grant on the server -$refreshTokenGrant = new RefreshTokenGrant( - 'file://' . __DIR__ . '/../public.key', - $clientRepository, - $scopeRepository, - $accessTokenRepository, - $refreshTokenRepository -); -$server->enableGrantType($refreshTokenGrant); // App -$app = new App([Server::class => $server]); +$app = new App([Server::class => function () { + // Init our repositories + $clientRepository = new ClientRepository(); + $scopeRepository = new ScopeRepository(); + $accessTokenRepository = new AccessTokenRepository(); + $refreshTokenRepository = new RefreshTokenRepository(); + + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + + // Setup the authorization server + $server = new Server( + $clientRepository, + $accessTokenRepository, + $scopeRepository, + $privateKeyPath, + $publicKeyPath + ); + + // Enable the refresh token grant on the server + $server->enableGrantType(new RefreshTokenGrant($refreshTokenRepository), new \DateInterval('PT1H')); + + return $server; +}]); $app->post('/access_token', function (Request $request, Response $response) { /** @var Server $server */ From 06ee612bb1c5a664ab8e546057a78d6841c00d4c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:25:54 +0000 Subject: [PATCH 166/444] Updated composer.lock in example --- examples/composer.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/composer.lock b/examples/composer.lock index 466319f3..251ab498 100644 --- a/examples/composer.lock +++ b/examples/composer.lock @@ -148,7 +148,7 @@ "dist": { "type": "path", "url": "../", - "reference": "dce1620f60d9f1a44a9ec99b6168810a8030c20c", + "reference": "168e7640c6e8217b7e961151de522810b3edce6e", "shasum": null }, "require": { From 660378c7b35e03a7c0b82394fd7d333f1e9eb23d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:28:13 +0000 Subject: [PATCH 167/444] Added MAC auth scheme to 401 header --- src/Exception/OAuthServerException.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index c7a04b9c..baf16f50 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -280,6 +280,8 @@ class OAuthServerException extends \Exception if ($authHeader !== []) { if (strpos($authHeader[0], 'Bearer') === 0) { $authScheme = 'Bearer'; + } elseif (strpos($authHeader[0], 'MAC') === 0) { + $authScheme = 'MAC'; } elseif (strpos($authHeader[0], 'Basic') === 0) { $authScheme = 'Basic'; } From cd19f117996b6cd29c971991f2d21d2700ac5355 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:55:36 +0000 Subject: [PATCH 168/444] Fixed conversion to response object --- src/Exception/OAuthServerException.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index baf16f50..46a79c1a 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -243,9 +243,9 @@ class OAuthServerException extends \Exception $response = $response->withHeader($header, $content); } - return $response - ->withStatus($this->getHttpStatusCode()) - ->getBody()->write(json_encode($payload)); + $response = $response->withStatus($this->getHttpStatusCode()); + $response->getBody()->write(json_encode($payload)); + return $response; } /** From 212938d1e243db748ba3405d2e616b5f496041ba Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:55:48 +0000 Subject: [PATCH 169/444] Fixed call to static --- src/Exception/OAuthServerException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 46a79c1a..b0309290 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -200,7 +200,7 @@ class OAuthServerException extends \Exception */ public static function accessDenied($hint = null) { - return new static('The server denied the request.', 401, $hint); + return new static('The server denied the request.', 'access_denied', 401, $hint); } /** From f1d06e7c3383770334dd3396618170f0db13f199 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:56:06 +0000 Subject: [PATCH 170/444] Use the error returned from the response type --- src/Middleware/ResourceServerMiddleware.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Middleware/ResourceServerMiddleware.php b/src/Middleware/ResourceServerMiddleware.php index 70711b94..fda7861d 100644 --- a/src/Middleware/ResourceServerMiddleware.php +++ b/src/Middleware/ResourceServerMiddleware.php @@ -43,7 +43,7 @@ class ResourceServerMiddleware $request = $this->server->getResponseType()->determineAccessTokenInHeader($request); if ($request->getAttribute('oauth_access_token') === null) { - $exception = OAuthServerException::accessDenied('Access token was invalid'); + $exception = OAuthServerException::accessDenied($request->getAttribute('oauth_access_token_error')); return $exception->generateHttpResponse($response); } From 419cb6d1498749092c32551d6a38ddf6b8a31918 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:56:35 +0000 Subject: [PATCH 171/444] Use first array result --- src/ResponseTypes/BearerTokenResponse.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index d714b5b3..5315e112 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -79,7 +79,7 @@ class BearerTokenResponse extends AbstractResponseType public function determineAccessTokenInHeader(ServerRequestInterface $request) { $header = $request->getHeader('authorization'); - $jwt = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header)); + $jwt = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header[0])); try { // Attempt to parse and validate the JWT From 8566a128c8244d0e8277ccdcc50f8cace780ea47 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:56:42 +0000 Subject: [PATCH 172/444] Pass errors back up the chain --- src/ResponseTypes/BearerTokenResponse.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index 5315e112..278b166d 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -85,12 +85,12 @@ class BearerTokenResponse extends AbstractResponseType // Attempt to parse and validate the JWT $token = (new Parser())->parse($jwt); if ($token->verify(new Sha256(), $this->pathToPublicKey) === false) { - return $request; + return $request->withAttribute('oauth_access_token_error', 'Access token could not be verified'); } // Check if token has been revoked - if ($this->accessTokenRepository->isAccessTokenRevoked($token->getClaim('jwt'))) { - return $request; + if ($this->accessTokenRepository->isAccessTokenRevoked($token->getClaim('jti'))) { + return $request->withAttribute('oauth_access_token_error', 'Access token has been revoked'); } // Return the request with additional attributes @@ -100,7 +100,7 @@ class BearerTokenResponse extends AbstractResponseType ->withAttribute('oauth_scopes', $token->getClaim('scopes')); } catch (\InvalidArgumentException $e) { // JWT couldn't be parsed so return the request as is - return $request; + return $request->withAttribute('oauth_access_token_error', $e->getMessage()); } } } From cbd45cc5ab93db70df12ef99ce8ea0c163e86d3c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 14:56:51 +0000 Subject: [PATCH 173/444] Added protected API example --- examples/public/protected_api.php | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 examples/public/protected_api.php diff --git a/examples/public/protected_api.php b/examples/public/protected_api.php new file mode 100644 index 00000000..f7362d63 --- /dev/null +++ b/examples/public/protected_api.php @@ -0,0 +1,66 @@ + [ + 'displayErrorDetails' => true, + ], + Server::class => function () { + + // Init our repositories + $clientRepository = new ClientRepository(); + $scopeRepository = new ScopeRepository(); + $accessTokenRepository = new AccessTokenRepository(); + + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + + // Setup the authorization server + $server = new Server( + $clientRepository, + $accessTokenRepository, + $scopeRepository, + $privateKeyPath, + $publicKeyPath + ); + + return $server; + } +]); + +$app->add(new ResourceServerMiddleware($app->getContainer()->get(Server::class))); +$app->post('/api/example', function (Request $request, Response $response) { + + $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'; + } + + $response->getBody()->write(json_encode($params)); + + return $response; +}); + +$app->run(); From 6cffbfe33b573e2afe0866bbc38ae972d4eb4b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Sun, 17 Jan 2016 17:01:08 +0100 Subject: [PATCH 174/444] remove scopedelimiter parameter --- src/Grant/ClientCredentialsGrant.php | 2 +- src/Grant/PasswordGrant.php | 2 +- src/Grant/RefreshTokenGrant.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 17b944f4..03c6c721 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -36,7 +36,7 @@ class ClientCredentialsGrant extends AbstractGrant ) { // Validate request $client = $this->validateClient($request); - $scopes = $this->validateScopes($request, $scopeDelimiter, $client); + $scopes = $this->validateScopes($request, $client); // Issue and persist access token $accessToken = $this->issueAccessToken($tokenTTL, $client, $client->getIdentifier(), $scopes); diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 351954b4..50593ef3 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -64,7 +64,7 @@ class PasswordGrant extends AbstractGrant // Validate request $client = $this->validateClient($request); $user = $this->validateUser($request); - $scopes = $this->validateScopes($request, $scopeDelimiter, $client); + $scopes = $this->validateScopes($request, $client); // Issue and persist new tokens $accessToken = $this->issueAccessToken($tokenTTL, $client, $user->getIdentifier(), $scopes); diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 99b6b402..f17b25e0 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -54,7 +54,7 @@ class RefreshTokenGrant extends AbstractGrant ) { $client = $this->validateClient($request); $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier()); - $scopes = $this->validateScopes($request, $scopeDelimiter, $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) { From 6beb8d42ff2715d36565f5cec8984f57b1490236 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 16:16:01 +0000 Subject: [PATCH 175/444] Replaced SecureKey::generate with random_bytes method --- composer.json | 3 +- src/Utils/KeyAlgorithm/DefaultAlgorithm.php | 36 ---------------- .../KeyAlgorithm/KeyAlgorithmInterface.php | 24 ----------- src/Utils/SecureKey.php | 41 +++++++------------ 4 files changed, 17 insertions(+), 87 deletions(-) delete mode 100644 src/Utils/KeyAlgorithm/DefaultAlgorithm.php delete mode 100644 src/Utils/KeyAlgorithm/KeyAlgorithmInterface.php diff --git a/composer.json b/composer.json index ba45b8a6..89cabf93 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,8 @@ "league/event": "~2.1", "zendframework/zend-diactoros": "~1.1", "namshi/jose": "^6.0", - "lcobucci/jwt": "^3.1" + "lcobucci/jwt": "^3.1", + "paragonie/random_compat": "^1.1" }, "require-dev": { "phpunit/phpunit": "4.8.*", diff --git a/src/Utils/KeyAlgorithm/DefaultAlgorithm.php b/src/Utils/KeyAlgorithm/DefaultAlgorithm.php deleted file mode 100644 index cdbe20bf..00000000 --- a/src/Utils/KeyAlgorithm/DefaultAlgorithm.php +++ /dev/null @@ -1,36 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Utils\KeyAlgorithm; - -class DefaultAlgorithm implements KeyAlgorithmInterface -{ - /** - * {@inheritdoc} - */ - public function generate($len = 40) - { - $stripped = ''; - do { - $bytes = openssl_random_pseudo_bytes($len, $strong); - - // We want to stop execution if the key fails because, well, that is bad. - if ($bytes === false || $strong === false) { - // @codeCoverageIgnoreStart - throw new \Exception('Error Generating Key'); - // @codeCoverageIgnoreEnd - } - $stripped .= str_replace(['/', '+', '='], '', base64_encode($bytes)); - } while (strlen($stripped) < $len); - - return substr($stripped, 0, $len); - } -} diff --git a/src/Utils/KeyAlgorithm/KeyAlgorithmInterface.php b/src/Utils/KeyAlgorithm/KeyAlgorithmInterface.php deleted file mode 100644 index c0f38ad1..00000000 --- a/src/Utils/KeyAlgorithm/KeyAlgorithmInterface.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Utils\KeyAlgorithm; - -interface KeyAlgorithmInterface -{ - /** - * Generate a new unique code - * - * @param integer $len Length of the generated code - * - * @return string - */ - public function generate($len); -} diff --git a/src/Utils/SecureKey.php b/src/Utils/SecureKey.php index 16dc367e..f5078bbf 100644 --- a/src/Utils/SecureKey.php +++ b/src/Utils/SecureKey.php @@ -11,48 +11,37 @@ namespace League\OAuth2\Server\Utils; -use League\OAuth2\Server\Utils\KeyAlgorithm\DefaultAlgorithm; -use League\OAuth2\Server\Utils\KeyAlgorithm\KeyAlgorithmInterface; +use League\OAuth2\Server\Exception\OAuthServerException; + /** * SecureKey class */ class SecureKey { - /** - * @var KeyAlgorithmInterface - */ - protected static $algorithm; - /** * 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) { - return self::getAlgorithm()->generate($len); - } - - /** - * @param KeyAlgorithmInterface $algorithm - */ - public static function setAlgorithm(KeyAlgorithmInterface $algorithm) - { - self::$algorithm = $algorithm; - } - - /** - * @return KeyAlgorithmInterface - */ - public static function getAlgorithm() - { - if (is_null(self::$algorithm)) { - self::$algorithm = new DefaultAlgorithm(); + 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 self::$algorithm; + return bin2hex($string); } } From 95634fb3901d194348258ff5b055f968b5dd6db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Sun, 17 Jan 2016 17:28:27 +0100 Subject: [PATCH 176/444] compound redirect uri with Psr\Http\Message\UriInterface --- src/Exception/OAuthServerException.php | 8 +++++- src/Utils/RedirectUri.php | 34 -------------------------- 2 files changed, 7 insertions(+), 35 deletions(-) delete mode 100644 src/Utils/RedirectUri.php diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index b0309290..936f41fd 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -6,6 +6,7 @@ use League\OAuth2\Server\Utils\RedirectUri; use Psr\Http\Message\ResponseInterface; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; +use Zend\Diactoros\Uri; class OAuthServerException extends \Exception { @@ -236,7 +237,12 @@ class OAuthServerException extends \Exception } if ($this->redirectUri !== null) { - $headers['Location'] = RedirectUri::make($this->redirectUri, $payload); + $redirectUri = new Uri($this->redirectUri); + parse_str($redirectUri->getQuery(), $redirectPayload); + + $headers['Location'] = (string) $redirectUri->withQuery(http_build_query( + array_merge($redirectPayload, $payload) + )); } foreach ($headers as $header => $content) { diff --git a/src/Utils/RedirectUri.php b/src/Utils/RedirectUri.php deleted file mode 100644 index d00f29cc..00000000 --- a/src/Utils/RedirectUri.php +++ /dev/null @@ -1,34 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Utils; - -/** - * RedirectUri class - */ -class RedirectUri -{ - /** - * Generate a new redirect uri - * - * @param string $uri The base URI - * @param array $params The query string parameters - * @param string $queryDelimiter The query string delimiter (default: "?") - * - * @return string The updated URI - */ - public static function make($uri, $params = [], $queryDelimiter = '?') - { - $uri .= (strstr($uri, $queryDelimiter) === false) ? $queryDelimiter : '&'; - - return $uri . http_build_query($params); - } -} From 322caa77af8cf1558afd177cfcfd5238736a8ae5 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 16:35:52 +0000 Subject: [PATCH 177/444] Fixes for RefreshTokenGrant --- src/Grant/RefreshTokenGrant.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 99b6b402..d8348d25 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -11,12 +11,12 @@ namespace League\OAuth2\Server\Grant; +use League\Event\Event; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\Utils\KeyCrypt; use Psr\Http\Message\ServerRequestInterface; -use Symfony\Component\EventDispatcher\Event; /** * Refresh token grant @@ -54,7 +54,7 @@ class RefreshTokenGrant extends AbstractGrant ) { $client = $this->validateClient($request); $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier()); - $scopes = $this->validateScopes($request, $scopeDelimiter, $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) { From 13ddec328396d7eb390702444fe61bf54ab4b860 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Jan 2016 16:38:25 +0000 Subject: [PATCH 178/444] Fix for PasswordGrant --- src/Grant/PasswordGrant.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 351954b4..50593ef3 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -64,7 +64,7 @@ class PasswordGrant extends AbstractGrant // Validate request $client = $this->validateClient($request); $user = $this->validateUser($request); - $scopes = $this->validateScopes($request, $scopeDelimiter, $client); + $scopes = $this->validateScopes($request, $client); // Issue and persist new tokens $accessToken = $this->issueAccessToken($tokenTTL, $client, $user->getIdentifier(), $scopes); From 8591fc7686c9752b22479cd5ccf6c99d75038fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Sun, 17 Jan 2016 18:40:26 +0100 Subject: [PATCH 179/444] moved to authentication middleware --- examples/public/middleware_authentication.php | 61 +++++++++++++++++++ examples/public/password.php | 2 +- .../AuthenticationServerMiddleware.php | 51 ++++++++++++++++ src/Middleware/ResourceServerMiddleware.php | 1 - src/Server.php | 20 ------ 5 files changed, 113 insertions(+), 22 deletions(-) create mode 100644 examples/public/middleware_authentication.php create mode 100644 src/Middleware/AuthenticationServerMiddleware.php diff --git a/examples/public/middleware_authentication.php b/examples/public/middleware_authentication.php new file mode 100644 index 00000000..f9b525dc --- /dev/null +++ b/examples/public/middleware_authentication.php @@ -0,0 +1,61 @@ + [ + 'displayErrorDetails' => true, + ], + Server::class => function () { + + // Init our repositories + $clientRepository = new ClientRepository(); + $accessTokenRepository = new AccessTokenRepository(); + $scopeRepository = new ScopeRepository(); + $userRepository = new UserRepository(); + $refreshTokenRepository = new RefreshTokenRepository(); + + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + + // Setup the authorization server + $server = new Server( + $clientRepository, + $accessTokenRepository, + $scopeRepository, + $privateKeyPath, + $publicKeyPath + ); + + // Enable the grants + $server->enableGrantType( + new PasswordGrant($userRepository, $refreshTokenRepository), + new \DateInterval('PT1H') + ); + $server->enableGrantType( + new RefreshTokenGrant($refreshTokenRepository), + new \DateInterval('PT1H') + ); + + return $server; + } +]); + +$app->post('/access_token', function () { +})->add(new AuthenticationServerMiddleware($app->getContainer()->get(Server::class))); + +$app->run(); diff --git a/examples/public/password.php b/examples/public/password.php index 1be26880..036d1b4f 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -39,7 +39,7 @@ $app = new App([ $publicKeyPath ); - // Enable the client credentials grant on the server with a token TTL of 1 hour + // Enable the password grant on the server with a token TTL of 1 hour $server->enableGrantType( new PasswordGrant($userRepository, $refreshTokenRepository), new \DateInterval('PT1H') diff --git a/src/Middleware/AuthenticationServerMiddleware.php b/src/Middleware/AuthenticationServerMiddleware.php new file mode 100644 index 00000000..28bd39cb --- /dev/null +++ b/src/Middleware/AuthenticationServerMiddleware.php @@ -0,0 +1,51 @@ +server = $server; + } + + /** + * @param \Psr\Http\Message\ServerRequestInterface $request + * @param \Psr\Http\Message\ResponseInterface $response + * @param callable $next + * + * @return \Psr\Http\Message\ResponseInterface + */ + public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) + { + try { + $response = $server->respondToRequest($request, $response); + } catch (OAuthServerException $exception) { + return $exception->generateHttpResponse($response); + } catch (\Exception $exception) { + return $response->withStatus(500)->write($exception->getMessage()); + } + + if (in_array($response->getStatusCode(), [400, 401, 500])) { + return $response; + } + + // Pass the request and response on to the next responder in the chain + return $next($request, $response); + } +} diff --git a/src/Middleware/ResourceServerMiddleware.php b/src/Middleware/ResourceServerMiddleware.php index fda7861d..874a14c6 100644 --- a/src/Middleware/ResourceServerMiddleware.php +++ b/src/Middleware/ResourceServerMiddleware.php @@ -14,7 +14,6 @@ class ResourceServerMiddleware */ private $server; - /** * ResourceServerMiddleware constructor. * diff --git a/src/Server.php b/src/Server.php index 034173cc..a62e8b32 100644 --- a/src/Server.php +++ b/src/Server.php @@ -172,24 +172,4 @@ class Server implements EmitterAwareInterface return $tokenResponse->generateHttpResponse($response); } - - /** - * PSR7 middleware callable - * - * @param \Psr\Http\Message\ServerRequestInterface $request - * @param \Psr\Http\Message\ResponseInterface $response - * @param callable $next - * - * @return \Psr\Http\Message\ResponseInterface - */ - public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) - { - $response = $this->respondToRequest($request, $response); - - if (in_array($response->getStatusCode(), [400, 401, 500])) { - return $response; - } - - return $next($request, $response); - } } From 94cc7c2bc76eef8de8ba8a5f27377e6e6913ff3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Wed, 20 Jan 2016 00:16:12 +0100 Subject: [PATCH 180/444] fix server reference --- src/Middleware/AuthenticationServerMiddleware.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Middleware/AuthenticationServerMiddleware.php b/src/Middleware/AuthenticationServerMiddleware.php index 28bd39cb..a71d4218 100644 --- a/src/Middleware/AuthenticationServerMiddleware.php +++ b/src/Middleware/AuthenticationServerMiddleware.php @@ -34,7 +34,7 @@ class AuthenticationServerMiddleware public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { try { - $response = $server->respondToRequest($request, $response); + $response = $this->server->respondToRequest($request, $response); } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); } catch (\Exception $exception) { From ef5904ab1a9ed04d2d67be09c9575dc235d0fe83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Wed, 20 Jan 2016 00:32:59 +0100 Subject: [PATCH 181/444] exception based determineAccessTokenInHeader --- src/Middleware/ResourceServerMiddleware.php | 16 +++++----------- src/ResponseTypes/AbstractResponseType.php | 16 +++++++++++++++- src/ResponseTypes/BearerTokenResponse.php | 12 +++++++----- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/Middleware/ResourceServerMiddleware.php b/src/Middleware/ResourceServerMiddleware.php index 874a14c6..ebcf2794 100644 --- a/src/Middleware/ResourceServerMiddleware.php +++ b/src/Middleware/ResourceServerMiddleware.php @@ -33,18 +33,12 @@ class ResourceServerMiddleware */ public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { - if ($request->hasHeader('authorization') === false) { - $exception = OAuthServerException::accessDenied('Missing authorization header'); - - return $exception->generateHttpResponse($response); - } - - $request = $this->server->getResponseType()->determineAccessTokenInHeader($request); - - if ($request->getAttribute('oauth_access_token') === null) { - $exception = OAuthServerException::accessDenied($request->getAttribute('oauth_access_token_error')); - + try { + $request = $this->server->getResponseType()->determineAccessTokenInHeader($request); + } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); + } catch (\Exception $exception) { + return $response->withStatus(500)->write($exception->getMessage()); } // Pass the request and response on to the next responder in the chain diff --git a/src/ResponseTypes/AbstractResponseType.php b/src/ResponseTypes/AbstractResponseType.php index 2388582f..9605a463 100644 --- a/src/ResponseTypes/AbstractResponseType.php +++ b/src/ResponseTypes/AbstractResponseType.php @@ -13,7 +13,9 @@ namespace League\OAuth2\Server\ResponseTypes; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; +use Psr\Http\Message\ServerRequestInterface; abstract class AbstractResponseType implements ResponseTypeInterface { @@ -66,10 +68,22 @@ abstract class AbstractResponseType implements ResponseTypeInterface } /** - * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshToken + * {@inheritdoc} */ public function setRefreshToken(RefreshTokenEntityInterface $refreshToken) { $this->refreshToken = $refreshToken; } + + /** + * {@inheritdoc} + */ + public function determineAccessTokenInHeader(ServerRequestInterface $request) + { + if ($request->hasHeader('authorization') === false) { + throw OAuthServerException::accessDenied('Missing "Authorization" header'); + } + + return $request; + } } diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index 278b166d..c67bc990 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -16,10 +16,10 @@ 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; use League\OAuth2\Server\Utils\KeyCrypt; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Zend\Diactoros\Response; class BearerTokenResponse extends AbstractResponseType { @@ -78,6 +78,8 @@ class BearerTokenResponse extends AbstractResponseType */ public function determineAccessTokenInHeader(ServerRequestInterface $request) { + $request = parent::determineAccessTokenInHeader($request); + $header = $request->getHeader('authorization'); $jwt = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header[0])); @@ -85,12 +87,12 @@ class BearerTokenResponse extends AbstractResponseType // Attempt to parse and validate the JWT $token = (new Parser())->parse($jwt); if ($token->verify(new Sha256(), $this->pathToPublicKey) === false) { - return $request->withAttribute('oauth_access_token_error', 'Access token could not be verified'); + throw OAuthServerException::accessDenied('Access token could not be verified'); } // Check if token has been revoked if ($this->accessTokenRepository->isAccessTokenRevoked($token->getClaim('jti'))) { - return $request->withAttribute('oauth_access_token_error', 'Access token has been revoked'); + throw OAuthServerException::accessDenied('Access token has been revoked'); } // Return the request with additional attributes @@ -98,9 +100,9 @@ class BearerTokenResponse extends AbstractResponseType ->withAttribute('oauth_client_id', $token->getClaim('aud')) ->withAttribute('oauth_user_id', $token->getClaim('sub')) ->withAttribute('oauth_scopes', $token->getClaim('scopes')); - } catch (\InvalidArgumentException $e) { + } catch (\InvalidArgumentException $exception) { // JWT couldn't be parsed so return the request as is - return $request->withAttribute('oauth_access_token_error', $e->getMessage()); + throw OAuthServerException::accessDenied($exception->getMessage()); } } } From 3e5889e93bcaaed4de1a0e205d0b00aeddef150f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Wed, 20 Jan 2016 10:36:16 +0100 Subject: [PATCH 182/444] minor improvements and documentation fixes --- .../Interfaces/AccessTokenEntityInterface.php | 2 +- src/Entities/ScopeEntity.php | 2 +- src/Entities/Traits/ClientEntityTrait.php | 2 +- src/Entities/Traits/RefreshTokenTrait.php | 2 +- src/Entities/Traits/TokenEntityTrait.php | 2 +- src/Exception/OAuthServerException.php | 6 ++++-- src/Grant/AbstractGrant.php | 19 ++++--------------- src/Grant/GrantTypeInterface.php | 11 ++--------- src/Grant/PasswordGrant.php | 2 +- src/Grant/RefreshTokenGrant.php | 9 ++++----- .../AuthCodeRepositoryInterface.php | 2 -- .../ClientRepositoryInterface.php | 4 ++-- src/Repositories/MacTokenInterface.php | 9 +++++---- .../RefreshTokenRepositoryInterface.php | 4 ++-- src/Repositories/ScopeRepositoryInterface.php | 6 +++--- src/ResponseTypes/BearerTokenResponse.php | 8 +++++--- src/Server.php | 1 - 17 files changed, 37 insertions(+), 54 deletions(-) diff --git a/src/Entities/Interfaces/AccessTokenEntityInterface.php b/src/Entities/Interfaces/AccessTokenEntityInterface.php index 242bc8da..2f62f045 100644 --- a/src/Entities/Interfaces/AccessTokenEntityInterface.php +++ b/src/Entities/Interfaces/AccessTokenEntityInterface.php @@ -4,4 +4,4 @@ namespace League\OAuth2\Server\Entities\Interfaces; interface AccessTokenEntityInterface extends TokenInterface { -} \ No newline at end of file +} diff --git a/src/Entities/ScopeEntity.php b/src/Entities/ScopeEntity.php index 09fd0227..5c21e55e 100644 --- a/src/Entities/ScopeEntity.php +++ b/src/Entities/ScopeEntity.php @@ -15,7 +15,7 @@ class ScopeEntity implements ScopeEntityInterface /** * @inheritdoc */ - function jsonSerialize() + public function jsonSerialize() { return $this->getIdentifier(); } diff --git a/src/Entities/Traits/ClientEntityTrait.php b/src/Entities/Traits/ClientEntityTrait.php index fee28e0e..80e61b93 100644 --- a/src/Entities/Traits/ClientEntityTrait.php +++ b/src/Entities/Traits/ClientEntityTrait.php @@ -25,4 +25,4 @@ trait ClientEntityTrait { $this->name = $name; } -} \ No newline at end of file +} diff --git a/src/Entities/Traits/RefreshTokenTrait.php b/src/Entities/Traits/RefreshTokenTrait.php index 71e39225..0e0a3500 100644 --- a/src/Entities/Traits/RefreshTokenTrait.php +++ b/src/Entities/Traits/RefreshTokenTrait.php @@ -50,4 +50,4 @@ trait RefreshTokenTrait { $this->expiryDateTime = $dateTime; } -} \ No newline at end of file +} diff --git a/src/Entities/Traits/TokenEntityTrait.php b/src/Entities/Traits/TokenEntityTrait.php index d16e6f8d..324de912 100644 --- a/src/Entities/Traits/TokenEntityTrait.php +++ b/src/Entities/Traits/TokenEntityTrait.php @@ -123,4 +123,4 @@ trait TokenEntityTrait { return (new DateTime()) > $this->getExpiryDateTime(); } -} \ No newline at end of file +} diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index b0309290..88b0ab04 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -60,7 +60,8 @@ class OAuthServerException extends \Exception $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.' + ? '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' @@ -106,7 +107,8 @@ class OAuthServerException extends \Exception $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.' + ? '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) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 490ecf4c..0fe2c987 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -11,7 +11,7 @@ namespace League\OAuth2\Server\Grant; -use League\Event\EmitterInterface; +use League\Event\EmitterAwareTrait; use League\Event\Event; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; @@ -29,6 +29,8 @@ use Psr\Http\Message\ServerRequestInterface; */ abstract class AbstractGrant implements GrantTypeInterface { + use EmitterAwareTrait; + const SCOPE_DELIMITER_STRING = ' '; /** @@ -60,11 +62,6 @@ abstract class AbstractGrant implements GrantTypeInterface */ protected $accessTokenRepository; - /** - * @var \League\Event\Emitter - */ - protected $emitter; - /** * @var ScopeRepositoryInterface */ @@ -120,14 +117,6 @@ abstract class AbstractGrant implements GrantTypeInterface $this->pathToPublicKey = $pathToPublicKey; } - /** - * @inheritdoc - */ - public function setEmitter(EmitterInterface $emitter) - { - $this->emitter = $emitter; - } - /** * {@inheritdoc} */ @@ -179,7 +168,7 @@ abstract class AbstractGrant implements GrantTypeInterface ); if (!$client instanceof ClientEntityInterface) { - $this->emitter->emit(new Event('client.authentication.failed', $request)); + $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); throw OAuthServerException::invalidClient(); } diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 5bc9bf08..bb2b07a6 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -12,7 +12,7 @@ namespace League\OAuth2\Server\Grant; use DateInterval; -use League\Event\EmitterInterface; +use League\Event\EmitterAwareInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; @@ -22,7 +22,7 @@ use Psr\Http\Message\ServerRequestInterface; /** * Grant type interface */ -interface GrantTypeInterface +interface GrantTypeInterface extends EmitterAwareInterface { /** * Return the identifier @@ -67,13 +67,6 @@ interface GrantTypeInterface */ public function canRespondToRequest(ServerRequestInterface $request); - /** - * Set the event emitter - * - * @param \League\Event\EmitterInterface $emitter - */ - public function setEmitter(EmitterInterface $emitter); - /** * Set the client repository * diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 50593ef3..57b85570 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -100,7 +100,7 @@ class PasswordGrant extends AbstractGrant $user = $this->userRepository->getUserEntityByUserCredentials($username, $password); if (!$user instanceof UserEntityInterface) { - $this->emitter->emit(new Event('user.authentication.failed', $request)); + $this->getEmitter()->emit(new Event('user.authentication.failed', $request)); throw OAuthServerException::invalidCredentials(); } diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index d8348d25..df935c92 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -38,9 +38,8 @@ class RefreshTokenGrant extends AbstractGrant /** * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository */ - public function __construct( - RefreshTokenRepositoryInterface $refreshTokenRepository - ) { + public function __construct(RefreshTokenRepositoryInterface $refreshTokenRepository) + { $this->refreshTokenRepository = $refreshTokenRepository; } @@ -64,7 +63,7 @@ class RefreshTokenGrant extends AbstractGrant // the request doesn't include any new scopes foreach ($scopes as $scope) { if (in_array($scope->getIdentifier(), $oldRefreshToken['scopes']) === false) { - $this->emitter->emit(new Event('scope.selection.failed', $request)); + $this->getEmitter()->emit(new Event('scope.selection.failed', $request)); throw OAuthServerException::invalidScope($scope->getIdentifier()); } @@ -112,7 +111,7 @@ class RefreshTokenGrant extends AbstractGrant $refreshTokenData = json_decode($refreshToken, true); if ($refreshTokenData['client_id'] !== $clientId) { - $this->emitter->emit(new Event('refresh_token.client.failed', $request)); + $this->getEmitter()->emit(new Event('refresh_token.client.failed', $request)); throw OAuthServerException::invalidRefreshToken( 'Token is not linked to client,' . diff --git a/src/Repositories/AuthCodeRepositoryInterface.php b/src/Repositories/AuthCodeRepositoryInterface.php index 85852ef3..481106d3 100644 --- a/src/Repositories/AuthCodeRepositoryInterface.php +++ b/src/Repositories/AuthCodeRepositoryInterface.php @@ -33,8 +33,6 @@ interface AuthCodeRepositoryInterface extends RepositoryInterface * @param string $code The authorization code string * @param integer $expireTime Token expire time * @param string $redirectUri Client redirect uri - * - * @return void */ public function persistNewAuthCode($code, $expireTime, $redirectUri); diff --git a/src/Repositories/ClientRepositoryInterface.php b/src/Repositories/ClientRepositoryInterface.php index b9b9aa3a..0cd88ad2 100644 --- a/src/Repositories/ClientRepositoryInterface.php +++ b/src/Repositories/ClientRepositoryInterface.php @@ -20,11 +20,11 @@ interface ClientRepositoryInterface extends RepositoryInterface * Get a client * * @param string $clientIdentifier The client's identifier - * @param string|null $clientSecret The client's secret + * @param string $clientSecret The client's secret * @param string|null $redirectUri The client's redirect URI * @param string|null $grantType The grant type used * * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface */ - public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null, $redirectUri = null); + public function getClientEntity($clientIdentifier, $clientSecret, $redirectUri = null, $grantType = null); } diff --git a/src/Repositories/MacTokenInterface.php b/src/Repositories/MacTokenInterface.php index 4b84b147..833a0d7b 100644 --- a/src/Repositories/MacTokenInterface.php +++ b/src/Repositories/MacTokenInterface.php @@ -13,7 +13,6 @@ namespace League\OAuth2\Server\Storage; use League\OAuth2\Server\Repositories\RepositoryInterface; - /** * MacTokenInterface */ @@ -21,15 +20,17 @@ interface MacTokenInterface extends RepositoryInterface { /** * Create a MAC key linked to an access token - * @param string $macKey - * @param string $accessToken - * @return void + * + * @param string $macKey + * @param string $accessToken */ public function persistMacTokenEntity($macKey, $accessToken); /** * Get a MAC key by access token + * * @param string $accessToken + * * @return string */ public function getMacKeyByAccessTokenString($accessToken); diff --git a/src/Repositories/RefreshTokenRepositoryInterface.php b/src/Repositories/RefreshTokenRepositoryInterface.php index 1ac9a0d1..533351d8 100644 --- a/src/Repositories/RefreshTokenRepositoryInterface.php +++ b/src/Repositories/RefreshTokenRepositoryInterface.php @@ -21,9 +21,9 @@ interface RefreshTokenRepositoryInterface extends RepositoryInterface /** * Create a new refresh token_name * - * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshTokenEntityInterface + * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshTokenEntity */ - public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntityInterface); + public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity); /** * Revoke the refresh token diff --git a/src/Repositories/ScopeRepositoryInterface.php b/src/Repositories/ScopeRepositoryInterface.php index 276ce264..0b45efe9 100644 --- a/src/Repositories/ScopeRepositoryInterface.php +++ b/src/Repositories/ScopeRepositoryInterface.php @@ -19,9 +19,9 @@ interface ScopeRepositoryInterface extends RepositoryInterface /** * Return information about a scope * - * @param string $identifier The scope identifier - * @param string $grantType The grant type used in the request - * @param string $clientId The client sending the request + * @param string $identifier The scope identifier + * @param string $grantType The grant type used in the request + * @param string|null $clientId The client sending the request * * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface */ diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index 278b166d..ae171fb1 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -28,12 +28,14 @@ class BearerTokenResponse extends AbstractResponseType */ public function generateHttpResponse(ResponseInterface $response) { + $expireDateTime = $this->accessToken->getExpiryDateTime()->getTimestamp(); + $jwtAccessToken = (new Builder()) ->setAudience($this->accessToken->getClient()->getIdentifier()) ->setId($this->accessToken->getIdentifier(), true) ->setIssuedAt(time()) ->setNotBefore(time()) - ->setExpiration($this->accessToken->getExpiryDateTime()->getTimestamp()) + ->setExpiration($expireDateTime) ->setSubject($this->accessToken->getUserIdentifier()) ->set('scopes', $this->accessToken->getScopes()) ->sign(new Sha256(), new Key($this->pathToPrivateKey)) @@ -41,7 +43,7 @@ class BearerTokenResponse extends AbstractResponseType $responseParams = [ 'token_type' => 'Bearer', - 'expires_in' => $this->accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp(), + 'expires_in' => $expireDateTime - (new \DateTime)->getTimestamp(), 'access_token' => (string) $jwtAccessToken, ]; @@ -54,7 +56,7 @@ class BearerTokenResponse extends AbstractResponseType 'access_token_id' => $this->accessToken->getIdentifier(), 'scopes' => $this->accessToken->getScopes(), 'user_id' => $this->accessToken->getUserIdentifier(), - 'expire_time' => $this->refreshToken->getExpiryDateTime()->getTimestamp(), + 'expire_time' => $expireDateTime, ] ), $this->pathToPrivateKey diff --git a/src/Server.php b/src/Server.php index a62e8b32..afc2a73a 100644 --- a/src/Server.php +++ b/src/Server.php @@ -2,7 +2,6 @@ namespace League\OAuth2\Server; -use DateInterval; use League\Event\EmitterAwareInterface; use League\Event\EmitterAwareTrait; use League\OAuth2\Server\Exception\OAuthServerException; From b7b1f56d0c86ebeeb1d2b6043baf7bfc9a6a52e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Wed, 20 Jan 2016 10:58:45 +0100 Subject: [PATCH 183/444] stream write fix --- src/Exception/OAuthServerException.php | 4 ++-- src/Middleware/AuthenticationServerMiddleware.php | 4 +++- src/Middleware/ResourceServerMiddleware.php | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index b0309290..c68c541d 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -243,9 +243,9 @@ class OAuthServerException extends \Exception $response = $response->withHeader($header, $content); } - $response = $response->withStatus($this->getHttpStatusCode()); $response->getBody()->write(json_encode($payload)); - return $response; + + return $response->withStatus($this->getHttpStatusCode()); } /** diff --git a/src/Middleware/AuthenticationServerMiddleware.php b/src/Middleware/AuthenticationServerMiddleware.php index a71d4218..14ac1c32 100644 --- a/src/Middleware/AuthenticationServerMiddleware.php +++ b/src/Middleware/AuthenticationServerMiddleware.php @@ -38,7 +38,9 @@ class AuthenticationServerMiddleware } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); } catch (\Exception $exception) { - return $response->withStatus(500)->write($exception->getMessage()); + $response->getBody()->write($exception->getMessage()); + + return $response->withStatus(500); } if (in_array($response->getStatusCode(), [400, 401, 500])) { diff --git a/src/Middleware/ResourceServerMiddleware.php b/src/Middleware/ResourceServerMiddleware.php index ebcf2794..1794cdce 100644 --- a/src/Middleware/ResourceServerMiddleware.php +++ b/src/Middleware/ResourceServerMiddleware.php @@ -38,7 +38,9 @@ class ResourceServerMiddleware } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); } catch (\Exception $exception) { - return $response->withStatus(500)->write($exception->getMessage()); + $response->getBody()->write($exception->getMessage()); + + return $response->withStatus(500); } // Pass the request and response on to the next responder in the chain From 44155a8efc1e95ce44a9ea54ae379554b4382651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Wed, 20 Jan 2016 12:21:44 +0100 Subject: [PATCH 184/444] allow refresh token ttl assign --- src/Grant/AbstractGrant.php | 5 ++- src/Grant/ClientCredentialsGrant.php | 5 ++- src/Grant/GrantTypeInterface.php | 7 +-- src/Grant/PasswordGrant.php | 7 +-- src/Grant/RefreshTokenGrant.php | 8 ++-- src/Server.php | 65 +++++++++++++--------------- 6 files changed, 50 insertions(+), 47 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 490ecf4c..22ffd77f 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -283,15 +283,16 @@ abstract class AbstractGrant implements GrantTypeInterface } /** + * @param \DateInterval $tokenTTL * @param \League\OAuth2\Server\Entities\AccessTokenEntity $accessToken * * @return \League\OAuth2\Server\Entities\RefreshTokenEntity */ - protected function issueRefreshToken(AccessTokenEntity $accessToken) + protected function issueRefreshToken(\DateInterval $tokenTTL, AccessTokenEntity $accessToken) { $refreshToken = new RefreshTokenEntity(); $refreshToken->setIdentifier(SecureKey::generate()); - $refreshToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('P1M'))); + $refreshToken->setExpiryDateTime((new \DateTime())->add($tokenTTL)); $refreshToken->setAccessToken($accessToken); return $refreshToken; diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 03c6c721..6fea3926 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -32,14 +32,15 @@ class ClientCredentialsGrant extends AbstractGrant public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - \DateInterval $tokenTTL + \DateInterval $accessTokenTTL, + \DateInterval $refreshTokenTTL ) { // Validate request $client = $this->validateClient($request); $scopes = $this->validateScopes($request, $client); // Issue and persist access token - $accessToken = $this->issueAccessToken($tokenTTL, $client, $client->getIdentifier(), $scopes); + $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $client->getIdentifier(), $scopes); $this->accessTokenRepository->persistNewAccessToken($accessToken); // Inject access token into response type diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 5bc9bf08..acf32ad3 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -11,7 +11,6 @@ namespace League\OAuth2\Server\Grant; -use DateInterval; use League\Event\EmitterInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -43,14 +42,16 @@ interface GrantTypeInterface * * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType - * @param \DateInterval $tokenTTL + * @param \DateInterval $accessTokenTTL + * @param \DateInterval $refreshTokenTTL * * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface */ public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - DateInterval $tokenTTL + \DateInterval $accessTokenTTL, + \DateInterval $refreshTokenTTL ); /** diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 50593ef3..b6a3771e 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -59,7 +59,8 @@ class PasswordGrant extends AbstractGrant public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - \DateInterval $tokenTTL + \DateInterval $accessTokenTTL, + \DateInterval $refreshTokenTTL ) { // Validate request $client = $this->validateClient($request); @@ -67,8 +68,8 @@ class PasswordGrant extends AbstractGrant $scopes = $this->validateScopes($request, $client); // Issue and persist new tokens - $accessToken = $this->issueAccessToken($tokenTTL, $client, $user->getIdentifier(), $scopes); - $refreshToken = $this->issueRefreshToken($accessToken); + $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $scopes); + $refreshToken = $this->issueRefreshToken($refreshTokenTTL, $accessToken); $this->accessTokenRepository->persistNewAccessToken($accessToken); $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index d8348d25..8af43365 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -50,8 +50,10 @@ class RefreshTokenGrant extends AbstractGrant public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - \DateInterval $tokenTTL + \DateInterval $accessTokenTTL, + \DateInterval $refreshTokenTTL ) { + // Validate request $client = $this->validateClient($request); $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier()); $scopes = $this->validateScopes($request, $client); @@ -75,8 +77,8 @@ class RefreshTokenGrant extends AbstractGrant $this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']); $this->refreshTokenRepository->revokeRefreshToken($oldRefreshToken['refresh_token_id']); - $accessToken = $this->issueAccessToken($tokenTTL, $client, $oldRefreshToken['user_id'], $scopes); - $refreshToken = $this->issueRefreshToken($accessToken); + $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes); + $refreshToken = $this->issueRefreshToken($refreshTokenTTL, $accessToken); $this->accessTokenRepository->persistNewAccessToken($accessToken); $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); diff --git a/src/Server.php b/src/Server.php index a62e8b32..70822010 100644 --- a/src/Server.php +++ b/src/Server.php @@ -26,15 +26,10 @@ class Server implements EmitterAwareInterface */ protected $enabledGrantTypes = []; - /** - * @var ResponseTypeInterface[] - */ - protected $grantResponseTypes = []; - /** * @var DateInterval[] */ - protected $grantTypeAccessTokenTTL = []; + protected $grantTypeTokensTTL = []; /** * @var string @@ -92,48 +87,31 @@ class Server implements EmitterAwareInterface $this->responseType = $responseType; } - /** - * Get the token type that grants will return in the HTTP response - * - * @return ResponseTypeInterface - */ - public function getResponseType() - { - if (!$this->responseType instanceof ResponseTypeInterface) { - $this->responseType = new BearerTokenResponse( - $this->privateKeyPath, - $this->publicKeyPath, - $this->accessTokenRepository - ); - } - - return $this->responseType; - } - /** * Enable a grant type on the server * * @param \League\OAuth2\Server\Grant\GrantTypeInterface $grantType - * @param DateInterval $accessTokenTTL + * @param DateInterval|null $accessTokenTTL + * @param DateInterval|null $refreshTokenTTL */ public function enableGrantType( GrantTypeInterface $grantType, - \DateInterval $accessTokenTTL + \DateInterval $accessTokenTTL, + \DateInterval $refreshTokenTTL = null ) { $grantType->setAccessTokenRepository($this->accessTokenRepository); $grantType->setClientRepository($this->clientRepository); $grantType->setScopeRepository($this->scopeRepository); $grantType->setPathToPrivateKey($this->privateKeyPath); $grantType->setPathToPublicKey($this->publicKeyPath); - $grantType->setEmitter($this->getEmitter()); + $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; - // Set grant response type - $this->grantResponseTypes[$grantType->getIdentifier()] = $this->getResponseType(); - - // Set grant access token TTL - $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL; + $this->grantTypeTokensTTL[$grantType->getIdentifier()] = [ + 'access' => $accessTokenTTL, + 'refresh' => $refreshTokenTTL !== null ? $refreshTokenTTL : new \DateInterval('P1M'), + ]; } /** @@ -160,8 +138,9 @@ class Server implements EmitterAwareInterface if ($grantType->canRespondToRequest($request)) { $tokenResponse = $grantType->respondToRequest( $request, - $this->grantResponseTypes[$grantType->getIdentifier()], - $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] + $this->getResponseType(), + $this->grantTypeTokensTTL[$grantType->getIdentifier()]['access'], + $this->grantTypeTokensTTL[$grantType->getIdentifier()]['refresh'] ); } } @@ -172,4 +151,22 @@ class Server implements EmitterAwareInterface return $tokenResponse->generateHttpResponse($response); } + + /** + * Get the token type that grants will return in the HTTP response + * + * @return ResponseTypeInterface + */ + public function getResponseType() + { + if (!$this->responseType instanceof ResponseTypeInterface) { + $this->responseType = new BearerTokenResponse( + $this->privateKeyPath, + $this->publicKeyPath, + $this->accessTokenRepository + ); + } + + return $this->responseType; + } } From 8fb64041df61259dbb13cfd3a6279905ffb6e005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Wed, 20 Jan 2016 12:50:23 +0100 Subject: [PATCH 185/444] client secret can be null --- src/Grant/AbstractGrant.php | 4 ++-- src/Repositories/ClientRepositoryInterface.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 0fe2c987..f4fe47ba 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -161,10 +161,10 @@ abstract class AbstractGrant implements GrantTypeInterface } $client = $this->clientRepository->getClientEntity( + $this->getIdentifier(), $clientId, $clientSecret, - null, - $this->getIdentifier() + null ); if (!$client instanceof ClientEntityInterface) { diff --git a/src/Repositories/ClientRepositoryInterface.php b/src/Repositories/ClientRepositoryInterface.php index 0cd88ad2..3bec9452 100644 --- a/src/Repositories/ClientRepositoryInterface.php +++ b/src/Repositories/ClientRepositoryInterface.php @@ -19,12 +19,12 @@ interface ClientRepositoryInterface extends RepositoryInterface /** * Get a client * + * @param string $grantType The grant type used * @param string $clientIdentifier The client's identifier - * @param string $clientSecret The client's secret + * @param string|null $clientSecret The client's secret * @param string|null $redirectUri The client's redirect URI - * @param string|null $grantType The grant type used * * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface */ - public function getClientEntity($clientIdentifier, $clientSecret, $redirectUri = null, $grantType = null); + public function getClientEntity($grantType, $clientIdentifier, $clientSecret = null, $redirectUri = null); } From b85f81c429e7e9a8615eeace343477a6d288d7f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Thu, 21 Jan 2016 18:11:53 +0100 Subject: [PATCH 186/444] configurable refresh token TTL per grant --- src/Grant/AbstractGrant.php | 18 +++++++++++++++--- src/Grant/ClientCredentialsGrant.php | 3 +-- src/Grant/GrantTypeInterface.php | 11 ++++++++--- src/Grant/PasswordGrant.php | 7 ++++--- src/Grant/RefreshTokenGrant.php | 9 +++++---- src/Server.php | 21 +++++++-------------- 6 files changed, 40 insertions(+), 29 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 22ffd77f..c6ffc760 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -80,6 +80,11 @@ abstract class AbstractGrant implements GrantTypeInterface */ protected $pathToPublicKey; + /** + * @var \DateInterval + */ + protected $refreshTokenTTL; + /** * @param ClientRepositoryInterface $clientRepository */ @@ -128,6 +133,14 @@ abstract class AbstractGrant implements GrantTypeInterface $this->emitter = $emitter; } + /** + * @inheritdoc + */ + public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL) + { + $this->refreshTokenTTL = $refreshTokenTTL; + } + /** * {@inheritdoc} */ @@ -283,16 +296,15 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @param \DateInterval $tokenTTL * @param \League\OAuth2\Server\Entities\AccessTokenEntity $accessToken * * @return \League\OAuth2\Server\Entities\RefreshTokenEntity */ - protected function issueRefreshToken(\DateInterval $tokenTTL, AccessTokenEntity $accessToken) + protected function issueRefreshToken(AccessTokenEntity $accessToken) { $refreshToken = new RefreshTokenEntity(); $refreshToken->setIdentifier(SecureKey::generate()); - $refreshToken->setExpiryDateTime((new \DateTime())->add($tokenTTL)); + $refreshToken->setExpiryDateTime((new \DateTime())->add($this->refreshTokenTTL)); $refreshToken->setAccessToken($accessToken); return $refreshToken; diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 6fea3926..918586f9 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -32,8 +32,7 @@ class ClientCredentialsGrant extends AbstractGrant public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - \DateInterval $accessTokenTTL, - \DateInterval $refreshTokenTTL + \DateInterval $accessTokenTTL ) { // Validate request $client = $this->validateClient($request); diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index acf32ad3..a6a5c63a 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -23,6 +23,13 @@ use Psr\Http\Message\ServerRequestInterface; */ interface GrantTypeInterface { + /** + * Set refresh token TTL + * + * @param \DateInterval $refreshTokenTTL + */ + public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL); + /** * Return the identifier * @@ -43,15 +50,13 @@ interface GrantTypeInterface * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType * @param \DateInterval $accessTokenTTL - * @param \DateInterval $refreshTokenTTL * * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface */ public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - \DateInterval $accessTokenTTL, - \DateInterval $refreshTokenTTL + \DateInterval $accessTokenTTL ); /** diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index b6a3771e..9f4f41e8 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -51,6 +51,8 @@ class PasswordGrant extends AbstractGrant ) { $this->userRepository = $userRepository; $this->refreshTokenRepository = $refreshTokenRepository; + + $this->refreshTokenTTL = new \DateInterval('P1M'); } /** @@ -59,8 +61,7 @@ class PasswordGrant extends AbstractGrant public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - \DateInterval $accessTokenTTL, - \DateInterval $refreshTokenTTL + \DateInterval $accessTokenTTL ) { // Validate request $client = $this->validateClient($request); @@ -69,7 +70,7 @@ class PasswordGrant extends AbstractGrant // Issue and persist new tokens $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $scopes); - $refreshToken = $this->issueRefreshToken($refreshTokenTTL, $accessToken); + $refreshToken = $this->issueRefreshToken($accessToken); $this->accessTokenRepository->persistNewAccessToken($accessToken); $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 8af43365..cf3286c8 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -42,6 +42,8 @@ class RefreshTokenGrant extends AbstractGrant RefreshTokenRepositoryInterface $refreshTokenRepository ) { $this->refreshTokenRepository = $refreshTokenRepository; + + $this->refreshTokenTTL = new \DateInterval('P1M'); } /** @@ -50,8 +52,7 @@ class RefreshTokenGrant extends AbstractGrant public function respondToRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, - \DateInterval $accessTokenTTL, - \DateInterval $refreshTokenTTL + \DateInterval $accessTokenTTL ) { // Validate request $client = $this->validateClient($request); @@ -77,9 +78,9 @@ class RefreshTokenGrant extends AbstractGrant $this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']); $this->refreshTokenRepository->revokeRefreshToken($oldRefreshToken['refresh_token_id']); + // Issue and persist new tokens $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes); - $refreshToken = $this->issueRefreshToken($refreshTokenTTL, $accessToken); - + $refreshToken = $this->issueRefreshToken($accessToken); $this->accessTokenRepository->persistNewAccessToken($accessToken); $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); diff --git a/src/Server.php b/src/Server.php index 70822010..adb6936d 100644 --- a/src/Server.php +++ b/src/Server.php @@ -7,6 +7,7 @@ use League\Event\EmitterAwareInterface; use League\Event\EmitterAwareTrait; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\GrantTypeInterface; +use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; @@ -29,7 +30,7 @@ class Server implements EmitterAwareInterface /** * @var DateInterval[] */ - protected $grantTypeTokensTTL = []; + protected $grantTypeAccessTokenTTL = []; /** * @var string @@ -91,14 +92,10 @@ class Server implements EmitterAwareInterface * Enable a grant type on the server * * @param \League\OAuth2\Server\Grant\GrantTypeInterface $grantType - * @param DateInterval|null $accessTokenTTL - * @param DateInterval|null $refreshTokenTTL + * @param DateInterval $accessTokenTTL */ - public function enableGrantType( - GrantTypeInterface $grantType, - \DateInterval $accessTokenTTL, - \DateInterval $refreshTokenTTL = null - ) { + public function enableGrantType(GrantTypeInterface $grantType, \DateInterval $accessTokenTTL) + { $grantType->setAccessTokenRepository($this->accessTokenRepository); $grantType->setClientRepository($this->clientRepository); $grantType->setScopeRepository($this->scopeRepository); @@ -108,10 +105,7 @@ class Server implements EmitterAwareInterface $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; - $this->grantTypeTokensTTL[$grantType->getIdentifier()] = [ - 'access' => $accessTokenTTL, - 'refresh' => $refreshTokenTTL !== null ? $refreshTokenTTL : new \DateInterval('P1M'), - ]; + $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL; } /** @@ -139,8 +133,7 @@ class Server implements EmitterAwareInterface $tokenResponse = $grantType->respondToRequest( $request, $this->getResponseType(), - $this->grantTypeTokensTTL[$grantType->getIdentifier()]['access'], - $this->grantTypeTokensTTL[$grantType->getIdentifier()]['refresh'] + $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] ); } } From 92a101f263537196b1b3a13c370ed8ab5cb5e71a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 11 Feb 2016 17:30:01 +0000 Subject: [PATCH 187/444] First commit of AuthCode rewrite --- examples/public/auth_code.php | 60 +++ .../AuthorizationCodeRequestEntity.php | 79 ++++ src/Grant/AuthCodeGrant.php | 361 +++++------------- 3 files changed, 236 insertions(+), 264 deletions(-) create mode 100644 examples/public/auth_code.php create mode 100644 src/Entities/AuthorizationCodeRequestEntity.php diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php new file mode 100644 index 00000000..d0e76989 --- /dev/null +++ b/examples/public/auth_code.php @@ -0,0 +1,60 @@ +enableGrantType($passwordGrant); + +// App +$app = new App([Server::class => $server]); + +$app->any('/authorise', function (Request $request, Response $response) { + if (strtoupper($request->getMethod()) === 'GET') { + $response = $response->withHeader('Set-Cookie', $authCodeGrant->storeOriginalRequestParams) + } +}); + +$app->post('/access_token', function (Request $request, Response $response) { + /** @var Server $server */ + $server = $this->get(Server::class); + try { + return $server->respondToRequest($request); + } catch (OAuthServerException $e) { + return $e->generateHttpResponse(); + } catch (\Exception $e) { + return $response->withStatus(500)->write($e->getMessage()); + } +}); + +$app->run(); diff --git a/src/Entities/AuthorizationCodeRequestEntity.php b/src/Entities/AuthorizationCodeRequestEntity.php new file mode 100644 index 00000000..bd401b24 --- /dev/null +++ b/src/Entities/AuthorizationCodeRequestEntity.php @@ -0,0 +1,79 @@ +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/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index a7ae36bb..c51954e3 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -1,303 +1,136 @@ - * @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\Emitter; -use League\Event\Event; -use League\OAuth2\Server\Entities\AccessTokenEntity; -use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Exception\InvalidClientException; -use League\OAuth2\Server\Exception\InvalidRequestException; -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\TokenTypes\TokenTypeInterface; -use League\OAuth2\Server\Utils\SecureKey; -use Symfony\Component\HttpFoundation\Request; use DateInterval; +use DateTime; +use League\OAuth2\Server\Exception\OAuthServerException; +use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; +use Psr\Http\Message\ServerRequestInterface; -/** - * Auth code grant class - */ class AuthCodeGrant extends AbstractGrant { /** - * @var \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface + * @inheritdoc */ - protected $authCodeRepository; - - /** - * @param \League\Event\Emitter $emitter - * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository - * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository - * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository - * @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository - * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository - */ - public function __construct( - Emitter $emitter, - ClientRepositoryInterface $clientRepository, - ScopeRepositoryInterface $scopeRepository, - AccessTokenRepositoryInterface $accessTokenRepository, - AuthCodeRepositoryInterface $authCodeRepository, - RefreshTokenRepositoryInterface $refreshTokenRepository = null + public function respondToRequest( + ServerRequestInterface $request, + ResponseTypeInterface $responseType, + DateInterval $tokenTTL, + $scopeDelimiter = ' ' ) { - $this->authCodeRepository = $authCodeRepository; - $this->refreshTokenRepository = $refreshTokenRepository; - parent::__construct($emitter, $clientRepository, $scopeRepository, $accessTokenRepository); + if ( + isset($request->getQueryParams()['response_type']) + && $request->getQueryParams()['response_type'] === 'code' + && isset($request->getQueryParams()['client_id']) + ) { + return $this->respondToAuthorizationRequest($request, $scopeDelimiter, $tokenTTL); + } elseif ( + isset($request->getParsedBody()['grant_type']) + && $request->getParsedBody()['grant_type'] === 'authorization_code' + ) { + return $this->respondToAccessTokenRequest($request, $responseType, $tokenTTL); + } else { + throw OAuthServerException::serverError('respondToRequest() should not have been called'); + } } /** - * Grant identifier + * Respond to an authorization request * - * @var string + * @param \Psr\Http\Message\ServerRequestInterface $request + * @param string $scopeDelimiter + * @param DateTime $tokenTTL */ - protected $identifier = 'authorization_code'; - - /** - * Response type - * - * @var string - */ - protected $responseType = 'code'; - - /** - * AuthServer instance - * - * @var \League\OAuth2\Server\AuthorizationServer - */ - protected $server = null; - - /** - * Access token expires in override - * - * @var int - */ - protected $accessTokenTTL = null; - - /** - * The TTL of the auth token - * - * @var integer - */ - protected $authTokenTTL = 600; - - /** - * Override the default access token expire time - * - * @param int $authTokenTTL - * - * @return void - */ - public function setAuthTokenTTL($authTokenTTL) - { - $this->authTokenTTL = $authTokenTTL; - } - - /** - * Check authorize parameters - * - * @return array Authorize request parameters - * - * @throws - */ - /*public function checkAuthorizeParams() - { + protected function respondToAuthorizationRequest( + ServerRequestInterface $request, + $scopeDelimiter = ' ', + DateTime $tokenTTL + ) { // Get required params - $clientId = $request->query->get('client_id', null); + /*$clientId = array_key_exists('client_id', $request->getQueryParams()) + ? $request->getQueryParams()['client_id'] // $_GET['client_id'] + : null; + if (is_null($clientId)) { - throw new InvalidRequestException('client_id'); + throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); } - $redirectUri = $request->query->get('redirect_uri', null); + $redirectUri = array_key_exists('redirect_uri', $request->getQueryParams()) + ? $request->getQueryParams()['redirect_uri'] // $_GET['redirect_uri'] + : null; + if (is_null($redirectUri)) { - throw new InvalidRequestException('redirect_uri'); + throw OAuthServerException::invalidRequest('redirect_uri', null, '`%s` parameter is missing'); } // Validate client ID and redirect URI - $client = $this->server->getClientStorage()->get( + $client = $this->clientRepository->getClientEntity( $clientId, + $this->getIdentifier(), null, - $redirectUri, - $this->getIdentifier() - ); - - if (($client instanceof ClientEntity) === false) { - $this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($request)); - throw new Exception\InvalidClientException(); - } - - $state = $request->query->get('state', null); - if ($this->server->stateParamRequired() === true && is_null($state)) { - throw new InvalidRequestException('state', $redirectUri); - } - - $responseType = $request->query->get('response_type', null); - if (is_null($responseType)) { - throw new InvalidRequestException('response_type', $redirectUri); - } - - // Ensure response type is one that is recognised - if (!in_array($responseType, $this->server->getResponseTypes())) { - throw new Exception\UnsupportedResponseTypeException($responseType, $redirectUri); - } - - // Validate any scopes that are in the request - $scopeParam = $request->query->get('scope', ''); - $scopes = $this->validateScopes($scopeParam, $client, $redirectUri); - - return [ - 'client' => $client, - 'redirect_uri' => $redirectUri, - 'state' => $state, - 'response_type' => $responseType, - 'scopes' => $scopes - ]; - }*/ - - /** - * Parse a new authorize request - * - * @param string $type The session owner's type - * @param string $typeId The session owner's ID - * @param array $authParams The authorize request $_GET parameters - * - * @return string An authorisation code - */ - /*public function newAuthorizeRequest($type, $typeId, $authParams = []) - { - // Create a new session - $session = new SessionEntity($this->server); - $session->setOwner($type, $typeId); - $session->associateClient($authParams['client']); - $session->save(); - - // Create a new auth code - $authCode = new AuthCodeEntity($this->server); - $authCode->setId(SecureKey::generate()); - $authCode->setRedirectUri($authParams['redirect_uri']); - $authCode->setExpireTime(time() + $this->authTokenTTL); - - foreach ($authParams['scopes'] as $scope) { - $authCode->associateScope($scope); - } - - $authCode->setSession($session); - $authCode->save(); - - return $authCode->generateRedirectUri($authParams['state']); - }*/ - - /** - * Return an access token - * - * @param \Symfony\Component\HttpFoundation\Request $request - * @param \League\OAuth2\Server\TokenTypes\TokenTypeInterface $tokenType - * @param \DateInterval $accessTokenTTL - * @param string $scopeDelimiter - * - * @return \League\OAuth2\Server\TokenTypes\TokenTypeInterface - * @throws \League\OAuth2\Server\Exception\InvalidClientException - * @throws \League\OAuth2\Server\Exception\InvalidGrantException - * @throws \League\OAuth2\Server\Exception\InvalidRequestException - */ - public function getAccessTokenAsType( - Request $request, - TokenTypeInterface $tokenType, - DateInterval $accessTokenTTL, - $scopeDelimiter = ' ' - ) { - // Get the required params - $clientId = $request->request->get('client_id', $request->getUser()); - if (is_null($clientId)) { - throw new InvalidRequestException('client_id', ''); - } - - $clientSecret = $request->request->get('client_secret', - $request->getPassword()); - if (is_null($clientSecret)) { - throw new InvalidRequestException('client_secret'); - } - - $redirectUri = $request->request->get('redirect_uri', null); - if (is_null($redirectUri)) { - throw new InvalidRequestException('redirect_uri'); - } - - // Validate client ID and client secret - $client = $this->clientRepository->get( - $clientId, - $clientSecret, - $redirectUri, - $this->getIdentifier() + $redirectUri ); if (($client instanceof ClientEntityInterface) === false) { - $this->emitter->emit(new Event('client.authentication.failed', $request)); - throw new InvalidClientException(); + throw OAuthServerException::invalidClient(); } - // Validate the auth code - $authCode = $request->request->get('code', null); - if (is_null($authCode)) { - throw new InvalidRequestException('code'); - } + $state = array_key_exists('state', $request->getQueryParams()) + ? $request->getQueryParams()['state'] // $_GET['state'] + : null; - $code = $this->authCodeRepository->get($authCode); - if (($code instanceof AuthCodeEntityInterface) === false) { - throw new InvalidRequestException('code'); - } + // Validate any scopes that are in the request + $scopeParam = array_key_exists('scope', $request->getQueryParams()) + ? $request->getQueryParams()['scope'] // $_GET['scope'] + : ''; + $scopes = $this->validateScopes($scopeParam, $scopeDelimiter, $client); - // Ensure the auth code hasn't expired - if ($code->isExpired() === true) { - throw new InvalidRequestException('code'); - } + // Create a new authorization code + $authCode = new AuthCodeEntity(); + $authCode->setIdentifier(SecureKey::generate()); + $authCode->setExpiryDateTime((new \DateTime())->add($authCodeTTL)); + $authCode->setClient($client); + $authCode->setUserIdentifier($userEntity->getIdentifier()); - // Check redirect URI presented matches redirect URI originally used in authorize request - if ($code->getRedirectUri() !== $redirectUri) { - throw new InvalidRequestException('redirect_uri'); - } + // Associate scopes with the session and access token + foreach ($scopes as $scope) { + $authCode->addScope($scope); + }*/ + } - // Generate the access token - $accessToken = new AccessTokenEntity($this->server); - $accessToken->setIdentifier(SecureKey::generate()); - $expirationDateTime = (new \DateTime())->add($accessTokenTTL); - $accessToken->setExpiryDateTime($expirationDateTime); - $accessToken->setClient($client); + /** + * 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 + */ + protected function respondToAccessTokenRequest( + ServerRequestInterface $request, + ResponseTypeInterface $responseType, + DateInterval $accessTokenTTL + ) { - foreach ($code->getScopes() as $scope) { - $accessToken->addScope($scope); - } + } - $tokenType->setAccessToken($accessToken); - - // Associate a refresh token if set - if ($this->refreshTokenRepository instanceof RefreshTokenRepositoryInterface) { -// $refreshToken = new RefreshTokenEntity($this->server); -// $refreshToken->setId(SecureKey::generate()); -// $refreshToken->setExpireTime($this->server->getGrantType('refresh_token')->getRefreshTokenTTL() + time()); -// $tokenType->setParam('refresh_token', $refreshToken->getId()); -// $refreshToken->setAccessToken($accessToken); - } - - // Expire the auth code - $this->authCodeRepository->delete($code); - - // Save the access token - $this->accessTokenRepository->create($accessToken); - - return $tokenType; + /** + * @inheritdoc + */ + public function canRespondToRequest(ServerRequestInterface $request) + { + return ( + ( + strtoupper($request->getMethod()) === 'GET' + && isset($request->getQueryParams()['response_type']) + && $request->getQueryParams()['response_type'] === 'code' + && isset($request->getQueryParams()['client_id']) + ) || ( + isset($request->getParsedBody()['grant_type']) + && $request->getParsedBody()['grant_type'] === 'authorization_code' + ) + ); } } From 11d25eb5a1da2f39e42c27ff3cd73fa964d2f64f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 11 Feb 2016 17:49:24 +0000 Subject: [PATCH 188/444] Removed old exceptions --- src/Exception/UnauthorizedClientException.php | 36 ------------------ .../UnsupportedResponseTypeException.php | 37 ------------------- 2 files changed, 73 deletions(-) delete mode 100644 src/Exception/UnauthorizedClientException.php delete mode 100644 src/Exception/UnsupportedResponseTypeException.php diff --git a/src/Exception/UnauthorizedClientException.php b/src/Exception/UnauthorizedClientException.php deleted file mode 100644 index fd1f18c3..00000000 --- a/src/Exception/UnauthorizedClientException.php +++ /dev/null @@ -1,36 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Exception; - -/** - * Exception class - */ -class UnauthorizedClientException extends OAuthException -{ - /** - * {@inheritdoc} - */ - public $httpStatusCode = 400; - - /** - * {@inheritdoc} - */ - public $errorType = 'unauthorized_client'; - - /** - * {@inheritdoc} - */ - public function __construct() - { - parent::__construct('The client is not authorized to request an access token using this method.'); - } -} diff --git a/src/Exception/UnsupportedResponseTypeException.php b/src/Exception/UnsupportedResponseTypeException.php deleted file mode 100644 index 8707f0c5..00000000 --- a/src/Exception/UnsupportedResponseTypeException.php +++ /dev/null @@ -1,37 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * @link https://github.com/thephpleague/oauth2-server - */ - -namespace League\OAuth2\Server\Exception; - -/** - * Exception class - */ -class UnsupportedResponseTypeException extends OAuthException -{ - /** - * {@inheritdoc} - */ - public $httpStatusCode = 400; - - /** - * {@inheritdoc} - */ - public $errorType = 'unsupported_response_type'; - - /** - * {@inheritdoc} - */ - public function __construct($parameter, $redirectUri = null) - { - parent::__construct('The authorization server does not support obtaining an access token using this method.'); - $this->redirectUri = $redirectUri; - } -} From 4bc89f3fc2965b6c9b649741f5950352021548fd Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 11 Feb 2016 17:49:31 +0000 Subject: [PATCH 189/444] Removed unused import --- src/Server.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Server.php b/src/Server.php index adb6936d..cc7eb320 100644 --- a/src/Server.php +++ b/src/Server.php @@ -7,7 +7,6 @@ use League\Event\EmitterAwareInterface; use League\Event\EmitterAwareTrait; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\GrantTypeInterface; -use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; From a40ac5d77be06bd0ab44dd719ee3bf5dd1e5c6a0 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 11 Feb 2016 17:49:41 +0000 Subject: [PATCH 190/444] Minor fixes --- src/Exception/OAuthServerException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 5531d5ee..09ef4ec5 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -2,7 +2,6 @@ namespace League\OAuth2\Server\Exception; -use League\OAuth2\Server\Utils\RedirectUri; use Psr\Http\Message\ResponseInterface; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; @@ -185,6 +184,7 @@ class OAuthServerException extends \Exception /** * Invalid refresh token * + * @param string|null $hint * @return static */ public static function invalidRefreshToken($hint = null) From ca776e83a22d9d547731cb7e1ca6df8f493075d0 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 11 Feb 2016 17:58:35 +0000 Subject: [PATCH 191/444] Fix for header writing --- src/ResponseTypes/BearerTokenResponse.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index c67bc990..1056a087 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -63,12 +63,13 @@ class BearerTokenResponse extends AbstractResponseType $responseParams['refresh_token'] = $refreshToken; } - $response + $response = $response ->withStatus(200) ->withHeader('pragma', 'no-cache') ->withHeader('cache-control', 'no-store') - ->withHeader('content-type', 'application/json;charset=UTF-8') - ->getBody()->write(json_encode($responseParams)); + ->withHeader('content-type', 'application/json; charset=UTF-8'); + + $response->getBody()->write(json_encode($responseParams)); return $response; } From d96f57d27f157919d6cd46c52ca07f8ff197f8a8 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 08:33:59 +0000 Subject: [PATCH 192/444] Got rid of mystery $identifier class property, moved it to the getIdentifier method --- src/Grant/AbstractGrant.php | 17 +---------------- src/Grant/ClientCredentialsGrant.php | 15 ++++++++------- src/Grant/GrantTypeInterface.php | 2 +- src/Grant/PasswordGrant.php | 15 ++++++++------- src/Grant/RefreshTokenGrant.php | 15 ++++++++------- 5 files changed, 26 insertions(+), 38 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index c6ffc760..42c1644e 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -31,13 +31,6 @@ abstract class AbstractGrant implements GrantTypeInterface { const SCOPE_DELIMITER_STRING = ' '; - /** - * Grant identifier - * - * @var string - */ - protected $identifier = ''; - /** * Grant responds with * @@ -141,14 +134,6 @@ abstract class AbstractGrant implements GrantTypeInterface $this->refreshTokenTTL = $refreshTokenTTL; } - /** - * {@inheritdoc} - */ - public function getIdentifier() - { - return $this->identifier; - } - /** * {@inheritdoc} */ @@ -317,7 +302,7 @@ abstract class AbstractGrant implements GrantTypeInterface { return ( isset($request->getParsedBody()['grant_type']) - && $request->getParsedBody()['grant_type'] === $this->identifier + && $request->getParsedBody()['grant_type'] === $this->getIdentifier() ); } } diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 918586f9..cf6ce268 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -19,13 +19,6 @@ use Psr\Http\Message\ServerRequestInterface; */ class ClientCredentialsGrant extends AbstractGrant { - /** - * Grant identifier - * - * @var string - */ - protected $identifier = 'client_credentials'; - /** * @inheritdoc */ @@ -47,4 +40,12 @@ class ClientCredentialsGrant extends AbstractGrant return $responseType; } + + /** + * @inheritdoc + */ + public function getIdentifier() + { + return 'client_credentials'; + } } diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index a6a5c63a..eed44f18 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -31,7 +31,7 @@ interface GrantTypeInterface public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL); /** - * Return the identifier + * Return the grant identifier that can be used in matching up requests * * @return string */ diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 9f4f41e8..0e2a1085 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -24,13 +24,6 @@ use Psr\Http\Message\ServerRequestInterface; */ class PasswordGrant extends AbstractGrant { - /** - * Grant identifier - * - * @var string - */ - protected $identifier = 'password'; - /** * @var \League\OAuth2\Server\Repositories\UserRepositoryInterface */ @@ -109,4 +102,12 @@ class PasswordGrant extends AbstractGrant return $user; } + + /** + * @inheritdoc + */ + public function getIdentifier() + { + return 'password'; + } } diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index cf3286c8..dc7d35b1 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -23,13 +23,6 @@ use Psr\Http\Message\ServerRequestInterface; */ class RefreshTokenGrant extends AbstractGrant { - /** - * Grant identifier - * - * @var string - */ - protected $identifier = 'refresh_token'; - /** * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface */ @@ -134,4 +127,12 @@ class RefreshTokenGrant extends AbstractGrant return $refreshTokenData; } + + /** + * @inheritdoc + */ + public function getIdentifier() + { + return 'refresh_token'; + } } From bfcf7af4d85e6cd7becdeafa341e5b59b4798897 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 09:02:17 +0000 Subject: [PATCH 193/444] Added getQueryStringParameter method --- src/Grant/AbstractGrant.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 42c1644e..bf526b8c 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -239,6 +239,20 @@ abstract class AbstractGrant implements GrantTypeInterface return (isset($request->getParsedBody()[$parameter])) ? $request->getParsedBody()[$parameter] : $default; } + /** + * Retrieve query string parameter. + * + * @param string $parameter + * @param \Psr\Http\Message\ServerRequestInterface $request + * @param mixed $default + * + * @return null|string + */ + protected function getQueryStringParameter($parameter, ServerRequestInterface $request, $default = null) + { + return (isset($request->getQueryParams()[$parameter])) ? $request->getQueryParams()[$parameter] : $default; + } + /** * Retrieve server parameter. * From c6d806d3f7e60f7aebfe324a9fb638ad8bbc0bb0 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 09:02:33 +0000 Subject: [PATCH 194/444] Docblock updates --- src/Grant/AbstractGrant.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index bf526b8c..208e5fbc 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -186,6 +186,8 @@ abstract class AbstractGrant implements GrantTypeInterface } /** + * Validate scopes in the request + * * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client * @param string $redirectUri @@ -268,6 +270,8 @@ abstract class AbstractGrant implements GrantTypeInterface } /** + * Issue an access token + * * @param \DateInterval $tokenTTL * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client * @param string $userIdentifier From 7a628409db3b67431cfecc69b8031ffa4abddd48 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 09:03:35 +0000 Subject: [PATCH 195/444] Validate client can now optionally validate secret + redirectUri, and actually validate the redirectUri --- src/Grant/AbstractGrant.php | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 208e5fbc..4b589f4e 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -143,14 +143,20 @@ abstract class AbstractGrant implements GrantTypeInterface } /** + * Validate the client + * * @param \Psr\Http\Message\ServerRequestInterface $request + * @param bool $validateSecret + * @param bool $validateRedirectUri * * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface - * * @throws \League\OAuth2\Server\Exception\OAuthServerException */ - protected function validateClient(ServerRequestInterface $request) - { + protected function validateClient( + ServerRequestInterface $request, + $validateSecret = true, + $validateRedirectUri = false + ) { $clientId = $this->getRequestParameter( 'client_id', $request, @@ -165,14 +171,19 @@ abstract class AbstractGrant implements GrantTypeInterface $request, $this->getServerParameter('PHP_AUTH_PW', $request) ); - if (is_null($clientSecret)) { + if (is_null($clientSecret) && $validateSecret === true) { throw OAuthServerException::invalidRequest('client_secret', null, '`%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, - null, + $redirectUri, $this->getIdentifier() ); From f4b83baf740963e9ed0a71f6a8b2755d284b1c75 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 09:09:39 +0000 Subject: [PATCH 196/444] Fix getClientEntity method call --- src/Grant/AbstractGrant.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 4aa45126..656affd0 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -179,10 +179,10 @@ abstract class AbstractGrant implements GrantTypeInterface } $client = $this->clientRepository->getClientEntity( - $this->getIdentifier(), $clientId, $clientSecret, - $redirectUri + $redirectUri, + $this->getIdentifier() ); if (!$client instanceof ClientEntityInterface) { From 38a7e53cb5feed5a1249c819a64d578a5f31e1ef Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 09:59:47 +0000 Subject: [PATCH 197/444] Added optional redirectUri parameter to accessDenied method --- src/Exception/OAuthServerException.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 35c38dd2..bd386a28 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -197,13 +197,20 @@ class OAuthServerException extends \Exception /** * Access denied * - * @param null|string $hint + * @param string|null $hint + * @param string|null $redirectUri * * @return static */ - public static function accessDenied($hint = null) + public static function accessDenied($hint = null, $redirectUri = null) { - return new static('The server denied the request.', 'access_denied', 401, $hint); + return new static( + 'The resource owner or authorization server denied the request.', + 'access_denied', + 401, + $hint, + $redirectUri + ); } /** From 0b6bcad9fbbdc1158d0f4e20366cf322ab4917fa Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 09:59:59 +0000 Subject: [PATCH 198/444] Added getCookieParameter method --- src/Grant/AbstractGrant.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 656affd0..5be39338 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -264,6 +264,20 @@ abstract class AbstractGrant implements GrantTypeInterface return (isset($request->getQueryParams()[$parameter])) ? $request->getQueryParams()[$parameter] : $default; } + /** + * Retrieve cookie parameter. + * + * @param string $parameter + * @param \Psr\Http\Message\ServerRequestInterface $request + * @param mixed $default + * + * @return null|string + */ + protected function getCookieParameter($parameter, ServerRequestInterface $request, $default = null) + { + return (isset($request->getCookieParams()[$parameter])) ? $request->getCookieParams()[$parameter] : $default; + } + /** * Retrieve server parameter. * From c2c199cf981eb1b8192ab55e74e7134a3d5a6aee Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 10:00:10 +0000 Subject: [PATCH 199/444] Added issueAuthCode method --- src/Grant/AbstractGrant.php | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 5be39338..39fbf543 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -15,6 +15,7 @@ use League\Event\EmitterAwareTrait; use League\Event\EmitterInterface; use League\Event\Event; use League\OAuth2\Server\Entities\AccessTokenEntity; +use League\OAuth2\Server\Entities\AuthCodeEntity; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Entities\ScopeEntity; @@ -321,6 +322,39 @@ abstract class AbstractGrant implements GrantTypeInterface return $accessToken; } + /** + * Issue an auth code + * + * @param \DateInterval $tokenTTL + * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client + * @param string $userIdentifier + * @param string $redirectUri + * @param array $scopes + * + * @return \League\OAuth2\Server\Entities\AuthCodeEntity + * @throws \League\OAuth2\Server\Exception\OAuthServerException + */ + protected function issueAuthCode( + \DateInterval $tokenTTL, + ClientEntityInterface $client, + $userIdentifier, + $redirectUri, + array $scopes = [] + ) { + $authCode = new AuthCodeEntity(); + $authCode->setIdentifier(SecureKey::generate()); + $authCode->setExpiryDateTime((new \DateTime())->add($tokenTTL)); + $authCode->setClient($client); + $authCode->setUserIdentifier($userIdentifier); + $authCode->setRedirectUri($redirectUri); + + foreach ($scopes as $scope) { + $authCode->addScope($scope); + } + + return $authCode; + } + /** * @param \League\OAuth2\Server\Entities\AccessTokenEntity $accessToken * From 264eba9f20d5ae2fa21f98513be6ee545754715e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 10:00:22 +0000 Subject: [PATCH 200/444] Updated AuthCodeRepositoryInterface --- .../AuthCodeRepositoryInterface.php | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Repositories/AuthCodeRepositoryInterface.php b/src/Repositories/AuthCodeRepositoryInterface.php index 481106d3..be341ca0 100644 --- a/src/Repositories/AuthCodeRepositoryInterface.php +++ b/src/Repositories/AuthCodeRepositoryInterface.php @@ -19,27 +19,27 @@ use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; interface AuthCodeRepositoryInterface extends RepositoryInterface { /** - * Get the auth code + * Persists a new auth code to permanent storage * - * @param string $code + * @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $authCodeEntityInterface * - * @return \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface + * @return */ - public function getAuthCodeEntityByCodeString($code); + public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntityInterface); /** - * Persist a new authorization code + * Revoke an auth code * - * @param string $code The authorization code string - * @param integer $expireTime Token expire time - * @param string $redirectUri Client redirect uri + * @param string $codeId */ - public function persistNewAuthCode($code, $expireTime, $redirectUri); + public function revokeAuthCode($codeId); /** - * Delete an access token + * Check if the auth code has been revoked * - * @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $token The access token to delete + * @param string $codeId + * + * @return bool Return true if this code has been revoked */ - public function deleteAuthCodeEntity(AuthCodeEntityInterface $token); + public function isAuthCodeRevoked($codeId); } From dcc3f5d856f2eef0633736a2181041963145712a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 10:00:32 +0000 Subject: [PATCH 201/444] First commit of new ResponseTypes --- .../AuthorizeClientResponseTypeInterface.php | 22 +++++++++++++++++++ .../LoginUserResponseTypeInterface.php | 22 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/ResponseTypes/AuthorizeClientResponseTypeInterface.php create mode 100644 src/ResponseTypes/LoginUserResponseTypeInterface.php diff --git a/src/ResponseTypes/AuthorizeClientResponseTypeInterface.php b/src/ResponseTypes/AuthorizeClientResponseTypeInterface.php new file mode 100644 index 00000000..188a0332 --- /dev/null +++ b/src/ResponseTypes/AuthorizeClientResponseTypeInterface.php @@ -0,0 +1,22 @@ + Date: Fri, 12 Feb 2016 10:00:41 +0000 Subject: [PATCH 202/444] Updated Docblock --- src/Utils/KeyCrypt.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Utils/KeyCrypt.php b/src/Utils/KeyCrypt.php index d5e5e2c4..634cd80b 100644 --- a/src/Utils/KeyCrypt.php +++ b/src/Utils/KeyCrypt.php @@ -51,6 +51,8 @@ class KeyCrypt * @param string $encryptedData * @param string $pathToPublicKey * + * @throws \LogicException + * * @return string */ public static function decrypt($encryptedData, $pathToPublicKey) From fccb06ed6753610c7b13ab3783375fd0b5688c9f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 10:01:15 +0000 Subject: [PATCH 203/444] First commit of updated AuthCodeGrant with respondToAuthorizationRequest method completed --- src/Grant/AuthCodeGrant.php | 204 +++++++++++++++++++++++++----------- 1 file changed, 143 insertions(+), 61 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index c51954e3..1e967437 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -3,100 +3,151 @@ namespace League\OAuth2\Server\Grant; use DateInterval; -use DateTime; use League\OAuth2\Server\Exception\OAuthServerException; +use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; +use League\OAuth2\Server\ResponseTypes\AuthorizeClientResponseTypeInterface; +use League\OAuth2\Server\ResponseTypes\LoginUserResponseTypeInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; +use League\OAuth2\Server\Utils\KeyCrypt; use Psr\Http\Message\ServerRequestInterface; +use Zend\Diactoros\Response; +use Zend\Diactoros\Uri; class AuthCodeGrant extends AbstractGrant { /** - * @inheritdoc + * @var \League\OAuth2\Server\ResponseTypes\LoginUserResponseTypeInterface */ - public function respondToRequest( - ServerRequestInterface $request, - ResponseTypeInterface $responseType, - DateInterval $tokenTTL, - $scopeDelimiter = ' ' + private $loginUserResponseType; + + /** + * @var \DateInterval + */ + private $authCodeTTL; + /** + * @var \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface + */ + private $authCodeRepository; + /** + * @var \League\OAuth2\Server\ResponseTypes\AuthorizeClientResponseTypeInterface + */ + private $authorizeClientResponseType; + + /** + * @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository + * @param \DateInterval $authCodeTTL + * @param \League\OAuth2\Server\ResponseTypes\LoginUserResponseTypeInterface $loginUserResponseType + * @param \League\OAuth2\Server\ResponseTypes\AuthorizeClientResponseTypeInterface $authorizeClientResponseType + */ + public function __construct( + AuthCodeRepositoryInterface $authCodeRepository, + \DateInterval $authCodeTTL, + LoginUserResponseTypeInterface $loginUserResponseType, + AuthorizeClientResponseTypeInterface $authorizeClientResponseType ) { - if ( - isset($request->getQueryParams()['response_type']) - && $request->getQueryParams()['response_type'] === 'code' - && isset($request->getQueryParams()['client_id']) - ) { - return $this->respondToAuthorizationRequest($request, $scopeDelimiter, $tokenTTL); - } elseif ( - isset($request->getParsedBody()['grant_type']) - && $request->getParsedBody()['grant_type'] === 'authorization_code' - ) { - return $this->respondToAccessTokenRequest($request, $responseType, $tokenTTL); - } else { - throw OAuthServerException::serverError('respondToRequest() should not have been called'); - } + $this->authCodeRepository = $authCodeRepository; + $this->authCodeTTL = $authCodeTTL; + $this->loginUserResponseType = $loginUserResponseType; + $this->authorizeClientResponseType = $authorizeClientResponseType; } + /** * Respond to an authorization request * * @param \Psr\Http\Message\ServerRequestInterface $request - * @param string $scopeDelimiter - * @param DateTime $tokenTTL + * + * @return \Psr\Http\Message\ResponseInterface + * @throws \League\OAuth2\Server\Exception\OAuthServerException */ protected function respondToAuthorizationRequest( - ServerRequestInterface $request, - $scopeDelimiter = ' ', - DateTime $tokenTTL + ServerRequestInterface $request ) { - // Get required params - /*$clientId = array_key_exists('client_id', $request->getQueryParams()) - ? $request->getQueryParams()['client_id'] // $_GET['client_id'] - : null; - + $clientId = $this->getQueryStringParameter( + 'client_id', + $request, + $this->getServerParameter('PHP_AUTH_USER', $request) + ); if (is_null($clientId)) { throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); } - $redirectUri = array_key_exists('redirect_uri', $request->getQueryParams()) - ? $request->getQueryParams()['redirect_uri'] // $_GET['redirect_uri'] - : null; - + $redirectUri = $this->getQueryStringParameter('redirect_uri', $request, null); if (is_null($redirectUri)) { throw OAuthServerException::invalidRequest('redirect_uri', null, '`%s` parameter is missing'); } - // Validate client ID and redirect URI $client = $this->clientRepository->getClientEntity( $clientId, - $this->getIdentifier(), null, - $redirectUri + $redirectUri, + $this->getIdentifier() ); - if (($client instanceof ClientEntityInterface) === false) { + if (!$client instanceof ClientEntityInterface) { + $this->emitter->emit(new Event('client.authentication.failed', $request)); + throw OAuthServerException::invalidClient(); } - $state = array_key_exists('state', $request->getQueryParams()) - ? $request->getQueryParams()['state'] // $_GET['state'] - : null; + $scopes = $this->validateScopes($request, $client, $redirectUri); + $queryString = http_build_query($request->getQueryParams()); - // Validate any scopes that are in the request - $scopeParam = array_key_exists('scope', $request->getQueryParams()) - ? $request->getQueryParams()['scope'] // $_GET['scope'] - : ''; - $scopes = $this->validateScopes($scopeParam, $scopeDelimiter, $client); + // Check if the user has been validated + $userIdCookieParam = $this->getCookieParameter('oauth_user_id', $request, null); + if ($userIdCookieParam === null) { + return $this->loginUserResponseType->handle($client, $scopes, $queryString, $this->pathToPrivateKey); + } else { + try { + $userId = KeyCrypt::decrypt($userIdCookieParam, $this->pathToPublicKey); + } catch (\LogicException $e) { + throw OAuthServerException::serverError($e->getMessage()); + } + } - // Create a new authorization code - $authCode = new AuthCodeEntity(); - $authCode->setIdentifier(SecureKey::generate()); - $authCode->setExpiryDateTime((new \DateTime())->add($authCodeTTL)); - $authCode->setClient($client); - $authCode->setUserIdentifier($userEntity->getIdentifier()); + // Check the user has approved the request + $userApprovedCookieParam = $this->getCookieParameter('oauth_user_approved_client', $request, null); + if ($userApprovedCookieParam === null) { + return $this->authorizeClientResponseType->handle($client, $scopes, $queryString, $this->pathToPrivateKey); + } else { + try { + $userApprovedClient = KeyCrypt::decrypt($userApprovedCookieParam, $this->pathToPublicKey); + } catch (\LogicException $e) { + throw OAuthServerException::serverError($e->getMessage()); + } + } - // Associate scopes with the session and access token - foreach ($scopes as $scope) { - $authCode->addScope($scope); - }*/ + $stateParameter = $this->getQueryStringParameter('state', $request); + + $redirectUri = new Uri($redirectUri); + parse_str($redirectUri->getQuery(), $redirectPayload); + if ($stateParameter !== null) { + $redirectPayload['state'] = $stateParameter; + } + + if ($userApprovedClient === 1) { + $authCode = $this->issueAuthCode( + $this->authCodeTTL, + $client, + $userId, + $redirectUri, + $scopes + ); + $this->authCodeRepository->persistNewAuthCode($authCode); + + $redirectPayload['code'] = $authCode->getIdentifier(); + + return new Response( + 'php://memory', + 302, + [ + 'Location' => $redirectUri->withQuery(http_build_query($redirectPayload)), + ] + ); + } + + $exception = OAuthServerException::accessDenied('The user denied the request', (string) $redirectUri); + return $exception->generateHttpResponse(); } /** @@ -127,10 +178,41 @@ class AuthCodeGrant extends AbstractGrant && isset($request->getQueryParams()['response_type']) && $request->getQueryParams()['response_type'] === 'code' && isset($request->getQueryParams()['client_id']) - ) || ( - isset($request->getParsedBody()['grant_type']) - && $request->getParsedBody()['grant_type'] === 'authorization_code' - ) + ) || (parent::canRespondToRequest($request)) ); } + + /** + * Return the grant identifier that can be used in matching up requests + * + * @return string + */ + public function getIdentifier() + { + return 'authorization_code'; + } + + /** + * @inheritdoc + */ + public function respondToRequest( + ServerRequestInterface $request, + ResponseTypeInterface $responseType, + \DateInterval $accessTokenTTL + ) { + if ( + isset($request->getQueryParams()['response_type']) + && $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'); + } + } } From ac9955b393725ca7d361765e6438c2f28503fced Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 11:30:59 +0000 Subject: [PATCH 204/444] Removed response type interfaces for auth code login + authorize because they were a stupid idea --- .../AuthorizeClientResponseTypeInterface.php | 22 ------------------- .../LoginUserResponseTypeInterface.php | 22 ------------------- 2 files changed, 44 deletions(-) delete mode 100644 src/ResponseTypes/AuthorizeClientResponseTypeInterface.php delete mode 100644 src/ResponseTypes/LoginUserResponseTypeInterface.php diff --git a/src/ResponseTypes/AuthorizeClientResponseTypeInterface.php b/src/ResponseTypes/AuthorizeClientResponseTypeInterface.php deleted file mode 100644 index 188a0332..00000000 --- a/src/ResponseTypes/AuthorizeClientResponseTypeInterface.php +++ /dev/null @@ -1,22 +0,0 @@ - Date: Fri, 12 Feb 2016 11:31:19 +0000 Subject: [PATCH 205/444] Suggest league/plates --- composer.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/composer.json b/composer.json index 89cabf93..21ee5356 100644 --- a/composer.json +++ b/composer.json @@ -65,5 +65,8 @@ "branch-alias": { "dev-V5-WIP": "5.0-dev" } + }, + "suggest": { + "league/plates": "Required for parsing authorization code templates" } } From 556c9fa782e1e309a7e464446e36bb481c365e42 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 11:31:46 +0000 Subject: [PATCH 206/444] Require league/plates in the examples composer.json --- examples/composer.json | 3 +- examples/composer.lock | 63 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/examples/composer.json b/examples/composer.json index 0b85ac70..f0bf2564 100644 --- a/examples/composer.json +++ b/examples/composer.json @@ -7,7 +7,8 @@ ], "require": { "slim/slim": "3.0.*", - "league/oauth2-server": "dev-V5-WIP" + "league/oauth2-server": "dev-V5-WIP", + "league/plates": "^3.1" }, "autoload": { "psr-4": { diff --git a/examples/composer.lock b/examples/composer.lock index 251ab498..776fb37a 100644 --- a/examples/composer.lock +++ b/examples/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "ff6f832d21c141662627622e68079ca5", - "content-hash": "f08d5c7c3ede910150d75ad3c56d1b46", + "hash": "143453cc35e7f499b130b6460222dc5a", + "content-hash": "1ea46581fb6db25f323a37a45ef74f95", "packages": [ { "name": "container-interop/container-interop", @@ -145,9 +145,14 @@ { "name": "league/oauth2-server", "version": "dev-V5-WIP", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/oauth2-server.git", + "reference": "95919a688e29c911d1e4e83112cacd18f719700f" + }, "dist": { "type": "path", - "url": "../", + "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/95919a688e29c911d1e4e83112cacd18f719700f", "reference": "168e7640c6e8217b7e961151de522810b3edce6e", "shasum": null }, @@ -214,6 +219,58 @@ "server" ] }, + { + "name": "league/plates", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/plates.git", + "reference": "2d8569e9f140a70d6a05db38006926f7547cb802" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/plates/zipball/2d8569e9f140a70d6a05db38006926f7547cb802", + "reference": "2d8569e9f140a70d6a05db38006926f7547cb802", + "shasum": "" + }, + "require-dev": { + "mikey179/vfsstream": "~1.4.0", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Plates\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Reinink", + "email": "jonathan@reinink.ca", + "role": "Developer" + } + ], + "description": "Plates, the native PHP template system that's fast, easy to use and easy to extend.", + "homepage": "http://platesphp.com", + "keywords": [ + "league", + "package", + "templates", + "templating", + "views" + ], + "time": "2015-07-09 02:14:40" + }, { "name": "namshi/jose", "version": "6.1.0", From 1c913fe75e147fcb19ce5565e4df701436602a7c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 11:32:09 +0000 Subject: [PATCH 207/444] Added default basic HTML login + authorise templates --- .../DefaultTemplates/authorize_client.php | 35 +++++++++++++++++++ .../DefaultTemplates/login_user.php | 35 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 src/ResponseTypes/DefaultTemplates/authorize_client.php create mode 100644 src/ResponseTypes/DefaultTemplates/login_user.php diff --git a/src/ResponseTypes/DefaultTemplates/authorize_client.php b/src/ResponseTypes/DefaultTemplates/authorize_client.php new file mode 100644 index 00000000..8ef9dddd --- /dev/null +++ b/src/ResponseTypes/DefaultTemplates/authorize_client.php @@ -0,0 +1,35 @@ + + + + + Authorize <?=$this->e($client->getName)?> + + + + +

+ Authorize e($client->getName)?> +

+ +

+ Do you want to authorize e($client->getName)?> to access the following data? +

+ +
    + +
  • getIdentifier?>
  • + +
+ +
+ + +
+ +
+ + +
+ + + \ No newline at end of file diff --git a/src/ResponseTypes/DefaultTemplates/login_user.php b/src/ResponseTypes/DefaultTemplates/login_user.php new file mode 100644 index 00000000..75b6b529 --- /dev/null +++ b/src/ResponseTypes/DefaultTemplates/login_user.php @@ -0,0 +1,35 @@ + + + + + Login + + + + +

Login

+ + +
+ e($error)?> +
+ + +
+ + + + +
+ + + + +
+ + + +
+ + + \ No newline at end of file From 2025749fa4d874a60ae1b714d7fe44a0e18e022f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 11:55:41 +0000 Subject: [PATCH 208/444] Updated `respondToAuthorizationRequest` to use Plates templates instead of custom ResponseType --- src/Grant/AuthCodeGrant.php | 154 ++++++++++++++++++++++++++---------- 1 file changed, 113 insertions(+), 41 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 1e967437..b5cfd85d 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -3,23 +3,19 @@ namespace League\OAuth2\Server\Grant; use DateInterval; +use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; -use League\OAuth2\Server\ResponseTypes\AuthorizeClientResponseTypeInterface; -use League\OAuth2\Server\ResponseTypes\LoginUserResponseTypeInterface; +use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\Utils\KeyCrypt; +use League\Plates\Engine; use Psr\Http\Message\ServerRequestInterface; use Zend\Diactoros\Response; use Zend\Diactoros\Uri; class AuthCodeGrant extends AbstractGrant { - /** - * @var \League\OAuth2\Server\ResponseTypes\LoginUserResponseTypeInterface - */ - private $loginUserResponseType; - /** * @var \DateInterval */ @@ -28,27 +24,41 @@ class AuthCodeGrant extends AbstractGrant * @var \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface */ private $authCodeRepository; - /** - * @var \League\OAuth2\Server\ResponseTypes\AuthorizeClientResponseTypeInterface - */ - private $authorizeClientResponseType; /** - * @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository - * @param \DateInterval $authCodeTTL - * @param \League\OAuth2\Server\ResponseTypes\LoginUserResponseTypeInterface $loginUserResponseType - * @param \League\OAuth2\Server\ResponseTypes\AuthorizeClientResponseTypeInterface $authorizeClientResponseType + * @var \League\OAuth2\Server\Repositories\UserRepositoryInterface + */ + private $userRepository; + + /** + * @var null|string + */ + private $pathToLoginTemplate; + + /** + * @var null|string + */ + private $pathToAuthorizeTemplate; + + /** + * @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository + * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository + * @param \DateInterval $authCodeTTL + * @param string|null $pathToLoginTemplate + * @param string|null $pathToAuthorizeTemplate */ public function __construct( AuthCodeRepositoryInterface $authCodeRepository, + UserRepositoryInterface $userRepository, \DateInterval $authCodeTTL, - LoginUserResponseTypeInterface $loginUserResponseType, - AuthorizeClientResponseTypeInterface $authorizeClientResponseType + $pathToLoginTemplate = null, + $pathToAuthorizeTemplate = null ) { $this->authCodeRepository = $authCodeRepository; + $this->userRepository = $userRepository; $this->authCodeTTL = $authCodeTTL; - $this->loginUserResponseType = $loginUserResponseType; - $this->authorizeClientResponseType = $authorizeClientResponseType; + $this->pathToLoginTemplate = $pathToLoginTemplate; + $this->pathToAuthorizeTemplate = $pathToAuthorizeTemplate; } @@ -92,31 +102,99 @@ class AuthCodeGrant extends AbstractGrant $scopes = $this->validateScopes($request, $client, $redirectUri); $queryString = http_build_query($request->getQueryParams()); + $postbackUri = new Uri( + sprintf( + '//%s%s', + $request->getServerParams()['HTTP_HOST'], + $request->getServerParams()['REQUEST_URI'] + ) + ); + + $userId = null; + $userHasApprovedClient = $userHasApprovedClient = $this->getRequestParameter('action', null); // Check if the user has been validated - $userIdCookieParam = $this->getCookieParameter('oauth_user_id', $request, null); - if ($userIdCookieParam === null) { - return $this->loginUserResponseType->handle($client, $scopes, $queryString, $this->pathToPrivateKey); - } else { + $oauthCookie = $this->getCookieParameter('oauth_authorize_request', $request, null); + if ($oauthCookie !== null) { try { - $userId = KeyCrypt::decrypt($userIdCookieParam, $this->pathToPublicKey); + $oauthCookiePayload = json_decode(KeyCrypt::decrypt($oauthCookie, $this->pathToPublicKey)); + $userId = $oauthCookiePayload->user_id; + $userHasApprovedClient = $oauthCookiePayload->client_is_authorized; } catch (\LogicException $e) { throw OAuthServerException::serverError($e->getMessage()); } } - // Check the user has approved the request - $userApprovedCookieParam = $this->getCookieParameter('oauth_user_approved_client', $request, null); - if ($userApprovedCookieParam === null) { - return $this->authorizeClientResponseType->handle($client, $scopes, $queryString, $this->pathToPrivateKey); - } else { - try { - $userApprovedClient = KeyCrypt::decrypt($userApprovedCookieParam, $this->pathToPublicKey); - } catch (\LogicException $e) { - throw OAuthServerException::serverError($e->getMessage()); + // The username + password might be available in $_POST + $usernameParameter = $this->getRequestParameter('username', null); + $passwordParameter = $this->getRequestParameter('password', 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(); + $html = $engine->render( + ($this->pathToLoginTemplate === null) + ? __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user.php' + : $this->pathToLoginTemplate, + [ + '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(); + $html = $engine->render( + ($this->pathToLoginTemplate === null) + ? __DIR__ . '/../ResponseTypes/DefaultTemplates/authorize_client.php' + : $this->pathToAuthorizeTemplate, + [ + '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', + KeyCrypt::encrypt( + json_encode([ + 'user_id' => $userId, + 'client_is_authorized' => null, + ]), + $this->pathToPrivateKey + ), + (new \DateTime())->add(new \DateInterval('PT5M'))->format('D, d M Y H:i:s e') + ), + ] + ); + } + $stateParameter = $this->getQueryStringParameter('state', $request); $redirectUri = new Uri($redirectUri); @@ -125,7 +203,7 @@ class AuthCodeGrant extends AbstractGrant $redirectPayload['state'] = $stateParameter; } - if ($userApprovedClient === 1) { + if ($userHasApprovedClient === true) { $authCode = $this->issueAuthCode( $this->authCodeTTL, $client, @@ -137,13 +215,7 @@ class AuthCodeGrant extends AbstractGrant $redirectPayload['code'] = $authCode->getIdentifier(); - return new Response( - 'php://memory', - 302, - [ - 'Location' => $redirectUri->withQuery(http_build_query($redirectPayload)), - ] - ); + return new Response\RedirectResponse($redirectUri->withQuery(http_build_query($redirectPayload))); } $exception = OAuthServerException::accessDenied('The user denied the request', (string) $redirectUri); From d2760e4ec7e5aa768e61491c8d3cc563788983e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Fri, 12 Feb 2016 13:56:14 +0100 Subject: [PATCH 209/444] secure access to body params --- src/Grant/AbstractGrant.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 01917c91..9d22418b 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -249,13 +249,15 @@ abstract class AbstractGrant implements GrantTypeInterface */ protected function getRequestParameter($parameter, ServerRequestInterface $request, $default = null) { - return (isset($request->getParsedBody()[$parameter])) ? $request->getParsedBody()[$parameter] : $default; + return (is_array($request->getParsedBody()) && isset($request->getParsedBody()[$parameter])) + ? $request->getParsedBody()[$parameter] + : $default; } /** * Retrieve server parameter. * - * @param string|array $parameter + * @param string $parameter * @param \Psr\Http\Message\ServerRequestInterface $request * @param mixed $default * @@ -314,7 +316,8 @@ abstract class AbstractGrant implements GrantTypeInterface public function canRespondToRequest(ServerRequestInterface $request) { return ( - isset($request->getParsedBody()['grant_type']) + is_array($request->getParsedBody()) + && isset($request->getParsedBody()['grant_type']) && $request->getParsedBody()['grant_type'] === $this->identifier ); } From 5e326d9e4544f69ed09ef751180030ead7675776 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 13:01:25 +0000 Subject: [PATCH 210/444] First commit of respondToAccessTokenRequest --- src/Grant/AuthCodeGrant.php | 48 ++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index b5cfd85d..763cfbdf 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -3,6 +3,7 @@ namespace League\OAuth2\Server\Grant; use DateInterval; +use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; @@ -213,7 +214,18 @@ class AuthCodeGrant extends AbstractGrant ); $this->authCodeRepository->persistNewAuthCode($authCode); - $redirectPayload['code'] = $authCode->getIdentifier(); + $redirectPayload['code'] = KeyCrypt::encrypt( + json_encode( + [ + 'client_id' => $authCode->getClient()->getIdentifier(), + 'auth_code_id' => $authCode->getIdentifier(), + 'scopes' => $authCode->getScopes(), + 'user_id' => $authCode->getUserIdentifier(), + 'expire_time' => $this->authCodeTTL->format('U'), + ] + ), + $this->pathToPrivateKey + ); return new Response\RedirectResponse($redirectUri->withQuery(http_build_query($redirectPayload))); } @@ -236,7 +248,41 @@ class AuthCodeGrant extends AbstractGrant ResponseTypeInterface $responseType, DateInterval $accessTokenTTL ) { + // Validate request + $client = $this->validateClient($request); + $scopes = $this->validateScopes($request, $client); + $encryptedAuthcode = $this->getRequestParameter('code', $request, null); + if ($encryptedAuthcode === null) { + throw OAuthServerException::invalidRequest('code'); + } + + // Validate the authorization code + try { + $authCodePayload = json_decode(KeyCrypt::decrypt($encryptedAuthcode, $this->pathToPrivateKey)); + if (time() > $authCodePayload->expire_time) { + throw OAuthServerException::invalidRequest('code', 'Authorization code has expired'); + } + } catch (\LogicException $e) { + throw OAuthServerException::invalidRequest('code'); + } + + $client = new ClientEntity(); + $client->setIdentifier($authCodePayload->client_id); + + // Issue and persist access token + $accessToken = $this->issueAccessToken( + $accessTokenTTL, + $client, + $authCodePayload->user_id, + $authCodePayload->scopes + ); + $this->accessTokenRepository->persistNewAccessToken($accessToken); + + // Inject access token into response type + $responseType->setAccessToken($accessToken); + + return $responseType; } /** From 9b97778618ac551866f53dd182f0baa6c67a95bd Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 13:02:26 +0000 Subject: [PATCH 211/444] Removed unused dependency --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index 21ee5356..55357050 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,6 @@ "php": ">=5.5.9", "league/event": "~2.1", "zendframework/zend-diactoros": "~1.1", - "namshi/jose": "^6.0", "lcobucci/jwt": "^3.1", "paragonie/random_compat": "^1.1" }, From f314154216f82b30a172f93a771f2583aff58f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Fri, 12 Feb 2016 14:19:47 +0100 Subject: [PATCH 212/444] abstract access token validation --- examples/public/middleware_authentication.php | 4 ++-- .../AuthenticationServerMiddleware.php | 6 ++++-- src/Middleware/ResourceServerMiddleware.php | 8 +++++--- src/Server.php | 20 ++++++++++++++++--- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/examples/public/middleware_authentication.php b/examples/public/middleware_authentication.php index f9b525dc..d928e19d 100644 --- a/examples/public/middleware_authentication.php +++ b/examples/public/middleware_authentication.php @@ -1,5 +1,7 @@ generateHttpResponse($response); } catch (\Exception $exception) { - $response->getBody()->write($exception->getMessage()); + $body = new Stream('php://temp', 'r+'); + $body->write($exception->getMessage()); - return $response->withStatus(500); + return $response->withStatus(500)->withBody($body); } if (in_array($response->getStatusCode(), [400, 401, 500])) { diff --git a/src/Middleware/ResourceServerMiddleware.php b/src/Middleware/ResourceServerMiddleware.php index 1794cdce..0f0b20ae 100644 --- a/src/Middleware/ResourceServerMiddleware.php +++ b/src/Middleware/ResourceServerMiddleware.php @@ -6,6 +6,7 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Server; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Zend\Diactoros\Stream; class ResourceServerMiddleware { @@ -34,13 +35,14 @@ class ResourceServerMiddleware public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { try { - $request = $this->server->getResponseType()->determineAccessTokenInHeader($request); + $request = $this->server->validateRequest($request); } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); } catch (\Exception $exception) { - $response->getBody()->write($exception->getMessage()); + $body = new Stream('php://temp', 'r+'); + $body->write($exception->getMessage()); - return $response->withStatus(500); + return $response->withStatus(500)->withBody($body); } // Pass the request and response on to the next responder in the chain diff --git a/src/Server.php b/src/Server.php index b63ad6ed..d8e420c1 100644 --- a/src/Server.php +++ b/src/Server.php @@ -26,7 +26,7 @@ class Server implements EmitterAwareInterface protected $enabledGrantTypes = []; /** - * @var DateInterval[] + * @var \DateInterval[] */ protected $grantTypeAccessTokenTTL = []; @@ -90,7 +90,7 @@ class Server implements EmitterAwareInterface * Enable a grant type on the server * * @param \League\OAuth2\Server\Grant\GrantTypeInterface $grantType - * @param DateInterval $accessTokenTTL + * @param \DateInterval $accessTokenTTL */ public function enableGrantType(GrantTypeInterface $grantType, \DateInterval $accessTokenTTL) { @@ -143,12 +143,26 @@ class Server implements EmitterAwareInterface return $tokenResponse->generateHttpResponse($response); } + /** + * Determine the access token validity + * + * @param \Psr\Http\Message\ServerRequestInterface $request + * + * @return \Psr\Http\Message\ServerRequestInterface + * + * @throws \League\OAuth2\Server\Exception\OAuthServerException + */ + public function validateRequest(ServerRequestInterface $request) + { + return $this->getResponseType()->determineAccessTokenInHeader($request); + } + /** * Get the token type that grants will return in the HTTP response * * @return ResponseTypeInterface */ - public function getResponseType() + protected function getResponseType() { if (!$this->responseType instanceof ResponseTypeInterface) { $this->responseType = new BearerTokenResponse( From 0115c41eeabff40d6981f179c99dadc1715d2daf Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 13:32:58 +0000 Subject: [PATCH 213/444] Numerous bug fixes --- examples/public/auth_code.php | 78 ++++++++++++------- .../src/Repositories/AuthCodeRepository.php | 42 ++++++++++ src/Grant/AuthCodeGrant.php | 46 +++++++---- .../AuthCodeRepositoryInterface.php | 6 +- 4 files changed, 125 insertions(+), 47 deletions(-) create mode 100644 examples/src/Repositories/AuthCodeRepository.php diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index d0e76989..3b2642c0 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -1,10 +1,10 @@ enableGrantType($passwordGrant); - // App -$app = new App([Server::class => $server]); +$app = new App([ + Server::class => function () { -$app->any('/authorise', function (Request $request, Response $response) { - if (strtoupper($request->getMethod()) === 'GET') { - $response = $response->withHeader('Set-Cookie', $authCodeGrant->storeOriginalRequestParams) - } + // Init our repositories + $clientRepository = new ClientRepository(); + $scopeRepository = new ScopeRepository(); + $accessTokenRepository = new AccessTokenRepository(); + $userRepository = new UserRepository(); + $refreshTokenRepository = new RefreshTokenRepository(); + $authCodeRepository = new AuthCodeRepository(); + + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + + // Setup the authorization server + $server = new Server( + $clientRepository, + $accessTokenRepository, + $scopeRepository, + $privateKeyPath, + $publicKeyPath + ); + + // Enable the password grant on the server with a token TTL of 1 hour + $server->enableGrantType( + new \League\OAuth2\Server\Grant\AuthCodeGrant( + $authCodeRepository, + $refreshTokenRepository, + $userRepository, + new \DateInterval('PT10M') + ), + new \DateInterval('PT1H') + ); + + return $server; + }, +]); + +$app->any('/authorize', function (Request $request, Response $response) { + /** @var Server $server */ + $server = $this->get(Server::class); + try { + return $server->respondToRequest($request, $response); + } catch (OAuthServerException $e) { + return $e->generateHttpResponse($response); + } catch (\Exception $e) { + return $response->withStatus(500)->write($e->getMessage()); + } }); $app->post('/access_token', function (Request $request, Response $response) { /** @var Server $server */ $server = $this->get(Server::class); try { - return $server->respondToRequest($request); + return $server->respondToRequest($request, $response); } catch (OAuthServerException $e) { - return $e->generateHttpResponse(); + return $e->generateHttpResponse($response); } catch (\Exception $e) { return $response->withStatus(500)->write($e->getMessage()); } diff --git a/examples/src/Repositories/AuthCodeRepository.php b/examples/src/Repositories/AuthCodeRepository.php new file mode 100644 index 00000000..dd91c749 --- /dev/null +++ b/examples/src/Repositories/AuthCodeRepository.php @@ -0,0 +1,42 @@ +authCodeRepository = $authCodeRepository; + $this->refreshTokenRepository = $refreshTokenRepository; $this->userRepository = $userRepository; $this->authCodeTTL = $authCodeTTL; $this->pathToLoginTemplate = $pathToLoginTemplate; @@ -242,6 +250,7 @@ class AuthCodeGrant extends AbstractGrant * @param \DateInterval $accessTokenTTL * * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface + * @throws \League\OAuth2\Server\Exception\OAuthServerException */ protected function respondToAccessTokenRequest( ServerRequestInterface $request, @@ -250,37 +259,44 @@ class AuthCodeGrant extends AbstractGrant ) { // Validate request $client = $this->validateClient($request); - $scopes = $this->validateScopes($request, $client); - $encryptedAuthcode = $this->getRequestParameter('code', $request, null); + $encryptedAuthCode = $this->getRequestParameter('code', $request, null); - if ($encryptedAuthcode === null) { + if ($encryptedAuthCode === null) { throw OAuthServerException::invalidRequest('code'); } // Validate the authorization code try { - $authCodePayload = json_decode(KeyCrypt::decrypt($encryptedAuthcode, $this->pathToPrivateKey)); + $authCodePayload = json_decode(KeyCrypt::decrypt($encryptedAuthCode, $this->pathToPrivateKey)); if (time() > $authCodePayload->expire_time) { throw OAuthServerException::invalidRequest('code', 'Authorization code has expired'); } + + if ($this->authCodeRepository->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'); + } } catch (\LogicException $e) { throw OAuthServerException::invalidRequest('code'); } - $client = new ClientEntity(); - $client->setIdentifier($authCodePayload->client_id); - - // Issue and persist access token + // Issue and persist access + refresh tokens $accessToken = $this->issueAccessToken( $accessTokenTTL, $client, $authCodePayload->user_id, $authCodePayload->scopes ); + $refreshToken = $this->issueRefreshToken($accessToken); $this->accessTokenRepository->persistNewAccessToken($accessToken); + $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); - // Inject access token into response type + // Inject tokens into response type $responseType->setAccessToken($accessToken); + $responseType->setRefreshToken($refreshToken); return $responseType; } diff --git a/src/Repositories/AuthCodeRepositoryInterface.php b/src/Repositories/AuthCodeRepositoryInterface.php index be341ca0..a6742092 100644 --- a/src/Repositories/AuthCodeRepositoryInterface.php +++ b/src/Repositories/AuthCodeRepositoryInterface.php @@ -21,11 +21,9 @@ interface AuthCodeRepositoryInterface extends RepositoryInterface /** * Persists a new auth code to permanent storage * - * @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $authCodeEntityInterface - * - * @return + * @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $authCodeEntity */ - public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntityInterface); + public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity); /** * Revoke an auth code From f6cc8bbb42050769a9f3b427ba5fc679076bf11d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 14:17:49 +0000 Subject: [PATCH 214/444] Import namespace --- examples/public/auth_code.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index 3b2642c0..761f7ae3 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -1,6 +1,7 @@ enableGrantType( - new \League\OAuth2\Server\Grant\AuthCodeGrant( + new AuthCodeGrant( $authCodeRepository, $refreshTokenRepository, $userRepository, From 6dd4caf0560ae2c8f6fe7dc951a00eb0c5079ac6 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 14:17:58 +0000 Subject: [PATCH 215/444] Fix for redirect_uri --- examples/src/Repositories/ClientRepository.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src/Repositories/ClientRepository.php b/examples/src/Repositories/ClientRepository.php index 1130121e..d708a4a7 100644 --- a/examples/src/Repositories/ClientRepository.php +++ b/examples/src/Repositories/ClientRepository.php @@ -15,7 +15,7 @@ class ClientRepository implements ClientRepositoryInterface 'myawesomeapp' => [ 'secret' => password_hash('abc123', PASSWORD_BCRYPT), 'name' => 'My Awesome App', - 'redirect_uri' => '' + 'redirect_uri' => 'http://foo/bar' ] ]; @@ -30,7 +30,7 @@ class ClientRepository implements ClientRepositoryInterface } // Check if redirect URI is valid - if ($redirectUri !== null && $redirectUri !== $clients[$clientIdentifier]['redirectUri']) { + if ($redirectUri !== null && $redirectUri !== $clients[$clientIdentifier]['redirect_uri']) { return null; } From 4234b69f3a4ee4c6647d5a105340a69854592adf Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 14:18:10 +0000 Subject: [PATCH 216/444] Fix for method calls --- src/ResponseTypes/DefaultTemplates/authorize_client.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ResponseTypes/DefaultTemplates/authorize_client.php b/src/ResponseTypes/DefaultTemplates/authorize_client.php index 8ef9dddd..81587174 100644 --- a/src/ResponseTypes/DefaultTemplates/authorize_client.php +++ b/src/ResponseTypes/DefaultTemplates/authorize_client.php @@ -2,22 +2,22 @@ - Authorize <?=$this->e($client->getName)?> + Authorize <?=$this->e($client->getName())?>

- Authorize e($client->getName)?> + Authorize e($client->getName())?>

- Do you want to authorize e($client->getName)?> to access the following data? + Do you want to authorize e($client->getName())?> to access the following data?

    -
  • getIdentifier?>
  • +
  • getIdentifier()?>
From 796106b6c1ca397ccc99857ff0764c2264485c04 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 14:18:34 +0000 Subject: [PATCH 217/444] Fix for non-imported namespace --- src/Server.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Server.php b/src/Server.php index b63ad6ed..52605297 100644 --- a/src/Server.php +++ b/src/Server.php @@ -2,6 +2,7 @@ namespace League\OAuth2\Server; +use DateInterval; use League\Event\EmitterAwareInterface; use League\Event\EmitterAwareTrait; use League\OAuth2\Server\Exception\OAuthServerException; @@ -92,7 +93,7 @@ class Server implements EmitterAwareInterface * @param \League\OAuth2\Server\Grant\GrantTypeInterface $grantType * @param DateInterval $accessTokenTTL */ - public function enableGrantType(GrantTypeInterface $grantType, \DateInterval $accessTokenTTL) + public function enableGrantType(GrantTypeInterface $grantType, DateInterval $accessTokenTTL) { $grantType->setAccessTokenRepository($this->accessTokenRepository); $grantType->setClientRepository($this->clientRepository); From 1a5030200ad190809955d8bfc9006699f9165c5b Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 14:18:45 +0000 Subject: [PATCH 218/444] The response may be a PSR response which is valid --- src/Server.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Server.php b/src/Server.php index 52605297..c7639db3 100644 --- a/src/Server.php +++ b/src/Server.php @@ -137,7 +137,11 @@ class Server implements EmitterAwareInterface } } - if (!$tokenResponse instanceof ResponseTypeInterface) { + if ($tokenResponse instanceof ResponseInterface) { + return $tokenResponse; + } + + if ($tokenResponse instanceof ResponseTypeInterface === false) { return OAuthServerException::unsupportedGrantType()->generateHttpResponse($response); } From 85b9412813edbc779f116a8406c63a9779f6c2ec Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 14:18:52 +0000 Subject: [PATCH 219/444] Multiple fixes --- src/Grant/AuthCodeGrant.php | 50 ++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 67c55db2..0a26d423 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -3,6 +3,7 @@ namespace League\OAuth2\Server\Grant; use DateInterval; +use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; @@ -11,6 +12,7 @@ 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; @@ -66,8 +68,12 @@ class AuthCodeGrant extends AbstractGrant $this->refreshTokenRepository = $refreshTokenRepository; $this->userRepository = $userRepository; $this->authCodeTTL = $authCodeTTL; - $this->pathToLoginTemplate = $pathToLoginTemplate; - $this->pathToAuthorizeTemplate = $pathToAuthorizeTemplate; + $this->pathToLoginTemplate = ($pathToLoginTemplate === null) + ? __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user.php' + : $this->pathToLoginTemplate; + $this->pathToAuthorizeTemplate = ($pathToLoginTemplate === null) + ? __DIR__ . '/../ResponseTypes/DefaultTemplates/authorize_client.php' + : $this->pathToAuthorizeTemplate; } @@ -103,7 +109,7 @@ class AuthCodeGrant extends AbstractGrant $this->getIdentifier() ); - if (!$client instanceof ClientEntityInterface) { + if ($client instanceof ClientEntityInterface === false) { $this->emitter->emit(new Event('client.authentication.failed', $request)); throw OAuthServerException::invalidClient(); @@ -120,23 +126,27 @@ class AuthCodeGrant extends AbstractGrant ); $userId = null; - $userHasApprovedClient = $userHasApprovedClient = $this->getRequestParameter('action', null); + $userHasApprovedClient = null; + if ($this->getRequestParameter('action', $request, null) !== null) { + $userHasApprovedClient = ($this->getRequestParameter('action', $request) === 'approve'); + } - // Check if the user has been validated + // 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)); - $userId = $oauthCookiePayload->user_id; - $userHasApprovedClient = $oauthCookiePayload->client_is_authorized; + 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', null); - $passwordParameter = $this->getRequestParameter('password', null); + $usernameParameter = $this->getRequestParameter('username', $request, null); + $passwordParameter = $this->getRequestParameter('password', $request, null); $loginError = null; @@ -156,11 +166,9 @@ class AuthCodeGrant extends AbstractGrant // The user hasn't logged in yet so show a login form if ($userId === null) { - $engine = new Engine(); + $engine = new Engine(dirname($this->pathToLoginTemplate)); $html = $engine->render( - ($this->pathToLoginTemplate === null) - ? __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user.php' - : $this->pathToLoginTemplate, + 'login_user', [ 'error' => $loginError, 'postback_uri' => (string) $postbackUri->withQuery($queryString), @@ -173,11 +181,9 @@ class AuthCodeGrant extends AbstractGrant // The user hasn't approved the client yet so show an authorize form if ($userId !== null && $userHasApprovedClient === null) { - $engine = new Engine(); + $engine = new Engine(dirname($this->pathToAuthorizeTemplate)); $html = $engine->render( - ($this->pathToLoginTemplate === null) - ? __DIR__ . '/../ResponseTypes/DefaultTemplates/authorize_client.php' - : $this->pathToAuthorizeTemplate, + 'authorize_client', [ 'client' => $client, 'scopes' => $scopes, @@ -191,13 +197,12 @@ class AuthCodeGrant extends AbstractGrant [ 'Set-Cookie' => sprintf( 'oauth_authorize_request=%s; Expires=%s', - KeyCrypt::encrypt( + urlencode(KeyCrypt::encrypt( json_encode([ - 'user_id' => $userId, - 'client_is_authorized' => null, + 'user_id' => $userId, ]), $this->pathToPrivateKey - ), + )), (new \DateTime())->add(new \DateInterval('PT5M'))->format('D, d M Y H:i:s e') ), ] @@ -308,8 +313,7 @@ class AuthCodeGrant extends AbstractGrant { return ( ( - strtoupper($request->getMethod()) === 'GET' - && isset($request->getQueryParams()['response_type']) + isset($request->getQueryParams()['response_type']) && $request->getQueryParams()['response_type'] === 'code' && isset($request->getQueryParams()['client_id']) ) || (parent::canRespondToRequest($request)) From d95958bae4f296c1e3f4a1ae0877f7f8a1338b9b Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 14:28:24 +0000 Subject: [PATCH 220/444] Small fixes --- src/Grant/AuthCodeGrant.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 0a26d423..560b8ad1 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -74,6 +74,7 @@ class AuthCodeGrant extends AbstractGrant $this->pathToAuthorizeTemplate = ($pathToLoginTemplate === null) ? __DIR__ . '/../ResponseTypes/DefaultTemplates/authorize_client.php' : $this->pathToAuthorizeTemplate; + $this->refreshTokenTTL = new \DateInterval('P1M'); } @@ -234,7 +235,7 @@ class AuthCodeGrant extends AbstractGrant 'auth_code_id' => $authCode->getIdentifier(), 'scopes' => $authCode->getScopes(), 'user_id' => $authCode->getUserIdentifier(), - 'expire_time' => $this->authCodeTTL->format('U'), + 'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'), ] ), $this->pathToPrivateKey @@ -272,7 +273,7 @@ class AuthCodeGrant extends AbstractGrant // Validate the authorization code try { - $authCodePayload = json_decode(KeyCrypt::decrypt($encryptedAuthCode, $this->pathToPrivateKey)); + $authCodePayload = json_decode(KeyCrypt::decrypt($encryptedAuthCode, $this->pathToPublicKey)); if (time() > $authCodePayload->expire_time) { throw OAuthServerException::invalidRequest('code', 'Authorization code has expired'); } @@ -285,7 +286,7 @@ class AuthCodeGrant extends AbstractGrant throw OAuthServerException::invalidRequest('code', 'Authorization code was not issued to this client'); } } catch (\LogicException $e) { - throw OAuthServerException::invalidRequest('code'); + throw OAuthServerException::invalidRequest('code', null, 'Cannot decrypt the authorization code'); } // Issue and persist access + refresh tokens From 64d4c4a38ac8de2dd3d5b8d7c1a64c21907e0abe Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 15:44:34 +0000 Subject: [PATCH 221/444] Removed old tests --- tests/unit/AbstractServerTest.php | 26 - tests/unit/AuthorizationServerTest.php | 82 --- tests/unit/Entity/AbstractTokenEntityTest.php | 116 --- tests/unit/Entity/AccessTokenEntityTest.php | 59 -- tests/unit/Entity/AuthCodeEntityTest.php | 73 -- tests/unit/Entity/ClientEntityTest.php | 25 - tests/unit/Entity/RefreshTokenEntityTest.php | 94 --- tests/unit/Entity/ScopeEntityTest.php | 23 - tests/unit/Entity/SessionEntityTest.php | 154 ---- tests/unit/Exception/OAuthExceptionTest.php | 34 - tests/unit/Grant/AbstractGrantTest.php | 160 ---- tests/unit/Grant/AuthCodeGrantTest.php | 696 ------------------ .../unit/Grant/ClientCredentialsGrantTest.php | 251 ------- tests/unit/Grant/PasswordGrantTest.php | 479 ------------ tests/unit/Grant/RefreshTokenGrantTest.php | 501 ------------- tests/unit/ResourceServerTest.php | 226 ------ tests/unit/Storage/AbstractStorageTest.php | 23 - tests/unit/Stubs/StubAbstractGrant.php | 18 - tests/unit/Stubs/StubAbstractServer.php | 8 - tests/unit/Stubs/StubAbstractStorage.php | 8 - tests/unit/Stubs/StubAbstractTokenEntity.php | 18 - tests/unit/TokenType/MacTest.php | 165 ----- tests/unit/util/RedirectUriTest.php | 19 - tests/unit/util/SecureKeyTest.php | 35 - 24 files changed, 3293 deletions(-) delete mode 100644 tests/unit/AbstractServerTest.php delete mode 100644 tests/unit/AuthorizationServerTest.php delete mode 100644 tests/unit/Entity/AbstractTokenEntityTest.php delete mode 100644 tests/unit/Entity/AccessTokenEntityTest.php delete mode 100644 tests/unit/Entity/AuthCodeEntityTest.php delete mode 100644 tests/unit/Entity/ClientEntityTest.php delete mode 100644 tests/unit/Entity/RefreshTokenEntityTest.php delete mode 100644 tests/unit/Entity/ScopeEntityTest.php delete mode 100644 tests/unit/Entity/SessionEntityTest.php delete mode 100644 tests/unit/Exception/OAuthExceptionTest.php delete mode 100644 tests/unit/Grant/AbstractGrantTest.php delete mode 100644 tests/unit/Grant/AuthCodeGrantTest.php delete mode 100644 tests/unit/Grant/ClientCredentialsGrantTest.php delete mode 100644 tests/unit/Grant/PasswordGrantTest.php delete mode 100644 tests/unit/Grant/RefreshTokenGrantTest.php delete mode 100644 tests/unit/ResourceServerTest.php delete mode 100644 tests/unit/Storage/AbstractStorageTest.php delete mode 100644 tests/unit/Stubs/StubAbstractGrant.php delete mode 100644 tests/unit/Stubs/StubAbstractServer.php delete mode 100644 tests/unit/Stubs/StubAbstractStorage.php delete mode 100644 tests/unit/Stubs/StubAbstractTokenEntity.php delete mode 100644 tests/unit/TokenType/MacTest.php delete mode 100644 tests/unit/util/RedirectUriTest.php delete mode 100644 tests/unit/util/SecureKeyTest.php diff --git a/tests/unit/AbstractServerTest.php b/tests/unit/AbstractServerTest.php deleted file mode 100644 index 074f363c..00000000 --- a/tests/unit/AbstractServerTest.php +++ /dev/null @@ -1,26 +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)); - } -} From 2f914a0aa327a4c553d6941ec303fac02ad2303e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Fri, 12 Feb 2016 18:32:09 +0100 Subject: [PATCH 222/444] secure params access on authcode grant --- src/Grant/AuthCodeGrant.php | 59 +++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 560b8ad1..010bc482 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -307,17 +307,44 @@ class AuthCodeGrant extends AbstractGrant return $responseType; } + /** + * @inheritdoc + */ + public function respondToRequest( + ServerRequestInterface $request, + ResponseTypeInterface $responseType, + \DateInterval $accessTokenTTL + ) { + $requestParameters = (array) $request->getParsedBody(); + + if (array_key_exists('response_type', $requestParameters) + && $requestParameters['response_type'] === 'code' + && array_key_exists('client_id', $requestParameters) + ) { + return $this->respondToAuthorizationRequest($request); + } elseif (array_key_exists('grant_type', $requestParameters) + && $requestParameters['grant_type'] === $this->getIdentifier() + ) { + return $this->respondToAccessTokenRequest($request, $responseType, $accessTokenTTL); + } else { + throw OAuthServerException::serverError('respondToRequest() should not have been called'); + } + } + /** * @inheritdoc */ public function canRespondToRequest(ServerRequestInterface $request) { + $requestParameters = (array) $request->getParsedBody(); + return ( ( - isset($request->getQueryParams()['response_type']) - && $request->getQueryParams()['response_type'] === 'code' - && isset($request->getQueryParams()['client_id']) - ) || (parent::canRespondToRequest($request)) + array_key_exists('response_type', $requestParameters) + && $requestParameters['response_type'] === 'code' + && array_key_exists('client_id', $requestParameters) + ) + || parent::canRespondToRequest($request) ); } @@ -330,28 +357,4 @@ class AuthCodeGrant extends AbstractGrant { return 'authorization_code'; } - - /** - * @inheritdoc - */ - public function respondToRequest( - ServerRequestInterface $request, - ResponseTypeInterface $responseType, - \DateInterval $accessTokenTTL - ) { - if ( - isset($request->getQueryParams()['response_type']) - && $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'); - } - } } From 1f6bb40952e157d63db4a82ab7930a29992b7875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Fri, 12 Feb 2016 18:45:47 +0100 Subject: [PATCH 223/444] correcting param access mistake --- src/Grant/AuthCodeGrant.php | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 010bc482..f9e17ea2 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -315,16 +315,12 @@ class AuthCodeGrant extends AbstractGrant ResponseTypeInterface $responseType, \DateInterval $accessTokenTTL ) { - $requestParameters = (array) $request->getParsedBody(); - - if (array_key_exists('response_type', $requestParameters) - && $requestParameters['response_type'] === 'code' - && array_key_exists('client_id', $requestParameters) + if (array_key_exists('response_type', $request->getQueryParams()) + && $request->getQueryParams()['response_type'] === 'code' + && array_key_exists('client_id', $request->getQueryParams()) ) { return $this->respondToAuthorizationRequest($request); - } elseif (array_key_exists('grant_type', $requestParameters) - && $requestParameters['grant_type'] === $this->getIdentifier() - ) { + } elseif (parent::canRespondToRequest($request)) { return $this->respondToAccessTokenRequest($request, $responseType, $accessTokenTTL); } else { throw OAuthServerException::serverError('respondToRequest() should not have been called'); @@ -336,13 +332,11 @@ class AuthCodeGrant extends AbstractGrant */ public function canRespondToRequest(ServerRequestInterface $request) { - $requestParameters = (array) $request->getParsedBody(); - return ( ( - array_key_exists('response_type', $requestParameters) - && $requestParameters['response_type'] === 'code' - && array_key_exists('client_id', $requestParameters) + array_key_exists('response_type', $request->getQueryParams()) + && $request->getQueryParams()['response_type'] === 'code' + && isset($request->getQueryParams()['client_id']) ) || parent::canRespondToRequest($request) ); From 9a8b7ec898c91bf0f3d84ccaf98cd99579230f58 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:46:30 +0000 Subject: [PATCH 224/444] Removed old codecept tests --- codeception.yml | 10 --- .../AuthorizationCodeRequestEntity.php | 79 ------------------- tests/_output/.gitignore | 0 tests/_support/ApiHelper.php | 10 --- tests/api/ClientCredentialsCept.php | 17 ---- .../ClientCredentialsInvalidClientIdCept.php | 17 ---- ...ientCredentialsInvalidClientSecretCept.php | 17 ---- .../ClientCredentialsMissingClientIdCept.php | 15 ---- ...ientCredentialsMissingClientSecretCept.php | 16 ---- tests/api/_bootstrap.php | 2 - 10 files changed, 183 deletions(-) delete mode 100644 codeception.yml delete mode 100644 src/Entities/AuthorizationCodeRequestEntity.php delete mode 100644 tests/_output/.gitignore delete mode 100644 tests/_support/ApiHelper.php delete mode 100644 tests/api/ClientCredentialsCept.php delete mode 100644 tests/api/ClientCredentialsInvalidClientIdCept.php delete mode 100644 tests/api/ClientCredentialsInvalidClientSecretCept.php delete mode 100644 tests/api/ClientCredentialsMissingClientIdCept.php delete mode 100644 tests/api/ClientCredentialsMissingClientSecretCept.php delete mode 100644 tests/api/_bootstrap.php 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/src/Entities/AuthorizationCodeRequestEntity.php b/src/Entities/AuthorizationCodeRequestEntity.php deleted file mode 100644 index bd401b24..00000000 --- a/src/Entities/AuthorizationCodeRequestEntity.php +++ /dev/null @@ -1,79 +0,0 @@ -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/tests/_output/.gitignore b/tests/_output/.gitignore deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/_support/ApiHelper.php b/tests/_support/ApiHelper.php deleted file mode 100644 index 5fcdbe2c..00000000 --- a/tests/_support/ApiHelper.php +++ /dev/null @@ -1,10 +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 @@ - Date: Fri, 12 Feb 2016 17:46:42 +0000 Subject: [PATCH 225/444] Ignore build folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3b5992e5..6b74c032 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ phpunit.xml /tests/_output examples/public.key examples/private.key +build From 21e2ccd0fbd03670abc8e16b62d635dbfbcdca51 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:51:10 +0000 Subject: [PATCH 226/444] Removed codeception --- composer.json | 7 ++----- tests/_bootstrap.php | 2 -- tests/api.suite.yml | 8 -------- tests/unit/Bootstrap.php | 5 ----- 4 files changed, 2 insertions(+), 20 deletions(-) delete mode 100644 tests/_bootstrap.php delete mode 100644 tests/api.suite.yml delete mode 100644 tests/unit/Bootstrap.php diff --git a/composer.json b/composer.json index 55357050..a1bfda41 100644 --- a/composer.json +++ b/composer.json @@ -11,10 +11,7 @@ "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.*" }, "repositories": [ { @@ -57,7 +54,7 @@ }, "autoload-dev": { "psr-4": { - "LeagueTests\\": "tests/unit/" + "LeagueTests\\": "tests/" } }, "extra": { 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 @@ - wget http://getcomposer.org/composer.phar\n> php composer.phar install\n"); -} From fa3fb36ed8e8f2720c78cd083c62dbc771626143 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:51:16 +0000 Subject: [PATCH 227/444] Updated .travis.yml --- .travis.yml | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) 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 From 174ae490fcb28c30b57c5c76972090e7bddb56d9 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:51:28 +0000 Subject: [PATCH 228/444] Updated .gitignore / .gitattributes files --- .gitattributes | 3 +-- .gitignore | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) 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 6b74c032..897c80b1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ phpunit.xml .idea /examples/vendor -/tests/_output examples/public.key examples/private.key build From 29068dd84c3e035cd95d2ebf2ab4b9faf082c564 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:51:59 +0000 Subject: [PATCH 229/444] Removed responseWith method --- src/Grant/AbstractGrant.php | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 39fbf543..5722357f 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -35,13 +35,6 @@ abstract class AbstractGrant implements GrantTypeInterface const SCOPE_DELIMITER_STRING = ' '; - /** - * Grant responds with - * - * @var string - */ - protected $respondsWith = 'token'; - /** * @var ServerRequestInterface */ @@ -133,14 +126,6 @@ abstract class AbstractGrant implements GrantTypeInterface $this->refreshTokenTTL = $refreshTokenTTL; } - /** - * {@inheritdoc} - */ - public function respondsWith() - { - return $this->respondsWith; - } - /** * Validate the client * From 7f2fd69d0a6df721d30ac2e6fcf554ff14d2a79c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:52:37 +0000 Subject: [PATCH 230/444] Removed respondsWith from interface --- src/Grant/GrantTypeInterface.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 698639d9..1341c1fa 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -37,13 +37,6 @@ interface GrantTypeInterface extends EmitterAwareInterface */ public function getIdentifier(); - /** - * Details what the grant responds with - * - * @return string - */ - public function respondsWith(); - /** * Respond to an incoming request * From 08ad67e4011cac7b22288e73911fbd95ebdf6bbe Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:53:07 +0000 Subject: [PATCH 231/444] Updated phpunit tests --- phpunit.xml.dist | 6 +- tests/Bootstrap.php | 5 + tests/Grant/AbstractGrantTest.php | 289 ++++++++++++++++++++++++++++++ 3 files changed, 297 insertions(+), 3 deletions(-) create mode 100644 tests/Bootstrap.php create mode 100644 tests/Grant/AbstractGrantTest.php diff --git a/phpunit.xml.dist b/phpunit.xml.dist index f78850c1..43c0a02c 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,8 +1,8 @@ - + - ./tests/unit/ + ./tests/ @@ -11,7 +11,7 @@ - + diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php new file mode 100644 index 00000000..7f8cf458 --- /dev/null +++ b/tests/Bootstrap.php @@ -0,0 +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..30e0079c --- /dev/null +++ b/tests/Grant/AbstractGrantTest.php @@ -0,0 +1,289 @@ +getMock(ClientRepositoryInterface::class); + $accessTokenRepositoryMock = $this->getMock(AccessTokenRepositoryInterface::class); + $scopeRepositoryMock = $this->getMock(ScopeRepositoryInterface::class); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setClientRepository($clientRepositoryMock); + $grantMock->setAccessTokenRepository($accessTokenRepositoryMock); + $grantMock->setScopeRepository($scopeRepositoryMock); + $grantMock->setPathToPrivateKey('./private.key'); + $grantMock->setPathToPublicKey('./public.key'); + $grantMock->setEmitter(new Emitter()); + $grantMock->setRefreshTokenTTL(new \DateInterval('PT1H')); + } + + public function testValidateClient() + { + $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', + '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(); + $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 testValidateClientMissingRedirectUri() + { + $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', + 'client_secret' => 'bar', + ]); + + $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); + $validateClientMethod->setAccessible(true); + + $validateClientMethod->invoke($grantMock, $serverRequest, true, 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() + { + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setRefreshTokenTTL(new \DateInterval('PT1M')); + + $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() + { + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + + $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() + { + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + + $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()); + } +} From e20c529f3963ab55d2106c26e8fe112c2d7527a1 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:53:42 +0000 Subject: [PATCH 232/444] Added isExpired method to refresh token --- src/Entities/Interfaces/RefreshTokenEntityInterface.php | 6 ++++++ src/Entities/Traits/RefreshTokenTrait.php | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/src/Entities/Interfaces/RefreshTokenEntityInterface.php b/src/Entities/Interfaces/RefreshTokenEntityInterface.php index a095d4a1..5b382754 100644 --- a/src/Entities/Interfaces/RefreshTokenEntityInterface.php +++ b/src/Entities/Interfaces/RefreshTokenEntityInterface.php @@ -39,4 +39,10 @@ interface RefreshTokenEntityInterface * @return \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface */ public function getAccessToken(); + + /** + * Has the token expired? + * @return bool + */ + public function isExpired(); } diff --git a/src/Entities/Traits/RefreshTokenTrait.php b/src/Entities/Traits/RefreshTokenTrait.php index 0e0a3500..b0e2a247 100644 --- a/src/Entities/Traits/RefreshTokenTrait.php +++ b/src/Entities/Traits/RefreshTokenTrait.php @@ -50,4 +50,13 @@ trait RefreshTokenTrait { $this->expiryDateTime = $dateTime; } + + /** + * Has the token expired? + * @return bool + */ + public function isExpired() + { + return (new DateTime()) > $this->getExpiryDateTime(); + } } From 2bd45f2a6b10eb3865532786660b7a0dd020722b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Fri, 12 Feb 2016 19:06:31 +0100 Subject: [PATCH 233/444] unify examples --- examples/README.md | 11 ++- examples/public/auth_code.php | 46 +++++------ examples/public/client_credentials.php | 37 +++++---- ...ware_authentication.php => middleware.php} | 52 ++++++++++--- examples/public/password.php | 32 ++++---- examples/public/refresh_token.php | 76 ++++++++++--------- .../{protected_api.php => secured_route.php} | 36 +++++---- 7 files changed, 169 insertions(+), 121 deletions(-) rename examples/public/{middleware_authentication.php => middleware.php} (52%) rename examples/public/{protected_api.php => secured_route.php} (61%) diff --git a/examples/README.md b/examples/README.md index e4a30a73..35fdc516 100644 --- a/examples/README.md +++ b/examples/README.md @@ -16,10 +16,10 @@ Send the following cURL request: curl -X "POST" "http://localhost:4444/client_credentials.php/access_token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -H "Accept: 1.0" \ + --data-urlencode "grant_type=client_credentials" \ --data-urlencode "client_id=myawesomeapp" \ - --data-urlencode "scope=basic email" \ --data-urlencode "client_secret=abc123" \ - --data-urlencode "grant_type=client_credentials" + --data-urlencode "scope=basic email" ``` ## Testing the password grant example @@ -30,12 +30,12 @@ Send the following cURL request: curl -X "POST" "http://localhost:4444/password.php/access_token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -H "Accept: 1.0" \ + --data-urlencode "grant_type=password" \ --data-urlencode "client_id=myawesomeapp" \ - --data-urlencode "scope=basic email" \ + --data-urlencode "client_secret=abc123" \ --data-urlencode "username=alex" \ --data-urlencode "password=whisky" \ - --data-urlencode "client_secret=abc123" \ - --data-urlencode "grant_type=password" + --data-urlencode "scope=basic email" ``` ## Testing the refresh token grant example @@ -51,4 +51,3 @@ curl -X "POST" "http://localhost:4444/refresh_token.php/access_token" \ --data-urlencode "client_secret=abc123" \ --data-urlencode "refresh_token={{REFRESH_TOKEN}}" ``` - diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index 761f7ae3..357fc626 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -3,31 +3,31 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\AuthCodeRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; use OAuth2ServerExamples\Repositories\UserRepository; - +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; use Slim\App; -use Slim\Http\Request; -use Slim\Http\Response; +use Zend\Diactoros\Stream; include(__DIR__ . '/../vendor/autoload.php'); -// App $app = new App([ + 'settings' => [ + 'displayErrorDetails' => true, + ], Server::class => function () { - // Init our repositories $clientRepository = new ClientRepository(); $scopeRepository = new ScopeRepository(); $accessTokenRepository = new AccessTokenRepository(); - $userRepository = new UserRepository(); - $refreshTokenRepository = new RefreshTokenRepository(); $authCodeRepository = new AuthCodeRepository(); + $refreshTokenRepository = new RefreshTokenRepository(); + $userRepository = new UserRepository(); $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; @@ -41,7 +41,7 @@ $app = new App([ $publicKeyPath ); - // Enable the password grant on the server with a token TTL of 1 hour + // Enable the authentication code grant on the server with a token TTL of 1 hour $server->enableGrantType( new AuthCodeGrant( $authCodeRepository, @@ -56,27 +56,19 @@ $app = new App([ }, ]); -$app->any('/authorize', function (Request $request, Response $response) { - /** @var Server $server */ - $server = $this->get(Server::class); - try { - return $server->respondToRequest($request, $response); - } catch (OAuthServerException $e) { - return $e->generateHttpResponse($response); - } catch (\Exception $e) { - return $response->withStatus(500)->write($e->getMessage()); - } -}); +$app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { + /* @var \League\OAuth2\Server\Server $server */ + $server = $app->getContainer()->get(Server::class); -$app->post('/access_token', function (Request $request, Response $response) { - /** @var Server $server */ - $server = $this->get(Server::class); try { return $server->respondToRequest($request, $response); - } catch (OAuthServerException $e) { - return $e->generateHttpResponse($response); - } catch (\Exception $e) { - return $response->withStatus(500)->write($e->getMessage()); + } 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); } }); diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index 684e3003..b6a1600a 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -3,25 +3,25 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; - +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; use Slim\App; -use Slim\Http\Request; -use Slim\Http\Response; +use Zend\Diactoros\Stream; include(__DIR__ . '/../vendor/autoload.php'); -// App $app = new App([ + 'settings' => [ + 'displayErrorDetails' => true, + ], Server::class => function () { - // Init our repositories $clientRepository = new ClientRepository(); - $scopeRepository = new ScopeRepository(); $accessTokenRepository = new AccessTokenRepository(); + $scopeRepository = new ScopeRepository(); $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; @@ -36,21 +36,28 @@ $app = new App([ ); // Enable the client credentials grant on the server with a token TTL of 1 hour - $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1H')); + $server->enableGrantType( + new ClientCredentialsGrant(), + new \DateInterval('PT1H') + ); return $server; } ]); -$app->post('/access_token', function (Request $request, Response $response) { - /** @var Server $server */ - $server = $this->get(Server::class); +$app->post('/access_token', 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 $e) { - return $e->generateHttpResponse($response); - } catch (\Exception $e) { - return $response->withStatus(500)->write($e->getMessage()); + } 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); } }); diff --git a/examples/public/middleware_authentication.php b/examples/public/middleware.php similarity index 52% rename from examples/public/middleware_authentication.php rename to examples/public/middleware.php index d928e19d..3ace6072 100644 --- a/examples/public/middleware_authentication.php +++ b/examples/public/middleware.php @@ -1,33 +1,35 @@ [ 'displayErrorDetails' => true, ], Server::class => function () { - // Init our repositories $clientRepository = new ClientRepository(); $accessTokenRepository = new AccessTokenRepository(); $scopeRepository = new ScopeRepository(); - $userRepository = new UserRepository(); + $authCodeRepository = new AuthCodeRepository(); $refreshTokenRepository = new RefreshTokenRepository(); + $userRepository = new UserRepository(); $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; @@ -41,21 +43,53 @@ $app = new App([ $publicKeyPath ); - // Enable the grants + // Enable the authentication code grant on the server with a token TTL of 1 hour $server->enableGrantType( - new PasswordGrant($userRepository, $refreshTokenRepository), + new AuthCodeGrant( + $authCodeRepository, + $refreshTokenRepository, + $userRepository, + new \DateInterval('PT10M') + ), new \DateInterval('PT1H') ); + + // Enable the refresh token grant on the server with a token TTL of 1 month $server->enableGrantType( new RefreshTokenGrant($refreshTokenRepository), - new \DateInterval('PT1H') + new \DateInterval('PT1M') ); return $server; } ]); +// Access token issuer $app->post('/access_token', function () { })->add(new AuthenticationServerMiddleware($app->getContainer()->get(Server::class))); +// Secured API +$app->group('/api', function() { + $this->get('/user', function (ServerRequestInterface $request, ResponseInterface $response) { + $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 = new Stream('php://temp', 'r+'); + $body->write(json_encode($params)); + + return $response->withBody($body); + }); +})->add(new ResourceServerMiddleware($app->getContainer()->get(Server::class))); + $app->run(); diff --git a/examples/public/password.php b/examples/public/password.php index 036d1b4f..72992536 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -3,27 +3,27 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; use OAuth2ServerExamples\Repositories\UserRepository; - +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; use Slim\App; -use Slim\Http\Request; -use Slim\Http\Response; +use Zend\Diactoros\Stream; include(__DIR__ . '/../vendor/autoload.php'); -// App $app = new App([ + 'settings' => [ + 'displayErrorDetails' => true, + ], Server::class => function () { - // Init our repositories $clientRepository = new ClientRepository(); - $scopeRepository = new ScopeRepository(); $accessTokenRepository = new AccessTokenRepository(); + $scopeRepository = new ScopeRepository(); $userRepository = new UserRepository(); $refreshTokenRepository = new RefreshTokenRepository(); @@ -49,15 +49,19 @@ $app = new App([ } ]); -$app->post('/access_token', function (Request $request, Response $response) { - /** @var Server $server */ - $server = $this->get(Server::class); +$app->post('/access_token', 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 $e) { - return $e->generateHttpResponse($response); - } catch (\Exception $e) { - return $response->withStatus(500)->write($e->getMessage()); + } 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); } }); diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index ad9bf0cb..041131b5 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -3,57 +3,63 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; - +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; use Slim\App; -use Slim\Http\Request; -use Slim\Http\Response; +use Zend\Diactoros\Stream; include(__DIR__ . '/../vendor/autoload.php'); +$app = new App([ + 'settings' => [ + 'displayErrorDetails' => true, + ], + Server::class => function () { + // Init our repositories + $clientRepository = new ClientRepository(); + $accessTokenRepository = new AccessTokenRepository(); + $scopeRepository = new ScopeRepository(); + $refreshTokenRepository = new RefreshTokenRepository(); + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; -// App -$app = new App([Server::class => function () { - // Init our repositories - $clientRepository = new ClientRepository(); - $scopeRepository = new ScopeRepository(); - $accessTokenRepository = new AccessTokenRepository(); - $refreshTokenRepository = new RefreshTokenRepository(); + // Setup the authorization server + $server = new Server( + $clientRepository, + $accessTokenRepository, + $scopeRepository, + $privateKeyPath, + $publicKeyPath + ); - $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + // Enable the refresh token grant on the server with a token TTL of 1 hour + $server->enableGrantType( + new RefreshTokenGrant($refreshTokenRepository), + new \DateInterval('PT1H') + ); - // Setup the authorization server - $server = new Server( - $clientRepository, - $accessTokenRepository, - $scopeRepository, - $privateKeyPath, - $publicKeyPath - ); + return $server; + } +]); - // Enable the refresh token grant on the server - $server->enableGrantType(new RefreshTokenGrant($refreshTokenRepository), new \DateInterval('PT1H')); +$app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { + /* @var \League\OAuth2\Server\Server $server */ + $server = $app->getContainer()->get(Server::class); - return $server; -}]); - -$app->post('/access_token', function (Request $request, Response $response) { - /** @var Server $server */ - $server = $this->get(Server::class); try { return $server->respondToRequest($request, $response); - } catch (OAuthServerException $e) { - return $e->generateHttpResponse($response); - } catch (\Exception $e) { - return $response->withStatus(500)->write( - sprintf('

%s

%s

', get_class($e), $e->getMessage()) - ); + } 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); } }); diff --git a/examples/public/protected_api.php b/examples/public/secured_route.php similarity index 61% rename from examples/public/protected_api.php rename to examples/public/secured_route.php index f7362d63..c98a8313 100644 --- a/examples/public/protected_api.php +++ b/examples/public/secured_route.php @@ -1,48 +1,54 @@ [ 'displayErrorDetails' => true, ], Server::class => function () { - // Init our repositories $clientRepository = new ClientRepository(); - $scopeRepository = new ScopeRepository(); $accessTokenRepository = new AccessTokenRepository(); + $scopeRepository = new ScopeRepository(); $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server - $server = new Server( + return new Server( $clientRepository, $accessTokenRepository, $scopeRepository, $privateKeyPath, $publicKeyPath ); - - return $server; } ]); -$app->add(new ResourceServerMiddleware($app->getContainer()->get(Server::class))); -$app->post('/api/example', function (Request $request, Response $response) { +$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 = []; @@ -58,9 +64,9 @@ $app->post('/api/example', function (Request $request, Response $response) { $params['email'] = 'alex@example.com'; } - $response->getBody()->write(json_encode($params)); + $body->write(json_encode($params)); - return $response; + return $response->withBody($body); }); $app->run(); From de13e14cdd50dc0a92d3d5c74fd51e89300a12d6 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 18:08:13 +0000 Subject: [PATCH 234/444] Added test/Utils --- tests/Utils/KeyCryptTest.php | 34 ++++++++++++++++++++++++++++++++++ tests/Utils/SecureKeyTest.php | 13 +++++++++++++ tests/Utils/private.key | 15 +++++++++++++++ tests/Utils/public.key | 6 ++++++ 4 files changed, 68 insertions(+) create mode 100644 tests/Utils/KeyCryptTest.php create mode 100644 tests/Utils/SecureKeyTest.php create mode 100644 tests/Utils/private.key create mode 100644 tests/Utils/public.key diff --git a/tests/Utils/KeyCryptTest.php b/tests/Utils/KeyCryptTest.php new file mode 100644 index 00000000..9720dbd3 --- /dev/null +++ b/tests/Utils/KeyCryptTest.php @@ -0,0 +1,34 @@ +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/SecureKeyTest.php b/tests/Utils/SecureKeyTest.php new file mode 100644 index 00000000..aebdb755 --- /dev/null +++ b/tests/Utils/SecureKeyTest.php @@ -0,0 +1,13 @@ +assertTrue(is_string(SecureKey::generate())); + } +} 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----- From 335630f150f87b43e562484daf36c3510041038a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 18:08:27 +0000 Subject: [PATCH 235/444] Added code coverage ignore docblocks --- src/Utils/KeyCrypt.php | 4 ++++ src/Utils/SecureKey.php | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/Utils/KeyCrypt.php b/src/Utils/KeyCrypt.php index 634cd80b..8b62c10a 100644 --- a/src/Utils/KeyCrypt.php +++ b/src/Utils/KeyCrypt.php @@ -36,7 +36,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; } @@ -72,7 +74,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 index f5078bbf..ee5a85ea 100644 --- a/src/Utils/SecureKey.php +++ b/src/Utils/SecureKey.php @@ -31,6 +31,7 @@ class SecureKey { try { $string = random_bytes($len); + // @codeCoverageIgnoreStart } catch (\TypeError $e) { // Well, it's an integer, so this IS unexpected. throw OAuthServerException::serverError("An unexpected error has occurred"); @@ -41,6 +42,7 @@ class SecureKey // If you get this message, the CSPRNG failed hard. throw OAuthServerException::serverError("Could not generate a random string. Is our OS secure?"); } + // @codeCoverageIgnoreEnd return bin2hex($string); } From 186853390a3f3b43e9000701e8da2a0ce85737e3 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 18:08:35 +0000 Subject: [PATCH 236/444] Updated phpunit.xml.dist --- phpunit.xml.dist | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 43c0a02c..943b7857 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,17 +1,23 @@ - - - - ./tests/ - - - - - src - - - - - - + + + + ./tests/ + + + + + src + + src/ResponseTypes/DefaultTemplates + + + + + + + From 099c9ce41bccddac4bfc84dd240326ab707771da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Sat, 13 Feb 2016 14:07:09 +0100 Subject: [PATCH 237/444] move token identifier generation --- src/Grant/AbstractGrant.php | 29 +++++++++++++++++++---- src/Utils/SecureKey.php | 47 ------------------------------------- 2 files changed, 25 insertions(+), 51 deletions(-) delete mode 100644 src/Utils/SecureKey.php diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 39fbf543..c18058f8 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -23,7 +23,6 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; -use League\OAuth2\Server\Utils\SecureKey; use Psr\Http\Message\ServerRequestInterface; /** @@ -310,7 +309,7 @@ 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); @@ -342,7 +341,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); @@ -363,13 +362,35 @@ 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); return $refreshToken; } + /** + * Generate a new unique identifier + * + * @param int $length + * + * @return string + * + * @throws \League\OAuth2\Server\Exception\OAuthServerException + */ + protected function generateUniqueIdentifier($length = 40) + { + try { + return bin2hex(random_bytes($length)); + } 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) { + throw OAuthServerException::serverError('Could not generate a random string'); + } + } + /** * @inheritdoc */ 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); - } -} From dbcaaa1f359899d8bab48847130cd184002a3153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Sat, 13 Feb 2016 14:38:23 +0100 Subject: [PATCH 238/444] rename determineAccessTokenInHeader --- src/Middleware/ResourceServerMiddleware.php | 2 +- src/ResponseTypes/AbstractResponseType.php | 2 +- src/ResponseTypes/BearerTokenResponse.php | 4 ++-- src/ResponseTypes/MAC.php | 2 +- src/ResponseTypes/ResponseTypeInterface.php | 2 +- src/Server.php | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Middleware/ResourceServerMiddleware.php b/src/Middleware/ResourceServerMiddleware.php index 0f0b20ae..3b92537b 100644 --- a/src/Middleware/ResourceServerMiddleware.php +++ b/src/Middleware/ResourceServerMiddleware.php @@ -35,7 +35,7 @@ class ResourceServerMiddleware public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { try { - $request = $this->server->validateRequest($request); + $request = $this->server->validateAuthenticatedRequest($request); } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); } catch (\Exception $exception) { diff --git a/src/ResponseTypes/AbstractResponseType.php b/src/ResponseTypes/AbstractResponseType.php index 9605a463..58916664 100644 --- a/src/ResponseTypes/AbstractResponseType.php +++ b/src/ResponseTypes/AbstractResponseType.php @@ -78,7 +78,7 @@ abstract class AbstractResponseType implements ResponseTypeInterface /** * {@inheritdoc} */ - public function determineAccessTokenInHeader(ServerRequestInterface $request) + public function validateAccessToken(ServerRequestInterface $request) { if ($request->hasHeader('authorization') === false) { throw OAuthServerException::accessDenied('Missing "Authorization" header'); diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index d1b88218..1ab2a5d6 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -79,9 +79,9 @@ class BearerTokenResponse extends AbstractResponseType /** * {@inheritdoc} */ - public function determineAccessTokenInHeader(ServerRequestInterface $request) + public function validateAccessToken(ServerRequestInterface $request) { - $request = parent::determineAccessTokenInHeader($request); + $request = parent::validateAccessToken($request); $header = $request->getHeader('authorization'); $jwt = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header[0])); diff --git a/src/ResponseTypes/MAC.php b/src/ResponseTypes/MAC.php index 48c2274f..ee6aa62e 100644 --- a/src/ResponseTypes/MAC.php +++ b/src/ResponseTypes/MAC.php @@ -42,7 +42,7 @@ class MAC extends AbstractTokenType implements TokenTypeInterface /** * {@inheritdoc} */ - public function determineAccessTokenInHeader(Request $request) + public function validateAccessToken(Request $request) { if ($request->headers->has('Authorization') === false) { return; diff --git a/src/ResponseTypes/ResponseTypeInterface.php b/src/ResponseTypes/ResponseTypeInterface.php index 6524f049..1a7155cc 100644 --- a/src/ResponseTypes/ResponseTypeInterface.php +++ b/src/ResponseTypes/ResponseTypeInterface.php @@ -36,7 +36,7 @@ interface ResponseTypeInterface * * @return ServerRequestInterface */ - public function determineAccessTokenInHeader(ServerRequestInterface $request); + public function validateAccessToken(ServerRequestInterface $request); /** * @param ResponseInterface $response diff --git a/src/Server.php b/src/Server.php index 4e7799d3..45f9213f 100644 --- a/src/Server.php +++ b/src/Server.php @@ -157,9 +157,9 @@ class Server implements EmitterAwareInterface * * @throws \League\OAuth2\Server\Exception\OAuthServerException */ - public function validateRequest(ServerRequestInterface $request) + public function validateAuthenticatedRequest(ServerRequestInterface $request) { - return $this->getResponseType()->determineAccessTokenInHeader($request); + return $this->getResponseType()->validateAccessToken($request); } /** From fc53d636f5d434218941b4d0fafbd06bd6b33dbb Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:47:06 +0000 Subject: [PATCH 239/444] Updated getClientEntity now just requires the client ID and the grant type --- src/Repositories/ClientRepositoryInterface.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Repositories/ClientRepositoryInterface.php b/src/Repositories/ClientRepositoryInterface.php index 3bec9452..eb88a6cd 100644 --- a/src/Repositories/ClientRepositoryInterface.php +++ b/src/Repositories/ClientRepositoryInterface.php @@ -19,12 +19,10 @@ interface ClientRepositoryInterface extends RepositoryInterface /** * 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 $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); } From 0d8cb0d06f7811a3572ce595bb53d74c8defb665 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:47:30 +0000 Subject: [PATCH 240/444] Fixes for RefreshTokenGrant --- src/Grant/RefreshTokenGrant.php | 11 +++- tests/Grant/RefreshTokenGrantTest.php | 82 +++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 tests/Grant/RefreshTokenGrantTest.php diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index b43792ee..665d60a4 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -12,6 +12,7 @@ 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; @@ -47,13 +48,17 @@ 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 diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php new file mode 100644 index 00000000..dc28b51f --- /dev/null +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -0,0 +1,82 @@ +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(); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $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')); + + $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); + $this->assertTrue($responseType->getRefreshToken() instanceof RefreshTokenEntityInterface); + } +} From fb77a78fb37c9e3af8ad47b0ee567b368887a9c4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:47:52 +0000 Subject: [PATCH 241/444] Added Password Grant test --- tests/Grant/PasswordGrantTest.php | 64 +++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 tests/Grant/PasswordGrantTest.php diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php new file mode 100644 index 00000000..8dd7a48d --- /dev/null +++ b/tests/Grant/PasswordGrantTest.php @@ -0,0 +1,64 @@ +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(); + + $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); + } +} From e808528cc854a436b5523ef854a05cb78f412c97 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:47:59 +0000 Subject: [PATCH 242/444] Added test stubs --- tests/Stubs/StubResponseType.php | 60 ++++++++++++++++++++++++++++++++ tests/Stubs/UserEntity.php | 13 +++++++ 2 files changed, 73 insertions(+) create mode 100644 tests/Stubs/StubResponseType.php create mode 100644 tests/Stubs/UserEntity.php diff --git a/tests/Stubs/StubResponseType.php b/tests/Stubs/StubResponseType.php new file mode 100644 index 00000000..4d40b089 --- /dev/null +++ b/tests/Stubs/StubResponseType.php @@ -0,0 +1,60 @@ +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) + { + // TODO: Implement generateHttpResponse() method. + } +} \ No newline at end of file diff --git a/tests/Stubs/UserEntity.php b/tests/Stubs/UserEntity.php new file mode 100644 index 00000000..4c157df5 --- /dev/null +++ b/tests/Stubs/UserEntity.php @@ -0,0 +1,13 @@ + Date: Thu, 18 Feb 2016 10:48:12 +0000 Subject: [PATCH 243/444] Updated ClientEntityInterface with additional methods --- .../Interfaces/ClientEntityInterface.php | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/Entities/Interfaces/ClientEntityInterface.php b/src/Entities/Interfaces/ClientEntityInterface.php index c0d0e812..2761c214 100644 --- a/src/Entities/Interfaces/ClientEntityInterface.php +++ b/src/Entities/Interfaces/ClientEntityInterface.php @@ -11,6 +11,7 @@ interface ClientEntityInterface /** * Set the client's identifier + * * @param $identifier */ public function setIdentifier($identifier); @@ -23,7 +24,42 @@ interface ClientEntityInterface /** * Set the client's name + * * @param string $name */ public function setName($name); + + /** + * @param string $secret + */ + public function setSecret($secret); + + /** + * Validate the secret provided by the client + * + * @param string $submittedSecret + * + * @return boolean + */ + public function validateSecret($submittedSecret); + + /** + * Set the client's redirect uri + * + * @param string $redirectUri + */ + public function setRedirectUri($redirectUri); + + /** + * Returns the registered redirect URI + * + * @return string + */ + public function getRedirectUri(); + + /** + * Returns true if the client is capable of keeping it's secrets secret + * @return boolean + */ + public function canKeepASecret(); } From 7f67000d531758129ce77e7d5beacc4fd4872224 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:48:23 +0000 Subject: [PATCH 244/444] Provided implementation of new client entity methods --- src/Entities/Traits/ClientEntityTrait.php | 56 +++++++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/src/Entities/Traits/ClientEntityTrait.php b/src/Entities/Traits/ClientEntityTrait.php index 80e61b93..d7665fcf 100644 --- a/src/Entities/Traits/ClientEntityTrait.php +++ b/src/Entities/Traits/ClientEntityTrait.php @@ -9,8 +9,17 @@ trait ClientEntityTrait protected $name; /** - * Get the client's name - * @return string + * @var string + */ + protected $secret; + + /** + * @var string + */ + protected $redirectUri; + + /** + * @inheritdoc */ public function getName() { @@ -18,11 +27,50 @@ trait ClientEntityTrait } /** - * Set the client's name - * @param string $name + * @inheritdoc */ public function setName($name) { $this->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; + } } From 3b36ae9000328ccba408b20752021cfbc51e7a6d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:49:05 +0000 Subject: [PATCH 245/444] Rewrote validateClient method to progressively test client secret and redirect URI --- src/Grant/AbstractGrant.php | 41 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 5722357f..2139e6fa 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -130,17 +130,12 @@ abstract class AbstractGrant implements GrantTypeInterface * Validate the client * * @param \Psr\Http\Message\ServerRequestInterface $request - * @param bool $validateSecret - * @param bool $validateRedirectUri * * @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, @@ -150,30 +145,34 @@ abstract class AbstractGrant implements GrantTypeInterface throw OAuthServerException::invalidRequest('client_id', null, '`%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) { + + if ($client->canKeepASecret() && is_null($clientSecret)) { throw OAuthServerException::invalidRequest('client_secret', null, '`%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'); + if ($client->canKeepASecret() && $client->validateSecret($clientSecret) === false) { + $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); + throw OAuthServerException::invalidClient(); } - $client = $this->clientRepository->getClientEntity( - $clientId, - $clientSecret, - $redirectUri, - $this->getIdentifier() - ); - - if (!$client instanceof ClientEntityInterface) { - $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); - + // 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(); } From 73cd377c4bc127ffc17918aa90fa75859c8f81f2 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:49:13 +0000 Subject: [PATCH 246/444] Added client credentials grant test --- tests/Grant/ClientCredentialsGrantTest.php | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 tests/Grant/ClientCredentialsGrantTest.php diff --git a/tests/Grant/ClientCredentialsGrantTest.php b/tests/Grant/ClientCredentialsGrantTest.php new file mode 100644 index 00000000..52e51c9a --- /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); + } +} From 704e1145685070f778093e1111ccc77dcc77cef1 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:49:39 +0000 Subject: [PATCH 247/444] Updated AuthCodeGrant --- src/Grant/AuthCodeGrant.php | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 560b8ad1..cc0a1f81 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -89,26 +89,7 @@ class AuthCodeGrant extends AbstractGrant protected function respondToAuthorizationRequest( ServerRequestInterface $request ) { - $clientId = $this->getQueryStringParameter( - 'client_id', - $request, - $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'); - } - - $client = $this->clientRepository->getClientEntity( - $clientId, - null, - $redirectUri, - $this->getIdentifier() - ); + $client = $this->validateClient($request); if ($client instanceof ClientEntityInterface === false) { $this->emitter->emit(new Event('client.authentication.failed', $request)); @@ -116,7 +97,7 @@ class AuthCodeGrant extends AbstractGrant throw OAuthServerException::invalidClient(); } - $scopes = $this->validateScopes($request, $client, $redirectUri); + $scopes = $this->validateScopes($request, $client, $client->getRedirectUri()); $queryString = http_build_query($request->getQueryParams()); $postbackUri = new Uri( sprintf( @@ -168,8 +149,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), @@ -183,8 +165,9 @@ class AuthCodeGrant extends AbstractGrant // 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, @@ -212,7 +195,7 @@ class AuthCodeGrant extends AbstractGrant $stateParameter = $this->getQueryStringParameter('state', $request); - $redirectUri = new Uri($redirectUri); + $redirectUri = new Uri($client->getRedirectUri()); parse_str($redirectUri->getQuery(), $redirectPayload); if ($stateParameter !== null) { $redirectPayload['state'] = $stateParameter; @@ -263,6 +246,12 @@ class AuthCodeGrant extends AbstractGrant ResponseTypeInterface $responseType, DateInterval $accessTokenTTL ) { + // The redirect URI is required in this request + $redirectUri = $this->getQueryStringParameter('redirect_uri', $request, null); + if (is_null($redirectUri)) { + throw OAuthServerException::invalidRequest('redirect_uri', null, '`%s` parameter is missing'); + } + // Validate request $client = $this->validateClient($request); $encryptedAuthCode = $this->getRequestParameter('code', $request, null); From ad5b242d10b1718e4c312b6fcbb4cef27e86a45f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 11:36:20 +0000 Subject: [PATCH 248/444] Updated AbstractGrantTest --- tests/Grant/AbstractGrantTest.php | 105 ++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 14 deletions(-) diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 30e0079c..92acf384 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -10,7 +10,6 @@ use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Grant\AbstractGrant; -use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use Zend\Diactoros\ServerRequest; @@ -19,24 +18,45 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase { public function testGetSet() { - $clientRepositoryMock = $this->getMock(ClientRepositoryInterface::class); - $accessTokenRepositoryMock = $this->getMock(AccessTokenRepositoryInterface::class); - $scopeRepositoryMock = $this->getMock(ScopeRepositoryInterface::class); + /** @var AbstractGrant $grantMock */ + $grantMock = $this->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); - $grantMock->setAccessTokenRepository($accessTokenRepositoryMock); - $grantMock->setScopeRepository($scopeRepositoryMock); - $grantMock->setPathToPrivateKey('./private.key'); - $grantMock->setPathToPublicKey('./public.key'); - $grantMock->setEmitter(new Emitter()); - $grantMock->setRefreshTokenTTL(new \DateInterval('PT1H')); + + $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 testValidateClient() + 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); @@ -89,6 +109,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase public function testValidateClientMissingClientSecret() { $client = new ClientEntity(); + $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); @@ -112,11 +133,67 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase /** * @expectedException \League\OAuth2\Server\Exception\OAuthServerException */ - public function testValidateClientMissingRedirectUri() + 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() { $client = new ClientEntity(); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); - $clientRepositoryMock->method('getClientEntity')->willReturn($client); + $clientRepositoryMock->method('getClientEntity')->willReturn(null); /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); @@ -133,7 +210,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); $validateClientMethod->setAccessible(true); - $validateClientMethod->invoke($grantMock, $serverRequest, true, true); + $validateClientMethod->invoke($grantMock, $serverRequest, true); } public function testCanRespondToRequest() From 064eb85f4e7c697f2d565af710399317e81441d5 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 12:07:23 +0000 Subject: [PATCH 249/444] AbstractGrant now handles persisting tokens --- src/Grant/AbstractGrant.php | 51 ++++++++++++++++++++++++++++ src/Grant/AuthCodeGrant.php | 17 ++-------- src/Grant/ClientCredentialsGrant.php | 1 - src/Grant/PasswordGrant.php | 9 +---- src/Grant/RefreshTokenGrant.php | 13 +++---- 5 files changed, 59 insertions(+), 32 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 2139e6fa..142e930d 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -21,9 +21,12 @@ 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; /** @@ -55,6 +58,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 */ @@ -94,6 +107,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 */ @@ -126,6 +155,22 @@ abstract class AbstractGrant implements GrantTypeInterface $this->refreshTokenTTL = $refreshTokenTTL; } + /** + * @return AuthCodeRepositoryInterface + */ + protected function getAuthCodeRepository() + { + return $this->authCodeRepository; + } + + /** + * @return RefreshTokenRepositoryInterface + */ + protected function getRefreshTokenRepository() + { + return $this->refreshTokenRepository; + } + /** * Validate the client * @@ -303,6 +348,8 @@ abstract class AbstractGrant implements GrantTypeInterface $accessToken->addScope($scope); } + $this->accessTokenRepository->persistNewAccessToken($accessToken); + return $accessToken; } @@ -336,6 +383,8 @@ abstract class AbstractGrant implements GrantTypeInterface $authCode->addScope($scope); } + $this->authCodeRepository->persistNewAuthCode($authCode); + return $authCode; } @@ -351,6 +400,8 @@ abstract class AbstractGrant implements GrantTypeInterface $refreshToken->setExpiryDateTime((new \DateTime())->add($this->refreshTokenTTL)); $refreshToken->setAccessToken($accessToken); + $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); + return $refreshToken; } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index cc0a1f81..13b8a984 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -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,10 +39,6 @@ class AuthCodeGrant extends AbstractGrant */ private $pathToAuthorizeTemplate; - /** - * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface - */ - private $refreshTokenRepository; /** * @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository @@ -64,8 +56,8 @@ 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) @@ -209,7 +201,6 @@ class AuthCodeGrant extends AbstractGrant $redirectUri, $scopes ); - $this->authCodeRepository->persistNewAuthCode($authCode); $redirectPayload['code'] = KeyCrypt::encrypt( json_encode( @@ -267,7 +258,7 @@ 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'); } @@ -286,8 +277,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); diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index cf6ce268..f5881e12 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -33,7 +33,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); diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 00ffa149..0b30bfe2 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -29,11 +29,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,7 +38,7 @@ class PasswordGrant extends AbstractGrant RefreshTokenRepositoryInterface $refreshTokenRepository ) { $this->userRepository = $userRepository; - $this->refreshTokenRepository = $refreshTokenRepository; + $this->setRefreshTokenRepository($refreshTokenRepository); $this->refreshTokenTTL = new \DateInterval('P1M'); } @@ -64,8 +59,6 @@ class PasswordGrant extends AbstractGrant // 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); diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 665d60a4..adaa2306 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -24,17 +24,12 @@ use Psr\Http\Message\ServerRequestInterface; */ 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'); } @@ -73,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); @@ -125,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'); } From e8a01c3bcd3e5ff62bcd4db4e1ea09a910f3cd89 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 12:07:36 +0000 Subject: [PATCH 250/444] Fix for logic --- src/Entities/Traits/ClientEntityTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entities/Traits/ClientEntityTrait.php b/src/Entities/Traits/ClientEntityTrait.php index d7665fcf..bac3ccda 100644 --- a/src/Entities/Traits/ClientEntityTrait.php +++ b/src/Entities/Traits/ClientEntityTrait.php @@ -39,7 +39,7 @@ trait ClientEntityTrait */ public function canKeepASecret() { - return $this->secret === null; + return $this->secret !== null; } /** From 13baa0bb26ff8a70b49ea655d21b26f0e6d2b3de Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 12:07:50 +0000 Subject: [PATCH 251/444] Updated tests --- tests/Grant/AbstractGrantTest.php | 13 ++++++- tests/Grant/PasswordGrantTest.php | 1 + tests/Grant/RefreshTokenGrantTest.php | 1 + tests/ServerTest.php | 56 +++++++++++++++++++++++++++ tests/Stubs/StubResponseType.php | 3 +- 5 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 tests/ServerTest.php diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 92acf384..cb19bf52 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -12,6 +12,9 @@ use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Grant\AbstractGrant; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use Zend\Diactoros\ServerRequest; class AbstractGrantTest extends \PHPUnit_Framework_TestCase @@ -191,7 +194,6 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase */ public function testValidateClientBadClient() { - $client = new ClientEntity(); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn(null); @@ -228,9 +230,12 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase 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'); @@ -246,8 +251,11 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase 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'); @@ -267,8 +275,11 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase 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'); diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php index 8dd7a48d..c81e4c61 100644 --- a/tests/Grant/PasswordGrantTest.php +++ b/tests/Grant/PasswordGrantTest.php @@ -40,6 +40,7 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); $grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index dc28b51f..8bfe71c9 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -43,6 +43,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); diff --git a/tests/ServerTest.php b/tests/ServerTest.php new file mode 100644 index 00000000..9a85c351 --- /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 index 4d40b089..d62daf9b 100644 --- a/tests/Stubs/StubResponseType.php +++ b/tests/Stubs/StubResponseType.php @@ -7,6 +7,7 @@ use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\ResponseTypes\AbstractResponseType; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Zend\Diactoros\Response; class StubResponseType extends AbstractResponseType { @@ -55,6 +56,6 @@ class StubResponseType extends AbstractResponseType */ public function generateHttpResponse(ResponseInterface $response) { - // TODO: Implement generateHttpResponse() method. + return new Response(); } } \ No newline at end of file From 65bcc97fc3cf2fad0857ef8ee3ecbbd6a1e3a2d5 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 19 Feb 2016 23:08:32 +0000 Subject: [PATCH 252/444] Create .styleci.yml --- .styleci.yml | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .styleci.yml 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 From a2460886f63ed3c0d5961bf06bbbbff1be4adca3 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 19 Feb 2016 18:09:39 -0500 Subject: [PATCH 253/444] Applied fixes from StyleCI --- examples/public/auth_code.php | 8 ++-- examples/public/client_credentials.php | 10 ++--- examples/public/middleware_authentication.php | 10 ++--- examples/public/password.php | 10 ++--- examples/public/protected_api.php | 12 +++--- examples/public/refresh_token.php | 10 ++--- examples/src/Entities/UserEntity.php | 5 ++- .../Repositories/AccessTokenRepository.php | 7 ++-- .../src/Repositories/AuthCodeRepository.php | 9 ++-- .../src/Repositories/ClientRepository.php | 13 +++--- .../Repositories/RefreshTokenRepository.php | 7 ++-- examples/src/Repositories/ScopeRepository.php | 11 ++--- examples/src/Repositories/UserRepository.php | 5 ++- src/Entities/AccessTokenEntity.php | 1 + src/Entities/AuthCodeEntity.php | 4 +- src/Entities/ClientEntity.php | 4 +- .../Interfaces/AccessTokenEntityInterface.php | 2 +- .../Interfaces/ClientEntityInterface.php | 24 ++++++----- .../RefreshTokenEntityInterface.php | 19 ++++++--- .../Interfaces/ScopeEntityInterface.php | 7 +++- src/Entities/Interfaces/TokenInterface.php | 37 ++++++++++------ .../Interfaces/UserEntityInterface.php | 3 +- src/Entities/RefreshTokenEntity.php | 4 +- src/Entities/ScopeEntity.php | 6 +-- src/Entities/Traits/ClientEntityTrait.php | 15 +++---- src/Entities/Traits/EntityTrait.php | 1 + src/Entities/Traits/RefreshTokenTrait.php | 11 +++-- src/Entities/Traits/TokenEntityTrait.php | 26 +++++++----- src/Exception/OAuthServerException.php | 41 +++++++++--------- src/Grant/AbstractGrant.php | 42 +++++++++---------- src/Grant/AuthCodeGrant.php | 31 +++++++------- src/Grant/ClientCredentialsGrant.php | 11 +++-- src/Grant/GrantTypeInterface.php | 25 ++++++----- src/Grant/PasswordGrant.php | 17 ++++---- src/Grant/RefreshTokenGrant.php | 24 +++++------ .../AccessTokenRepositoryInterface.php | 13 +++--- .../AuthCodeRepositoryInterface.php | 13 +++--- .../ClientRepositoryInterface.php | 13 +++--- src/Repositories/MacTokenInterface.php | 13 +++--- .../RefreshTokenRepositoryInterface.php | 13 +++--- src/Repositories/RepositoryInterface.php | 7 ++-- src/Repositories/ScopeRepositoryInterface.php | 9 ++-- src/Repositories/UserRepositoryInterface.php | 2 +- src/ResponseTypes/AbstractResponseType.php | 5 +-- src/ResponseTypes/BearerTokenResponse.php | 7 ++-- src/ResponseTypes/MAC.php | 25 +++++------ src/ResponseTypes/ResponseTypeInterface.php | 7 ++-- src/Server.php | 17 ++++---- src/Utils/KeyCrypt.php | 9 ++-- src/Utils/SecureKey.php | 21 +++++----- tests/Bootstrap.php | 2 +- tests/Grant/AbstractGrantTest.php | 10 ++--- tests/Grant/ClientCredentialsGrantTest.php | 2 +- tests/Grant/RefreshTokenGrantTest.php | 2 - tests/ServerTest.php | 6 +-- tests/Stubs/StubResponseType.php | 6 ++- tests/Stubs/UserEntity.php | 2 +- 57 files changed, 346 insertions(+), 330 deletions(-) diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index 761f7ae3..d15a1561 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -3,19 +3,17 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\AuthCodeRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; use OAuth2ServerExamples\Repositories\UserRepository; - use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include(__DIR__ . '/../vendor/autoload.php'); +include __DIR__.'/../vendor/autoload.php'; // App $app = new App([ @@ -29,8 +27,8 @@ $app = new App([ $refreshTokenRepository = new RefreshTokenRepository(); $authCodeRepository = new AuthCodeRepository(); - $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + $privateKeyPath = 'file://'.__DIR__.'/../private.key'; + $publicKeyPath = 'file://'.__DIR__.'/../public.key'; // Setup the authorization server $server = new Server( diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index 684e3003..48ee0b6f 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -3,16 +3,14 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; - use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include(__DIR__ . '/../vendor/autoload.php'); +include __DIR__.'/../vendor/autoload.php'; // App $app = new App([ @@ -23,8 +21,8 @@ $app = new App([ $scopeRepository = new ScopeRepository(); $accessTokenRepository = new AccessTokenRepository(); - $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + $privateKeyPath = 'file://'.__DIR__.'/../private.key'; + $publicKeyPath = 'file://'.__DIR__.'/../public.key'; // Setup the authorization server $server = new Server( @@ -39,7 +37,7 @@ $app = new App([ $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1H')); return $server; - } + }, ]); $app->post('/access_token', function (Request $request, Response $response) { diff --git a/examples/public/middleware_authentication.php b/examples/public/middleware_authentication.php index d928e19d..27f03c5a 100644 --- a/examples/public/middleware_authentication.php +++ b/examples/public/middleware_authentication.php @@ -4,16 +4,14 @@ use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Middleware\AuthenticationServerMiddleware; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; use OAuth2ServerExamples\Repositories\UserRepository; - use Slim\App; -include(__DIR__ . '/../vendor/autoload.php'); +include __DIR__.'/../vendor/autoload.php'; // App $app = new App([ @@ -29,8 +27,8 @@ $app = new App([ $userRepository = new UserRepository(); $refreshTokenRepository = new RefreshTokenRepository(); - $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + $privateKeyPath = 'file://'.__DIR__.'/../private.key'; + $publicKeyPath = 'file://'.__DIR__.'/../public.key'; // Setup the authorization server $server = new Server( @@ -52,7 +50,7 @@ $app = new App([ ); return $server; - } + }, ]); $app->post('/access_token', function () { diff --git a/examples/public/password.php b/examples/public/password.php index 036d1b4f..4c0548b4 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -3,18 +3,16 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; use OAuth2ServerExamples\Repositories\UserRepository; - use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include(__DIR__ . '/../vendor/autoload.php'); +include __DIR__.'/../vendor/autoload.php'; // App $app = new App([ @@ -27,8 +25,8 @@ $app = new App([ $userRepository = new UserRepository(); $refreshTokenRepository = new RefreshTokenRepository(); - $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + $privateKeyPath = 'file://'.__DIR__.'/../private.key'; + $publicKeyPath = 'file://'.__DIR__.'/../public.key'; // Setup the authorization server $server = new Server( @@ -46,7 +44,7 @@ $app = new App([ ); return $server; - } + }, ]); $app->post('/access_token', function (Request $request, Response $response) { diff --git a/examples/public/protected_api.php b/examples/public/protected_api.php index f7362d63..35b829ae 100644 --- a/examples/public/protected_api.php +++ b/examples/public/protected_api.php @@ -2,16 +2,14 @@ use League\OAuth2\Server\Middleware\ResourceServerMiddleware; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; - use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include(__DIR__ . '/../vendor/autoload.php'); +include __DIR__.'/../vendor/autoload.php'; // App $app = new App([ @@ -25,8 +23,8 @@ $app = new App([ $scopeRepository = new ScopeRepository(); $accessTokenRepository = new AccessTokenRepository(); - $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + $privateKeyPath = 'file://'.__DIR__.'/../private.key'; + $publicKeyPath = 'file://'.__DIR__.'/../public.key'; // Setup the authorization server $server = new Server( @@ -38,7 +36,7 @@ $app = new App([ ); return $server; - } + }, ]); $app->add(new ResourceServerMiddleware($app->getContainer()->get(Server::class))); @@ -50,7 +48,7 @@ $app->post('/api/example', function (Request $request, Response $response) { $params = [ 'id' => 1, 'name' => 'Alex', - 'city' => 'London' + 'city' => 'London', ]; } diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index ad9bf0cb..6ecf5122 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -3,19 +3,15 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; - use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include(__DIR__ . '/../vendor/autoload.php'); - - +include __DIR__.'/../vendor/autoload.php'; // App $app = new App([Server::class => function () { @@ -25,8 +21,8 @@ $app = new App([Server::class => function () { $accessTokenRepository = new AccessTokenRepository(); $refreshTokenRepository = new RefreshTokenRepository(); - $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + $privateKeyPath = 'file://'.__DIR__.'/../private.key'; + $publicKeyPath = 'file://'.__DIR__.'/../public.key'; // Setup the authorization server $server = new Server( 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 @@ $this->errorType, - 'message' => $this->getMessage() + 'message' => $this->getMessage(), ]; if ($this->hint !== null) { @@ -264,14 +265,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 @@ -303,7 +304,7 @@ class OAuthServerException extends \Exception } } if ($authScheme !== null) { - $headers[] = 'WWW-Authenticate: ' . $authScheme . ' realm="OAuth"'; + $headers[] = 'WWW-Authenticate: '.$authScheme.' realm="OAuth"'; } } @@ -312,7 +313,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 */ diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index b2d06179..ee4ab684 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; @@ -29,7 +28,7 @@ use OAuth2ServerExamples\Repositories\AuthCodeRepository; use Psr\Http\Message\ServerRequestInterface; /** - * Abstract grant class + * Abstract grant class. */ abstract class AbstractGrant implements GrantTypeInterface { @@ -139,7 +138,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function setEmitter(EmitterInterface $emitter = null) { @@ -147,7 +146,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL) { @@ -171,12 +170,13 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * Validate the client + * Validate the client. * * @param \Psr\Http\Message\ServerRequestInterface $request * - * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface */ protected function validateClient(ServerRequestInterface $request) { @@ -224,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, @@ -322,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 @@ -353,7 +353,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * Issue an auth code + * Issue an auth code. * * @param \DateInterval $tokenTTL * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client @@ -361,8 +361,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, @@ -405,13 +406,13 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * Generate a new unique identifier + * Generate a new unique identifier. * * @param int $length * - * @return string - * * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return string */ protected function generateUniqueIdentifier($length = 40) { @@ -430,13 +431,12 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function canRespondToRequest(ServerRequestInterface $request) { - return ( + return isset($request->getParsedBody()['grant_type']) - && $request->getParsedBody()['grant_type'] === $this->getIdentifier() - ); + && $request->getParsedBody()['grant_type'] === $this->getIdentifier(); } } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 13b8a984..e134b59f 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; @@ -39,7 +39,6 @@ class AuthCodeGrant extends AbstractGrant */ private $pathToAuthorizeTemplate; - /** * @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository @@ -61,22 +60,22 @@ class AuthCodeGrant extends AbstractGrant $this->userRepository = $userRepository; $this->authCodeTTL = $authCodeTTL; $this->pathToLoginTemplate = ($pathToLoginTemplate === null) - ? __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user.php' + ? __DIR__.'/../ResponseTypes/DefaultTemplates/login_user.php' : $this->pathToLoginTemplate; $this->pathToAuthorizeTemplate = ($pathToLoginTemplate === null) - ? __DIR__ . '/../ResponseTypes/DefaultTemplates/authorize_client.php' + ? __DIR__.'/../ResponseTypes/DefaultTemplates/authorize_client.php' : $this->pathToAuthorizeTemplate; $this->refreshTokenTTL = new \DateInterval('P1M'); } - /** - * 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 @@ -153,7 +152,6 @@ 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)); @@ -219,18 +217,20 @@ class AuthCodeGrant extends AbstractGrant } $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, @@ -286,21 +286,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 */ @@ -310,7 +309,7 @@ class AuthCodeGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function respondToRequest( ServerRequestInterface $request, diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index f5881e12..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, @@ -41,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 1341c1fa..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,26 +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(); /** - * Respond to an incoming request + * Respond to an incoming request. * * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType @@ -62,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/PasswordGrant.php b/src/Grant/PasswordGrant.php index 0b30bfe2..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 { @@ -44,7 +43,7 @@ class PasswordGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function respondToRequest( ServerRequestInterface $request, @@ -53,7 +52,7 @@ 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 @@ -70,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) { @@ -97,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 adaa2306..19bab077 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.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\Utils\KeyCrypt; use Psr\Http\Message\ServerRequestInterface; /** - * Refresh token grant + * Refresh token grant. */ class RefreshTokenGrant extends AbstractGrant { @@ -35,7 +34,7 @@ class RefreshTokenGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function respondToRequest( ServerRequestInterface $request, @@ -52,6 +51,7 @@ class RefreshTokenGrant extends AbstractGrant $scopes = array_map(function ($scopeId) { $scope = new ScopeEntity(); $scope->setIdentifier($scopeId); + return $scope; }, $oldRefreshToken['scopes']); } else { @@ -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) { @@ -102,7 +102,7 @@ class RefreshTokenGrant extends AbstractGrant try { $refreshToken = KeyCrypt::decrypt($encryptedRefreshToken, $this->pathToPublicKey); } catch (\LogicException $e) { - throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: ' . $e->getMessage()); + throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: '.$e->getMessage()); } $refreshTokenData = json_decode($refreshToken, true); @@ -110,9 +110,9 @@ class RefreshTokenGrant extends AbstractGrant $this->getEmitter()->emit(new Event('refresh_token.client.failed', $request)); throw OAuthServerException::invalidRefreshToken( - 'Token is not linked to client,' . - ' got: ' . $clientId . - ' expected: ' . $refreshTokenData['client_id'] + 'Token is not linked to client,'. + ' got: '.$clientId. + ' expected: '.$refreshTokenData['client_id'] ); } @@ -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 eb88a6cd..0c7ebe4f 100644 --- a/src/Repositories/ClientRepositoryInterface.php +++ b/src/Repositories/ClientRepositoryInterface.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\Repositories; /** - * Client storage interface + * Client storage interface. */ interface ClientRepositoryInterface extends RepositoryInterface { /** - * Get a client + * Get a client. * - * @param string $clientIdentifier The client's identifier - * @param string $grantType The grant type used + * @param string $clientIdentifier The client's identifier + * @param string $grantType The grant type used * * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface */ 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..28e9003a 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.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 Lcobucci\JWT\Builder; @@ -43,7 +42,7 @@ class BearerTokenResponse extends AbstractResponseType $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 8b62c10a..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 @@ -48,7 +47,7 @@ class KeyCrypt } /** - * Decrypt data with a public key + * Decrypt data with a public key. * * @param string $encryptedData * @param string $pathToPublicKey diff --git a/src/Utils/SecureKey.php b/src/Utils/SecureKey.php index ee5a85ea..17a2fcf2 100644 --- a/src/Utils/SecureKey.php +++ b/src/Utils/SecureKey.php @@ -1,31 +1,30 @@ * @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 + * SecureKey class. */ class SecureKey { /** - * Generate a new unique code + * Generate a new unique code. * - * @param integer $len Length of the generated code + * @param int $len Length of the generated code + * + * @throws \League\OAuth2\Server\Exception\OAuthServerException * * @return string - * @throws \League\OAuth2\Server\Exception\OAuthServerException */ public static function generate($len = 40) { @@ -34,13 +33,13 @@ class SecureKey // @codeCoverageIgnoreStart } catch (\TypeError $e) { // Well, it's an integer, so this IS unexpected. - throw OAuthServerException::serverError("An unexpected error has occurred"); + 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"); + 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?"); + throw OAuthServerException::serverError('Could not generate a random string. Is our OS secure?'); } // @codeCoverageIgnoreEnd diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php index 7f8cf458..8ea9bc26 100644 --- a/tests/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 index d64f6edb..a2b764d2 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -10,11 +10,11 @@ use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Grant\AbstractGrant; -use League\OAuth2\Server\Repositories\ClientRepositoryInterface; -use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; -use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; 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 Zend\Diactoros\ServerRequest; class AbstractGrantTest extends \PHPUnit_Framework_TestCase @@ -151,7 +151,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $serverRequest = new ServerRequest(); $serverRequest = $serverRequest->withParsedBody([ - 'client_id' => 'foo', + 'client_id' => 'foo', 'client_secret' => 'foo', ]); @@ -180,7 +180,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $serverRequest = new ServerRequest(); $serverRequest = $serverRequest->withParsedBody([ 'client_id' => 'foo', - 'redirect_uri' => 'http://bar/foo' + 'redirect_uri' => 'http://bar/foo', ]); $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); diff --git a/tests/Grant/ClientCredentialsGrantTest.php b/tests/Grant/ClientCredentialsGrantTest.php index 52e51c9a..c67e889c 100644 --- a/tests/Grant/ClientCredentialsGrantTest.php +++ b/tests/Grant/ClientCredentialsGrantTest.php @@ -42,7 +42,7 @@ class ClientCredentialsGrantTest extends \PHPUnit_Framework_TestCase $responseType = new StubResponseType(); $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); - + $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); } } diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index 8bfe71c9..3be59bdb 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -5,7 +5,6 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; -use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -14,7 +13,6 @@ use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\Utils\KeyCrypt; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; -use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use Zend\Diactoros\ServerRequest; class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 9a85c351..3f823a17 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -4,11 +4,11 @@ namespace LeagueTests; use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Grant\ClientCredentialsGrant; +use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Server; use LeagueTests\Stubs\StubResponseType; -use League\OAuth2\Server\Repositories\ClientRepositoryInterface; -use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; -use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use Psr\Http\Message\ResponseInterface; class ServerTest extends \PHPUnit_Framework_TestCase diff --git a/tests/Stubs/StubResponseType.php b/tests/Stubs/StubResponseType.php index d62daf9b..22d093a0 100644 --- a/tests/Stubs/StubResponseType.php +++ b/tests/Stubs/StubResponseType.php @@ -11,7 +11,9 @@ use Zend\Diactoros\Response; class StubResponseType extends AbstractResponseType { - public function __construct() {} + public function __construct() + { + } public function getAccessToken() { @@ -58,4 +60,4 @@ class StubResponseType extends AbstractResponseType { return new Response(); } -} \ No newline at end of file +} diff --git a/tests/Stubs/UserEntity.php b/tests/Stubs/UserEntity.php index 4c157df5..5d102c77 100644 --- a/tests/Stubs/UserEntity.php +++ b/tests/Stubs/UserEntity.php @@ -10,4 +10,4 @@ class UserEntity implements UserEntityInterface { return 123; } -} \ No newline at end of file +} From 97c138bb0b0591680459874ec8dbcc0eb7b83236 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 20 Feb 2016 10:05:15 +0000 Subject: [PATCH 254/444] Removed unused SecureKey class --- src/Utils/SecureKey.php | 48 ----------------------------------------- 1 file changed, 48 deletions(-) delete mode 100644 src/Utils/SecureKey.php diff --git a/src/Utils/SecureKey.php b/src/Utils/SecureKey.php deleted file mode 100644 index 17a2fcf2..00000000 --- a/src/Utils/SecureKey.php +++ /dev/null @@ -1,48 +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 int $len Length of the generated code - * - * @throws \League\OAuth2\Server\Exception\OAuthServerException - * - * @return string - */ - public static function generate($len = 40) - { - try { - $string = random_bytes($len); - // @codeCoverageIgnoreStart - } 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?'); - } - // @codeCoverageIgnoreEnd - - return bin2hex($string); - } -} From d0878300d0461f77267ab707949aa12a93d4bef9 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 14:32:16 +0000 Subject: [PATCH 255/444] Bug fix for AuthCodeGrant --- src/Grant/AuthCodeGrant.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index e134b59f..cdd0f1cd 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -80,7 +80,19 @@ class AuthCodeGrant extends AbstractGrant protected function respondToAuthorizationRequest( ServerRequestInterface $request ) { - $client = $this->validateClient($request); + $clientId = $this->getQueryStringParameter( + 'client_id', + $request, + $this->getServerParameter('PHP_AUTH_USER', $request) + ); + if (is_null($clientId)) { + throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); + } + + $client = $this->clientRepository->getClientEntity( + $clientId, + $this->getIdentifier() + ); if ($client instanceof ClientEntityInterface === false) { $this->emitter->emit(new Event('client.authentication.failed', $request)); From 8b601d79b9bd0819450e95d34c19f62bda279e3c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 14:32:27 +0000 Subject: [PATCH 256/444] First commit of AuthCodeGrant test --- tests/Grant/AuthCodeGrantTest.php | 114 ++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 tests/Grant/AuthCodeGrantTest.php diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php new file mode 100644 index 00000000..41979461 --- /dev/null +++ b/tests/Grant/AuthCodeGrantTest.php @@ -0,0 +1,114 @@ +getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $this->getMock(UserRepositoryInterface::class), + new \DateInterval('PT10M') + ); + + $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', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'approve' + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + } +} From a4b65241adbe622ab37a67befa440eed44577862 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 16:09:39 +0000 Subject: [PATCH 257/444] Updated PasswordGrant test --- tests/Grant/PasswordGrantTest.php | 101 ++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php index c81e4c61..096f374e 100644 --- a/tests/Grant/PasswordGrantTest.php +++ b/tests/Grant/PasswordGrantTest.php @@ -5,6 +5,7 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -62,4 +63,104 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase $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')); + } } From 7f539f8736ac9bc9c3f05fa40f4865159ae359c7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 16:40:01 +0000 Subject: [PATCH 258/444] Removed unused exception parameters --- src/Exception/OAuthServerException.php | 108 +++++++++---------------- src/Grant/AbstractGrant.php | 6 +- src/Grant/AuthCodeGrant.php | 10 +-- 3 files changed, 45 insertions(+), 79 deletions(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 3a8aa469..061722d7 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -33,14 +33,15 @@ class OAuthServerException extends \Exception * Throw a new exception. * * @param string $message Error message + * @param int $code Error code * @param string $errorType Error type * @param int $httpStatusCode HTTP status code to send (default = 400) * @param null|string $hint A helper hint * @param null|string $redirectUri A HTTP URI to redirect the user back to */ - public function __construct($message, $errorType, $httpStatusCode = 400, $hint = null, $redirectUri = null) + public function __construct($message, $code, $errorType, $httpStatusCode = 400, $hint = null, $redirectUri = null) { - parent::__construct($message); + parent::__construct($message, $code); $this->httpStatusCode = $httpStatusCode; $this->errorType = $errorType; $this->hint = $hint; @@ -49,110 +50,73 @@ class OAuthServerException extends \Exception /** * Invalid grant type error. - * - * @param null|string $localizedError - * @param null|string $localizedHint - * * @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 - * * @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. * - * @param string $parameter The invalid parameter - * @param null|string $localizedError - * @param null|string $localizedHint + * @param string $parameter The invalid parameter + * @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); + public static function invalidRequest($parameter, $hint = null) + { + $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_request', 400, $hint); + return new static($errorMessage, 3, 'invalid_request', 400, $hint); } /** * Invalid client error. * - * @param null|string $localizedError - * * @return static */ - public static function invalidClient($localizedError = null) + public static function invalidClient() { - $errorMessage = (is_null($localizedError)) - ? 'Client authentication failed' - : $localizedError; + $errorMessage = 'Client authentication failed'; - return new static($errorMessage, 'invalid_client', 401); + return new static($errorMessage, 4, 'invalid_client', 401); } /** * 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 + * @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, $localizedError = null, $localizedHint = null, $redirectUri = null) + public static function invalidScope($scope, $redirectUri = null) { - $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 = 'The requested scope is invalid, unknown, or malformed'; + $hint = sprintf('Check the `%s` scope', $scope); - return new static($errorMessage, 'invalid_scope', 400, $hint, $redirectUri); + return new static($errorMessage, 5, 'invalid_scope', 400, $hint, $redirectUri); } /** @@ -162,7 +126,7 @@ class OAuthServerException extends \Exception */ 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); } /** @@ -176,7 +140,8 @@ class OAuthServerException extends \Exception { return new static( 'The authorization server encountered an unexpected condition which prevented it from fulfilling' - .'the request.', + . 'the request.', + 7, 'server_error', 500, $hint @@ -192,7 +157,7 @@ class OAuthServerException extends \Exception */ 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); } /** @@ -208,6 +173,7 @@ class OAuthServerException extends \Exception return new static( 'The resource owner or authorization server denied the request.', 'access_denied', + 9, 401, $hint, $redirectUri @@ -304,7 +270,7 @@ class OAuthServerException extends \Exception } } if ($authScheme !== null) { - $headers[] = 'WWW-Authenticate: '.$authScheme.' realm="OAuth"'; + $headers[] = 'WWW-Authenticate: ' . $authScheme . ' realm="OAuth"'; } } diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index ee4ab684..3823047d 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -186,7 +186,7 @@ abstract class AbstractGrant implements GrantTypeInterface $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( @@ -206,7 +206,7 @@ abstract class AbstractGrant implements GrantTypeInterface ); if ($client->canKeepASecret() && is_null($clientSecret)) { - throw OAuthServerException::invalidRequest('client_secret', null, '`%s` parameter is missing'); + throw OAuthServerException::invalidRequest('client_secret', '`%s` parameter is missing'); } if ($client->canKeepASecret() && $client->validateSecret($clientSecret) === false) { @@ -256,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; diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index cdd0f1cd..4c808ad9 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -60,10 +60,10 @@ class AuthCodeGrant extends AbstractGrant $this->userRepository = $userRepository; $this->authCodeTTL = $authCodeTTL; $this->pathToLoginTemplate = ($pathToLoginTemplate === null) - ? __DIR__.'/../ResponseTypes/DefaultTemplates/login_user.php' + ? __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user.php' : $this->pathToLoginTemplate; $this->pathToAuthorizeTemplate = ($pathToLoginTemplate === null) - ? __DIR__.'/../ResponseTypes/DefaultTemplates/authorize_client.php' + ? __DIR__ . '/../ResponseTypes/DefaultTemplates/authorize_client.php' : $this->pathToAuthorizeTemplate; $this->refreshTokenTTL = new \DateInterval('P1M'); } @@ -86,7 +86,7 @@ class AuthCodeGrant extends AbstractGrant $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'); } $client = $this->clientRepository->getClientEntity( @@ -252,7 +252,7 @@ class AuthCodeGrant extends AbstractGrant // The redirect URI is required in this request $redirectUri = $this->getQueryStringParameter('redirect_uri', $request, null); if (is_null($redirectUri)) { - throw OAuthServerException::invalidRequest('redirect_uri', null, '`%s` parameter is missing'); + throw OAuthServerException::invalidRequest('redirect_uri'); } // Validate request @@ -278,7 +278,7 @@ class AuthCodeGrant extends AbstractGrant throw OAuthServerException::invalidRequest('code', 'Authorization code was not issued to this client'); } } 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 From bc82f5baddd9e655b9d2bc4999a1be107571c6b8 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 16:40:16 +0000 Subject: [PATCH 259/444] Improved RefreshTokenGrant tests --- tests/Grant/RefreshTokenGrantTest.php | 347 +++++++++++++++++++++++++- 1 file changed, 338 insertions(+), 9 deletions(-) diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index 3be59bdb..c9edebe2 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -5,14 +5,14 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; -use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Utils\KeyCrypt; use LeagueTests\Stubs\StubResponseType; -use LeagueTests\Stubs\UserEntity; use Zend\Diactoros\ServerRequest; class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase @@ -36,18 +36,14 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $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 RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPathToPublicKey('file://'.__DIR__.'/../Utils/public.key'); - $grant->setPathToPrivateKey('file://'.__DIR__.'/../Utils/private.key'); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); $oldRefreshToken = KeyCrypt::encrypt( json_encode( @@ -60,7 +56,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase 'expire_time' => time() + 3600, ] ), - 'file://'.__DIR__.'/../Utils/private.key' + 'file://' . __DIR__ . '/../Utils/private.key' ); $serverRequest = new ServerRequest(); @@ -78,4 +74,337 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $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')); + } } From 27d4441d1d885f5054f0bde197f70b8cabff5c9e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 16:40:29 +0000 Subject: [PATCH 260/444] Updated to phpunit 5 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index a1bfda41..800e0f1a 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ "paragonie/random_compat": "^1.1" }, "require-dev": { - "phpunit/phpunit": "4.8.*" + "phpunit/phpunit": "~5.2" }, "repositories": [ { From 2488cbd55d122741664b653157ba44d3fdcdb837 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 17:08:49 +0000 Subject: [PATCH 261/444] Bug fixes --- src/Grant/AuthCodeGrant.php | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 4c808ad9..27dbb1c0 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -59,13 +59,21 @@ class AuthCodeGrant extends AbstractGrant $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; + } } /** @@ -95,7 +103,7 @@ class AuthCodeGrant extends AbstractGrant ); 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(); } @@ -329,13 +337,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']) + array_key_exists('grant_type', $request->getParsedBody()) && $request->getParsedBody()['grant_type'] === 'authorization_code' ) { return $this->respondToAccessTokenRequest($request, $responseType, $accessTokenTTL); From 9675dff220fe4e4063452c7ac22f2a2c5ca40482 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 17:08:57 +0000 Subject: [PATCH 262/444] Added AuthCodeGrant tests --- tests/Grant/AuthCodeGrantTest.php | 419 +++++++++++++++++++++++++++++- 1 file changed, 412 insertions(+), 7 deletions(-) diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 41979461..faf18318 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -23,7 +23,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), $this->getMock(UserRepositoryInterface::class), - new \DateInterval('PT10M') + new \DateInterval('PT10M'), + '', + '' ); $this->assertEquals('authorization_code', $grant->getIdentifier()); @@ -49,7 +51,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $cookies = [], $queryParams = [ 'response_type' => 'code', - 'client_id' => 'foo' + 'client_id' => 'foo', ] ); @@ -76,8 +78,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase '' ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://'.__DIR__.'/../Utils/public.key'); - $grant->setPathToPrivateKey('file://'.__DIR__.'/../Utils/private.key'); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); $request = new ServerRequest( [ @@ -93,8 +95,187 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase [ 'oauth_authorize_request' => KeyCrypt::encrypt( json_encode(['user_id' => 123]), - 'file://'.__DIR__.'/../Utils/private.key' - ) + '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); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 4 + */ + 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', @@ -103,7 +284,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase [ 'username' => 'alex', 'password' => 'whisky', - 'action' => 'approve' + 'action' => 'approve', ] ); @@ -111,4 +292,228 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->assertTrue($response instanceof ResponseInterface); } + + /** + * @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); + } } From f06adb38cd62f58f9b644307a0e0c12c8c3b92ca Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 17:09:04 +0000 Subject: [PATCH 263/444] Require dev league/plates --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 800e0f1a..7d6ba886 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ "paragonie/random_compat": "^1.1" }, "require-dev": { - "phpunit/phpunit": "~5.2" + "phpunit/phpunit": "~5.2", + "league/plates": "^3.1" }, "repositories": [ { From eedcfe115c0e8827c697e962e58e3ccb2cd781f7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 17:09:12 +0000 Subject: [PATCH 264/444] Bug fixes --- src/Exception/OAuthServerException.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 061722d7..951f8a82 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -140,11 +140,10 @@ 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 ); } @@ -172,8 +171,8 @@ class OAuthServerException extends \Exception { return new static( 'The resource owner or authorization server denied the request.', - 'access_denied', 9, + 'access_denied', 401, $hint, $redirectUri From cee4147688e289cc573dcb9e80c1f391196183c8 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 17:11:58 +0000 Subject: [PATCH 265/444] PHP 5.5 doesn't support phpunit 5 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7d6ba886..67e551a9 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ "paragonie/random_compat": "^1.1" }, "require-dev": { - "phpunit/phpunit": "~5.2", + "phpunit/phpunit": "^4.8", "league/plates": "^3.1" }, "repositories": [ From d02437dd7397df13f0aba782e6dbb2cd0e0e867e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 18:13:39 +0000 Subject: [PATCH 266/444] Improved testing --- src/Exception/OAuthServerException.php | 8 + src/Grant/AbstractGrant.php | 11 +- src/Grant/AuthCodeGrant.php | 23 +- tests/Grant/AuthCodeGrantTest.php | 502 ++++++++++++++++++++++++- 4 files changed, 521 insertions(+), 23 deletions(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 951f8a82..af9379d9 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -286,4 +286,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 3823047d..407ae4db 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -16,6 +16,7 @@ use League\Event\Event; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\AuthCodeEntity; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Exception\OAuthServerException; @@ -344,6 +345,11 @@ abstract class AbstractGrant implements GrantTypeInterface $accessToken->setUserIdentifier($userIdentifier); foreach ($scopes as $scope) { + if (is_string($scope)) { + $s = new ScopeEntity(); + $s->setIdentifier($scope); + $scope = $s; + } $accessToken->addScope($scope); } @@ -435,8 +441,7 @@ abstract class AbstractGrant implements GrantTypeInterface */ 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 27dbb1c0..05afc7fd 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -61,7 +61,7 @@ class AuthCodeGrant extends AbstractGrant $this->authCodeTTL = $authCodeTTL; $this->refreshTokenTTL = new \DateInterval('P1M'); - $this->pathToLoginTemplate = __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user'; + $this->pathToLoginTemplate = __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user'; if ($pathToLoginTemplate !== null) { $this->pathToLoginTemplate = (substr($pathToLoginTemplate, -4) === '.php') ? substr($pathToLoginTemplate, 0, -4) @@ -108,6 +108,11 @@ class AuthCodeGrant extends AbstractGrant throw OAuthServerException::invalidClient(); } + $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( @@ -224,6 +229,7 @@ class AuthCodeGrant extends AbstractGrant json_encode( [ 'client_id' => $authCode->getClient()->getIdentifier(), + 'redirect_uri' => $authCode->getRedirectUri(), 'auth_code_id' => $authCode->getIdentifier(), 'scopes' => $authCode->getScopes(), 'user_id' => $authCode->getUserIdentifier(), @@ -258,7 +264,7 @@ class AuthCodeGrant extends AbstractGrant DateInterval $accessTokenTTL ) { // The redirect URI is required in this request - $redirectUri = $this->getQueryStringParameter('redirect_uri', $request, null); + $redirectUri = $this->getRequestParameter('redirect_uri', $request, null); if (is_null($redirectUri)) { throw OAuthServerException::invalidRequest('redirect_uri'); } @@ -285,6 +291,10 @@ class AuthCodeGrant extends AbstractGrant 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', 'Cannot decrypt the authorization code'); } @@ -341,13 +351,8 @@ class AuthCodeGrant extends AbstractGrant && $request->getQueryParams()['response_type'] === 'code' ) { return $this->respondToAuthorizationRequest($request); - } elseif ( - array_key_exists('grant_type', $request->getParsedBody()) - && $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/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index faf18318..d5764843 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -3,10 +3,14 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\Entities\ClientEntity; +use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\Utils\KeyCrypt; use LeagueTests\Stubs\StubResponseType; @@ -24,8 +28,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMock(RefreshTokenRepositoryInterface::class), $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M'), - '', - '' + 'foo/bar.php', + 'foo/bar.php' ); $this->assertEquals('authorization_code', $grant->getIdentifier()); @@ -234,10 +238,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->assertTrue($response instanceof ResponseInterface); } - /** - * @expectedException \League\OAuth2\Server\Exception\OAuthServerException - * @expectedExceptionCode 4 - */ public function testRespondToAuthorizationRequestBadClient() { $client = null; @@ -252,9 +252,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), $userRepositoryMock, - new \DateInterval('PT10M'), - '', - '' + new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); @@ -288,9 +286,69 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ] ); - $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + try { + /** @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } catch (OAuthServerException $e) { + $this->assertEquals($e->getMessage(), 'Client authentication failed'); + } + } - $this->assertTrue($response instanceof ResponseInterface); + 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'); + } } /** @@ -516,4 +574,426 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $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'); + } + } } From e08669d50cc2589297f117062757ec5c92b37fc1 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 22 Feb 2016 07:58:12 +0000 Subject: [PATCH 267/444] Doc improvements --- src/Grant/AuthCodeGrant.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 05afc7fd..4d253488 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -208,14 +208,16 @@ class AuthCodeGrant extends AbstractGrant ); } - $stateParameter = $this->getQueryStringParameter('state', $request); - + // 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, @@ -242,6 +244,7 @@ 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(); From a1bdaae9a94c897a9ee71a76ffa9964504339bd9 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 22 Feb 2016 07:58:25 +0000 Subject: [PATCH 268/444] Access token can now return a JWT from itself --- src/Entities/AccessTokenEntity.php | 23 +++++++++++++++++++ .../Interfaces/AccessTokenEntityInterface.php | 10 ++++++++ 2 files changed, 33 insertions(+) diff --git a/src/Entities/AccessTokenEntity.php b/src/Entities/AccessTokenEntity.php index d95eee31..75bcb4c6 100644 --- a/src/Entities/AccessTokenEntity.php +++ b/src/Entities/AccessTokenEntity.php @@ -2,6 +2,8 @@ namespace League\OAuth2\Server\Entities; +use Lcobucci\JWT\Builder; +use Lcobucci\JWT\Signer\Rsa\Sha256; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Traits\EntityTrait; use League\OAuth2\Server\Entities\Traits\TokenEntityTrait; @@ -9,4 +11,25 @@ use League\OAuth2\Server\Entities\Traits\TokenEntityTrait; class AccessTokenEntity implements AccessTokenEntityInterface { use EntityTrait, TokenEntityTrait; + + /** + * Generate a JWT from the access token + * + * @param string $pathToPrivateKey + * + * @return string + */ + public function convertToJWT($pathToPrivateKey) + { + return (new Builder()) + ->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/Interfaces/AccessTokenEntityInterface.php b/src/Entities/Interfaces/AccessTokenEntityInterface.php index a4252bae..2a7ef985 100644 --- a/src/Entities/Interfaces/AccessTokenEntityInterface.php +++ b/src/Entities/Interfaces/AccessTokenEntityInterface.php @@ -2,6 +2,16 @@ namespace League\OAuth2\Server\Entities\Interfaces; +use Lcobucci\JWT\Builder; + interface AccessTokenEntityInterface extends TokenInterface { + /** + * Generate a JWT from the access token + * + * @param string $pathToPrivateKey + * + * @return string + */ + public function convertToJWT($pathToPrivateKey); } From ad270f7d9df097a8fb910b64fc866844eb5c1032 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 22 Feb 2016 07:58:44 +0000 Subject: [PATCH 269/444] Redirect either with query string parameters or fragment parameters --- src/Exception/OAuthServerException.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index af9379d9..3bd4e934 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -191,10 +191,12 @@ class OAuthServerException extends \Exception * 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(); @@ -215,9 +217,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) { From 0d0aaa8764f091b5647d1f3aced732edf9fd67ff Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 22 Feb 2016 07:58:59 +0000 Subject: [PATCH 270/444] Use the new access token covertToJWT method --- src/ResponseTypes/BearerTokenResponse.php | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index 28e9003a..a1da1fe8 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -29,16 +29,7 @@ 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', From e2794c47afdf5667d774d97b6a6d88710f515964 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 22 Feb 2016 07:59:17 +0000 Subject: [PATCH 271/444] First commit of the implicit grant --- src/Grant/ImplicitGrant.php | 242 ++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 src/Grant/ImplicitGrant.php diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php new file mode 100644 index 00000000..959c69b2 --- /dev/null +++ b/src/Grant/ImplicitGrant.php @@ -0,0 +1,242 @@ +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); + } +} From 997d390f3d60734b02cf6cc48f2d54da62dbcfe0 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 22 Feb 2016 03:00:50 -0500 Subject: [PATCH 272/444] Applied fixes from StyleCI --- examples/public/auth_code.php | 6 +- examples/public/client_credentials.php | 6 +- examples/public/middleware_authentication.php | 6 +- examples/public/password.php | 6 +- examples/public/protected_api.php | 6 +- examples/public/refresh_token.php | 6 +- .../Interfaces/AccessTokenEntityInterface.php | 2 - src/Exception/OAuthServerException.php | 1 + src/Grant/AbstractGrant.php | 1 - src/Grant/ImplicitGrant.php | 1 - src/Grant/RefreshTokenGrant.php | 8 +-- src/ResponseTypes/BearerTokenResponse.php | 2 - tests/Bootstrap.php | 2 +- tests/Grant/AuthCodeGrantTest.php | 72 +++++++------------ tests/Grant/PasswordGrantTest.php | 1 - tests/Utils/KeyCryptTest.php | 8 +-- 16 files changed, 55 insertions(+), 79 deletions(-) diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index d15a1561..998101dc 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -13,7 +13,7 @@ use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include __DIR__.'/../vendor/autoload.php'; +include __DIR__ . '/../vendor/autoload.php'; // App $app = new App([ @@ -27,8 +27,8 @@ $app = new App([ $refreshTokenRepository = new RefreshTokenRepository(); $authCodeRepository = new AuthCodeRepository(); - $privateKeyPath = 'file://'.__DIR__.'/../private.key'; - $publicKeyPath = 'file://'.__DIR__.'/../public.key'; + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new Server( diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index 48ee0b6f..a36207ee 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -10,7 +10,7 @@ use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include __DIR__.'/../vendor/autoload.php'; +include __DIR__ . '/../vendor/autoload.php'; // App $app = new App([ @@ -21,8 +21,8 @@ $app = new App([ $scopeRepository = new ScopeRepository(); $accessTokenRepository = new AccessTokenRepository(); - $privateKeyPath = 'file://'.__DIR__.'/../private.key'; - $publicKeyPath = 'file://'.__DIR__.'/../public.key'; + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new Server( diff --git a/examples/public/middleware_authentication.php b/examples/public/middleware_authentication.php index 27f03c5a..f5790687 100644 --- a/examples/public/middleware_authentication.php +++ b/examples/public/middleware_authentication.php @@ -11,7 +11,7 @@ use OAuth2ServerExamples\Repositories\ScopeRepository; use OAuth2ServerExamples\Repositories\UserRepository; use Slim\App; -include __DIR__.'/../vendor/autoload.php'; +include __DIR__ . '/../vendor/autoload.php'; // App $app = new App([ @@ -27,8 +27,8 @@ $app = new App([ $userRepository = new UserRepository(); $refreshTokenRepository = new RefreshTokenRepository(); - $privateKeyPath = 'file://'.__DIR__.'/../private.key'; - $publicKeyPath = 'file://'.__DIR__.'/../public.key'; + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new Server( diff --git a/examples/public/password.php b/examples/public/password.php index 4c0548b4..aa4f75dc 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -12,7 +12,7 @@ use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include __DIR__.'/../vendor/autoload.php'; +include __DIR__ . '/../vendor/autoload.php'; // App $app = new App([ @@ -25,8 +25,8 @@ $app = new App([ $userRepository = new UserRepository(); $refreshTokenRepository = new RefreshTokenRepository(); - $privateKeyPath = 'file://'.__DIR__.'/../private.key'; - $publicKeyPath = 'file://'.__DIR__.'/../public.key'; + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new Server( diff --git a/examples/public/protected_api.php b/examples/public/protected_api.php index 35b829ae..6e502fba 100644 --- a/examples/public/protected_api.php +++ b/examples/public/protected_api.php @@ -9,7 +9,7 @@ use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include __DIR__.'/../vendor/autoload.php'; +include __DIR__ . '/../vendor/autoload.php'; // App $app = new App([ @@ -23,8 +23,8 @@ $app = new App([ $scopeRepository = new ScopeRepository(); $accessTokenRepository = new AccessTokenRepository(); - $privateKeyPath = 'file://'.__DIR__.'/../private.key'; - $publicKeyPath = 'file://'.__DIR__.'/../public.key'; + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new Server( diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index 6ecf5122..bbec33e3 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -11,7 +11,7 @@ use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include __DIR__.'/../vendor/autoload.php'; +include __DIR__ . '/../vendor/autoload.php'; // App $app = new App([Server::class => function () { @@ -21,8 +21,8 @@ $app = new App([Server::class => function () { $accessTokenRepository = new AccessTokenRepository(); $refreshTokenRepository = new RefreshTokenRepository(); - $privateKeyPath = 'file://'.__DIR__.'/../private.key'; - $publicKeyPath = 'file://'.__DIR__.'/../public.key'; + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new Server( diff --git a/src/Entities/Interfaces/AccessTokenEntityInterface.php b/src/Entities/Interfaces/AccessTokenEntityInterface.php index 2a7ef985..884c0187 100644 --- a/src/Entities/Interfaces/AccessTokenEntityInterface.php +++ b/src/Entities/Interfaces/AccessTokenEntityInterface.php @@ -2,8 +2,6 @@ namespace League\OAuth2\Server\Entities\Interfaces; -use Lcobucci\JWT\Builder; - interface AccessTokenEntityInterface extends TokenInterface { /** diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 3bd4e934..7b8a1016 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -50,6 +50,7 @@ class OAuthServerException extends \Exception /** * Invalid grant type error. + * * @return static */ public static function invalidGrantType() diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 407ae4db..a7b5fbd1 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -16,7 +16,6 @@ use League\Event\Event; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\AuthCodeEntity; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Exception\OAuthServerException; diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 959c69b2..8123550e 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -2,7 +2,6 @@ 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; diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 19bab077..83ffe5ed 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -102,7 +102,7 @@ class RefreshTokenGrant extends AbstractGrant try { $refreshToken = KeyCrypt::decrypt($encryptedRefreshToken, $this->pathToPublicKey); } catch (\LogicException $e) { - throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: '.$e->getMessage()); + throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: ' . $e->getMessage()); } $refreshTokenData = json_decode($refreshToken, true); @@ -110,9 +110,9 @@ class RefreshTokenGrant extends AbstractGrant $this->getEmitter()->emit(new Event('refresh_token.client.failed', $request)); throw OAuthServerException::invalidRefreshToken( - 'Token is not linked to client,'. - ' got: '.$clientId. - ' expected: '.$refreshTokenData['client_id'] + 'Token is not linked to client,' . + ' got: ' . $clientId . + ' expected: ' . $refreshTokenData['client_id'] ); } diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index a1da1fe8..fdbe73b0 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -10,9 +10,7 @@ */ 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; diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php index 8ea9bc26..99c00e16 100644 --- a/tests/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/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index d5764843..1508329c 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -7,16 +7,15 @@ use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; +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\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\Utils\KeyCrypt; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; use Psr\Http\Message\ResponseInterface; -use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase @@ -46,8 +45,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, null, 'php://input', @@ -90,8 +88,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -148,8 +145,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -211,8 +207,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -263,8 +258,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -287,7 +281,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); try { - /** @var StubResponseType $response */ + /* @var StubResponseType $response */ $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } catch (OAuthServerException $e) { $this->assertEquals($e->getMessage(), 'Client authentication failed'); @@ -319,8 +313,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -334,7 +327,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase [ 'response_type' => 'code', 'client_id' => 'foo', - 'redirect_uri' => 'sdfsdf' + 'redirect_uri' => 'sdfsdf', ], [ 'username' => 'alex', @@ -344,7 +337,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); try { - /** @var StubResponseType $response */ + /* @var StubResponseType $response */ $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } catch (OAuthServerException $e) { $this->assertEquals($e->getMessage(), 'Client authentication failed'); @@ -383,8 +376,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -436,8 +428,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -491,8 +482,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -547,8 +537,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -607,8 +596,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, 'POST', 'php://input', @@ -667,8 +655,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, 'POST', 'php://input', @@ -680,7 +667,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ] ); - /** @var StubResponseType $response */ + /* @var StubResponseType $response */ $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } @@ -714,8 +701,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, 'POST', 'php://input', @@ -730,7 +716,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ] ); - /** @var StubResponseType $response */ + /* @var StubResponseType $response */ $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } @@ -766,8 +752,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, 'POST', 'php://input', @@ -795,7 +780,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); try { - /** @var StubResponseType $response */ + /* @var StubResponseType $response */ $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } catch (OAuthServerException $e) { $this->assertEquals($e->getHint(), 'Authorization code has expired'); @@ -837,8 +822,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, 'POST', 'php://input', @@ -866,7 +850,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); try { - /** @var StubResponseType $response */ + /* @var StubResponseType $response */ $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } catch (OAuthServerException $e) { $this->assertEquals($e->getHint(), 'Authorization code has been revoked'); @@ -905,8 +889,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, 'POST', 'php://input', @@ -934,7 +917,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); try { - /** @var StubResponseType $response */ + /* @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'); @@ -973,8 +956,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, 'POST', 'php://input', @@ -990,7 +972,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); try { - /** @var StubResponseType $response */ + /* @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/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php index 096f374e..e4f9e3a9 100644 --- a/tests/Grant/PasswordGrantTest.php +++ b/tests/Grant/PasswordGrantTest.php @@ -5,7 +5,6 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; -use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; diff --git a/tests/Utils/KeyCryptTest.php b/tests/Utils/KeyCryptTest.php index 9720dbd3..3fa1f17c 100644 --- a/tests/Utils/KeyCryptTest.php +++ b/tests/Utils/KeyCryptTest.php @@ -9,8 +9,8 @@ class KeyCryptTest extends \PHPUnit_Framework_TestCase public function testEncryptDecrypt() { $payload = 'alex loves whisky'; - $encrypted = KeyCrypt::encrypt($payload, 'file://'.__DIR__.'/private.key'); - $plainText = KeyCrypt::decrypt($encrypted, 'file://'.__DIR__.'/public.key'); + $encrypted = KeyCrypt::encrypt($payload, 'file://' . __DIR__ . '/private.key'); + $plainText = KeyCrypt::decrypt($encrypted, 'file://' . __DIR__ . '/public.key'); $this->assertNotEquals($payload, $encrypted); $this->assertEquals($payload, $plainText); @@ -21,7 +21,7 @@ class KeyCryptTest extends \PHPUnit_Framework_TestCase */ public function testBadPrivateKey() { - KeyCrypt::encrypt('', 'file://'.__DIR__.'/public.key'); + KeyCrypt::encrypt('', 'file://' . __DIR__ . '/public.key'); } /** @@ -29,6 +29,6 @@ class KeyCryptTest extends \PHPUnit_Framework_TestCase */ public function testBadPublicKey() { - KeyCrypt::decrypt('', 'file://'.__DIR__.'/private.key'); + KeyCrypt::decrypt('', 'file://' . __DIR__ . '/private.key'); } } From da53067e6372421e33c84cdfb3420a98581a91e4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 22 Feb 2016 11:04:03 +0000 Subject: [PATCH 273/444] Updated README --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 From 57604508541954e1b14e69e10e7fee9bf8140d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Tue, 8 Mar 2016 21:49:05 +0100 Subject: [PATCH 274/444] satisfy StyleCI --- examples/public/middleware_use.php | 4 ++-- examples/public/refresh_token.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/public/middleware_use.php b/examples/public/middleware_use.php index 9597c2d7..9b8e0991 100644 --- a/examples/public/middleware_use.php +++ b/examples/public/middleware_use.php @@ -69,7 +69,7 @@ $app->post('/access_token', function () { })->add(new AuthenticationServerMiddleware($app->getContainer()->get(Server::class))); // Secured API -$app->group('/api', function() { +$app->group('/api', function () { $this->get('/user', function (ServerRequestInterface $request, ResponseInterface $response) { $params = []; @@ -77,7 +77,7 @@ $app->group('/api', function() { $params = [ 'id' => 1, 'name' => 'Alex', - 'city' => 'London' + 'city' => 'London', ]; } diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index a5e80047..64553311 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -44,7 +44,7 @@ $app = new App([ ); return $server; - } + }, ]); $app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { From 1bdeb71efb1c1e4e7844706bb5c51cc456bcd409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Tue, 8 Mar 2016 21:59:10 +0100 Subject: [PATCH 275/444] make StyleCI happy --- src/Grant/AbstractGrant.php | 1 + src/Grant/AuthCodeGrant.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 1267a6b0..f700c57b 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -277,6 +277,7 @@ abstract class AbstractGrant implements GrantTypeInterface protected function getRequestParameter($parameter, ServerRequestInterface $request, $default = null) { $requestParameters = (array) $request->getParsedBody(); + return isset($requestParameters[$parameter]) ? $requestParameters[$parameter] : $default; } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index a33e8fe9..b8ea461c 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -337,7 +337,7 @@ class AuthCodeGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function canRespondToRequest(ServerRequestInterface $request) { From 8ff0cb6495d32ec0945dae3ec955f535392713df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Tue, 8 Mar 2016 22:17:56 +0100 Subject: [PATCH 276/444] include implicit grant example --- examples/public/implicit.php | 66 ++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 examples/public/implicit.php diff --git a/examples/public/implicit.php b/examples/public/implicit.php new file mode 100644 index 00000000..a9313017 --- /dev/null +++ b/examples/public/implicit.php @@ -0,0 +1,66 @@ + [ + 'displayErrorDetails' => true, + ], + Server::class => function () { + // Init our repositories + $clientRepository = new ClientRepository(); + $scopeRepository = new ScopeRepository(); + $accessTokenRepository = new AccessTokenRepository(); + $userRepository = new UserRepository(); + + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + + // Setup the authorization server + $server = new Server( + $clientRepository, + $accessTokenRepository, + $scopeRepository, + $privateKeyPath, + $publicKeyPath + ); + + // Enable the implicit grant on the server with a token TTL of 1 hour + $server->enableGrantType( + new ImplicitGrant($userRepository), + new \DateInterval('PT1H') + ); + + return $server; + }, +]); + +$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->run(); From 1218cede79fb6e48dfb48bdfba661fc89d21b8ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Wed, 9 Mar 2016 12:32:01 +0100 Subject: [PATCH 277/444] allow different template engines --- composer.json | 5 +- src/Grant/AbstractAuthorizeGrant.php | 90 ++++++++++++++++++++++ src/Grant/AuthCodeGrant.php | 69 +++++------------ src/Grant/ImplicitGrant.php | 71 +++++------------ src/TemplateRenderer/MustacheRenderer.php | 39 ++++++++++ src/TemplateRenderer/PlatesRenderer.php | 43 +++++++++++ src/TemplateRenderer/RendererInterface.php | 22 ++++++ src/TemplateRenderer/SmartyRenderer.php | 45 +++++++++++ src/TemplateRenderer/TwigRenderer.php | 39 ++++++++++ 9 files changed, 323 insertions(+), 100 deletions(-) create mode 100644 src/Grant/AbstractAuthorizeGrant.php create mode 100644 src/TemplateRenderer/MustacheRenderer.php create mode 100644 src/TemplateRenderer/PlatesRenderer.php create mode 100644 src/TemplateRenderer/RendererInterface.php create mode 100644 src/TemplateRenderer/SmartyRenderer.php create mode 100644 src/TemplateRenderer/TwigRenderer.php diff --git a/composer.json b/composer.json index 67e551a9..1c129543 100644 --- a/composer.json +++ b/composer.json @@ -64,6 +64,9 @@ } }, "suggest": { - "league/plates": "Required for parsing authorization code templates" + "league/plates": "Used for parsing authorization code templates", + "twig/twig": "Used for parsing authorization code templates", + "smarty/smarty": "Used for parsing authorization code templates", + "mustache/mustache": "Used for parsing authorization code templates" } } diff --git a/src/Grant/AbstractAuthorizeGrant.php b/src/Grant/AbstractAuthorizeGrant.php new file mode 100644 index 00000000..9914e989 --- /dev/null +++ b/src/Grant/AbstractAuthorizeGrant.php @@ -0,0 +1,90 @@ + + * @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\TemplateRenderer\PlatesRenderer; +use League\OAuth2\Server\TemplateRenderer\RendererInterface; +use League\Plates\Engine; + +abstract class AbstractAuthorizeGrant extends AbstractGrant +{ + /** + * @var null|\League\OAuth2\Server\TemplateRenderer\RendererInterface + */ + protected $templateRenderer; + + /** + * @var null|string + */ + protected $loginTemplate; + + /** + * @var null|string + */ + protected $authorizeTemplate; + + /** + * @param array $data + * + * @return string + */ + protected function renderLoginTemplate(array $data = []) + { + return $this->getTemplateRenderer()->render($this->getLoginTemplate(), $data); + } + + /** + * @param array $data + * + * @return string + */ + protected function renderAuthorizeTemplate(array $data = []) + { + return $this->getTemplateRenderer()->render($this->getAuthorizeTemplate(), $data); + } + + /** + * @return \League\OAuth2\Server\TemplateRenderer\RendererInterface + */ + protected function getTemplateRenderer() + { + if (!$this->templateRenderer instanceof RendererInterface) { + $this->templateRenderer = new PlatesRenderer(new Engine(__DIR__ . '/../ResponseTypes/DefaultTemplates')); + } + + return $this->templateRenderer; + } + + /** + * @return string + */ + protected function getLoginTemplate() + { + if (empty($this->loginTemplate)) { + $this->loginTemplate = 'login_user'; + } + + return $this->loginTemplate; + } + + /** + * @return string + */ + protected function getAuthorizeTemplate() + { + if (empty($this->authorizeTemplate)) { + $this->authorizeTemplate = 'authorize_client'; + } + + return $this->authorizeTemplate; + } +} diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 4d253488..3ee979b2 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -11,13 +11,13 @@ use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; +use League\OAuth2\Server\TemplateRenderer\RendererInterface; use League\OAuth2\Server\Utils\KeyCrypt; -use League\Plates\Engine; use Psr\Http\Message\ServerRequestInterface; use Zend\Diactoros\Response; use Zend\Diactoros\Uri; -class AuthCodeGrant extends AbstractGrant +class AuthCodeGrant extends AbstractAuthorizeGrant { /** * @var \DateInterval @@ -29,51 +29,32 @@ class AuthCodeGrant extends AbstractGrant */ private $userRepository; - /** - * @var null|string - */ - private $pathToLoginTemplate; - - /** - * @var null|string - */ - private $pathToAuthorizeTemplate; - /** * @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository * @param \DateInterval $authCodeTTL - * @param string|null $pathToLoginTemplate - * @param string|null $pathToAuthorizeTemplate + * @param string|null $loginTemplate + * @param string|null $authorizeTemplate + * @param \League\OAuth2\Server\TemplateRenderer\RendererInterface|null $templateRenderer */ public function __construct( AuthCodeRepositoryInterface $authCodeRepository, RefreshTokenRepositoryInterface $refreshTokenRepository, UserRepositoryInterface $userRepository, \DateInterval $authCodeTTL, - $pathToLoginTemplate = null, - $pathToAuthorizeTemplate = null + $loginTemplate = null, + $authorizeTemplate = null, + RendererInterface $templateRenderer = null ) { $this->setAuthCodeRepository($authCodeRepository); $this->setRefreshTokenRepository($refreshTokenRepository); $this->userRepository = $userRepository; $this->authCodeTTL = $authCodeTTL; $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; - } + $this->loginTemplate = $loginTemplate; + $this->authorizeTemplate = $authorizeTemplate; + $this->templateRenderer = $templateRenderer; } /** @@ -164,31 +145,21 @@ 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( - end($pathParts), - [ - 'error' => $loginError, - 'postback_uri' => (string) $postbackUri->withQuery($queryString), - ] - ); + $html = $this->renderLoginTemplate([ + '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), - ] - ); + $html = $this->renderAuthorizeTemplate([ + 'client' => $client, + 'scopes' => $scopes, + 'postback_uri' => (string) $postbackUri->withQuery($queryString), + ]); return new Response\HtmlResponse( $html, diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 8123550e..341ef8a0 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -7,14 +7,14 @@ use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\TemplateRenderer\RendererInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\Utils\KeyCrypt; -use League\Plates\Engine; use Psr\Http\Message\ServerRequestInterface; use Zend\Diactoros\Response; use Zend\Diactoros\Uri; -class ImplicitGrant extends AbstractGrant +class ImplicitGrant extends AbstractAuthorizeGrant { /** * @var \League\OAuth2\Server\Repositories\UserRepositoryInterface @@ -22,41 +22,22 @@ class ImplicitGrant extends AbstractGrant private $userRepository; /** - * @var null|string - */ - private $pathToLoginTemplate; - - /** - * @var null|string - */ - private $pathToAuthorizeTemplate; - - /** - * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository - * @param string|null $pathToLoginTemplate - * @param string|null $pathToAuthorizeTemplate + * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository + * @param string|null $loginTemplate + * @param string|null $authorizeTemplate + * @param \League\OAuth2\Server\TemplateRenderer\RendererInterface|null $templateRenderer */ public function __construct( UserRepositoryInterface $userRepository, - $pathToLoginTemplate = null, - $pathToAuthorizeTemplate = null + $loginTemplate = null, + $authorizeTemplate = null, + RendererInterface $templateRenderer = null ) { $this->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; - } + $this->loginTemplate = $loginTemplate; + $this->authorizeTemplate = $authorizeTemplate; + $this->templateRenderer = $templateRenderer; } /** @@ -164,31 +145,21 @@ class ImplicitGrant 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( - end($pathParts), - [ - 'error' => $loginError, - 'postback_uri' => (string) $postbackUri->withQuery($queryString), - ] - ); + $html = $this->renderLoginTemplate([ + '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), - ] - ); + $html = $this->renderAuthorizeTemplate([ + 'client' => $client, + 'scopes' => $scopes, + 'postback_uri' => (string) $postbackUri->withQuery($queryString), + ]); return new Response\HtmlResponse( $html, diff --git a/src/TemplateRenderer/MustacheRenderer.php b/src/TemplateRenderer/MustacheRenderer.php new file mode 100644 index 00000000..e5287eac --- /dev/null +++ b/src/TemplateRenderer/MustacheRenderer.php @@ -0,0 +1,39 @@ + + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ +namespace League\OAuth2\Server\TemplateRenderer; + +use Mustache_Engine; + +class MustacheRenderer implements RendererInterface +{ + /** + * @var \Mustache_Engine + */ + private $engine; + + /** + * TwigRenderer constructor. + * + * @param \Mustache_Engine $engine + */ + public function __construct(Mustache_Engine $engine) + { + $this->engine = $engine; + } + + /** + * {@inheritdoc} + */ + public function render($template, array $data = []) + { + return $this->engine->render($template, $data); + } +} diff --git a/src/TemplateRenderer/PlatesRenderer.php b/src/TemplateRenderer/PlatesRenderer.php new file mode 100644 index 00000000..114815af --- /dev/null +++ b/src/TemplateRenderer/PlatesRenderer.php @@ -0,0 +1,43 @@ + + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ +namespace League\OAuth2\Server\TemplateRenderer; + +use League\Plates\Engine; + +class PlatesRenderer implements RendererInterface +{ + /** + * @var \League\Plates\Engine + */ + private $engine; + + /** + * PlatesRenderer constructor. + * + * @param \League\Plates\Engine $engine + */ + public function __construct(Engine $engine) + { + $this->engine = $engine; + } + + /** + * {@inheritdoc} + */ + public function render($template, array $data = []) + { + if ($this->engine->getFileExtension()) { + $template = preg_replace(sprintf('/\.%s$/', $this->engine->getFileExtension()), '', $template); + } + + return $this->engine->render($template, $data); + } +} diff --git a/src/TemplateRenderer/RendererInterface.php b/src/TemplateRenderer/RendererInterface.php new file mode 100644 index 00000000..676334ab --- /dev/null +++ b/src/TemplateRenderer/RendererInterface.php @@ -0,0 +1,22 @@ + + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ +namespace League\OAuth2\Server\TemplateRenderer; + +interface RendererInterface +{ + /** + * @param string $template + * @param array $data + * + * @return string + */ + public function render($template, array $data = []); +} diff --git a/src/TemplateRenderer/SmartyRenderer.php b/src/TemplateRenderer/SmartyRenderer.php new file mode 100644 index 00000000..a54a4719 --- /dev/null +++ b/src/TemplateRenderer/SmartyRenderer.php @@ -0,0 +1,45 @@ + + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ +namespace League\OAuth2\Server\TemplateRenderer; + +use Smarty; + +class SmartyRenderer implements RendererInterface +{ + /** + * Smarty class. + * + * @var \Smarty + */ + private $smarty; + + /** + * @param \Smarty $smarty + */ + public function __construct(Smarty $smarty) + { + $this->smarty = $smarty; + } + + /** + * {@inheritdoc} + */ + public function render($template, array $data = []) + { + $this->smarty->assign($data); + + $output = $this->smarty->fetch($template); + + $this->smarty->clear_assign(array_keys($data)); + + return $output; + } +} diff --git a/src/TemplateRenderer/TwigRenderer.php b/src/TemplateRenderer/TwigRenderer.php new file mode 100644 index 00000000..ae44a2a7 --- /dev/null +++ b/src/TemplateRenderer/TwigRenderer.php @@ -0,0 +1,39 @@ + + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ +namespace League\OAuth2\Server\TemplateRenderer; + +use Twig_Environment; + +class PlatesRenderer implements RendererInterface +{ + /** + * @var \Twig_Environment + */ + private $environment; + + /** + * TwigRenderer constructor. + * + * @param \Twig_Environment $environment + */ + public function __construct(Twig_Environment $environment) + { + $this->environment = $environment; + } + + /** + * {@inheritdoc} + */ + public function render($template, array $data = []) + { + return $this->environment->loadTemplate($template)->render($data); + } +} From 320d9e65d589f004835e81dbc00be39c7d182fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Wed, 9 Mar 2016 12:44:47 +0100 Subject: [PATCH 278/444] StyleCI always watching upon us --- src/Grant/ImplicitGrant.php | 2 +- src/TemplateRenderer/TwigRenderer.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 341ef8a0..56124305 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -7,8 +7,8 @@ use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\UserRepositoryInterface; -use League\OAuth2\Server\TemplateRenderer\RendererInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; +use League\OAuth2\Server\TemplateRenderer\RendererInterface; use League\OAuth2\Server\Utils\KeyCrypt; use Psr\Http\Message\ServerRequestInterface; use Zend\Diactoros\Response; diff --git a/src/TemplateRenderer/TwigRenderer.php b/src/TemplateRenderer/TwigRenderer.php index ae44a2a7..37e3f565 100644 --- a/src/TemplateRenderer/TwigRenderer.php +++ b/src/TemplateRenderer/TwigRenderer.php @@ -12,7 +12,7 @@ namespace League\OAuth2\Server\TemplateRenderer; use Twig_Environment; -class PlatesRenderer implements RendererInterface +class TwigRenderer implements RendererInterface { /** * @var \Twig_Environment From 01517bb57ab8406adf2e70a35127da4301426238 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 10 Mar 2016 15:09:56 +0000 Subject: [PATCH 279/444] Added missing namespace --- src/Entities/AccessTokenEntity.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Entities/AccessTokenEntity.php b/src/Entities/AccessTokenEntity.php index 75bcb4c6..fc31a9fd 100644 --- a/src/Entities/AccessTokenEntity.php +++ b/src/Entities/AccessTokenEntity.php @@ -3,6 +3,7 @@ namespace League\OAuth2\Server\Entities; use Lcobucci\JWT\Builder; +use Lcobucci\JWT\Signer\Key; use Lcobucci\JWT\Signer\Rsa\Sha256; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Traits\EntityTrait; From 721a31534e3d9adc8bad107c2d5f539425cd2e46 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 10 Mar 2016 15:10:08 +0000 Subject: [PATCH 280/444] Added implicit grant test --- tests/Grant/ImplicitGrantTest.php | 453 ++++++++++++++++++++++++++++++ 1 file changed, 453 insertions(+) create mode 100644 tests/Grant/ImplicitGrantTest.php diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php new file mode 100644 index 00000000..592d0df0 --- /dev/null +++ b/tests/Grant/ImplicitGrantTest.php @@ -0,0 +1,453 @@ +getMock(UserRepositoryInterface::class), + 'foo/bar.php', + 'foo/bar.php' + ); + + $this->assertEquals('implicit', $grant->getIdentifier()); + } + + public function testCanRespondToRequest() + { + $grant = new ImplicitGrant( + $this->getMock(UserRepositoryInterface::class), + 'foo/bar.php', + 'foo/bar.php' + ); + + $request = new ServerRequest( + [], + [], + null, + null, + 'php://input', + [], + [], + [ + 'response_type' => 'token' + ] + ); + + $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); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $grant = new ImplicitGrant($userRepositoryMock, 'foo', 'foo'); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $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', + [], + [], + [ + 'response_type' => 'token', + '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); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 3 + */ + public function testRespondToAuthorizationRequestMissingClientId() + { + $grant = new ImplicitGrant( + $this->getMock(UserRepositoryInterface::class), + 'foo/bar.php', + 'foo/bar.php' + ); + $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' => 'token', + ], + [ + '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); + + $grant = new ImplicitGrant( + $this->getMock(UserRepositoryInterface::class), + 'foo/bar.php', + 'foo/bar.php' + ); + $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' => 'token', + '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 ImplicitGrant( + $this->getMock(UserRepositoryInterface::class), + 'foo/bar.php', + 'foo/bar.php' + ); + $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' => 'token', + '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 ImplicitGrant( + $this->getMock(UserRepositoryInterface::class), + 'foo/bar.php', + 'foo/bar.php' + ); + $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' => 'token', + '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 ImplicitGrant($this->getMock(UserRepositoryInterface::class)); + $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' => 'token', + '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 ImplicitGrant($this->getMock(UserRepositoryInterface::class)); + $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 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 ImplicitGrant($this->getMock(UserRepositoryInterface::class)); + $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); + } +} From 5074ad9a6ca7be14c1b3a3323c0c62c5ea5b3479 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 10 Mar 2016 15:49:57 +0000 Subject: [PATCH 281/444] Fixed request attribute --- src/ResponseTypes/BearerTokenResponse.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index fdbe73b0..643c1917 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -87,7 +87,8 @@ class BearerTokenResponse extends AbstractResponseType } // Return the request with additional attributes - return $request->withAttribute('oauth_access_token', $token->getClaim('jti')) + return $request + ->withAttribute('oauth_access_token_id', $token->getClaim('jti')) ->withAttribute('oauth_client_id', $token->getClaim('aud')) ->withAttribute('oauth_user_id', $token->getClaim('sub')) ->withAttribute('oauth_scopes', $token->getClaim('scopes')); From 021663890369b37571892d5a165a786e8f38d9ce Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 10 Mar 2016 15:50:17 +0000 Subject: [PATCH 282/444] Added BearerResponseType test --- .../ResponseTypes/BearerResponseTypeTest.php | 214 ++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 tests/ResponseTypes/BearerResponseTypeTest.php diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php new file mode 100644 index 00000000..8a960214 --- /dev/null +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -0,0 +1,214 @@ +getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + + $responseType = new BearerTokenResponse( + 'file://' . __DIR__ . '/../Utils/private.key', + 'file://' . __DIR__ . '/../Utils/public.key', + $accessTokenRepositoryMock + ); + + $client = new ClientEntity(); + $client->setIdentifier('clientName'); + + $accessToken = new AccessTokenEntity(); + $accessToken->setIdentifier('abcdef'); + $accessToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H'))); + $accessToken->setClient($client); + + $refreshToken = new RefreshTokenEntity(); + $refreshToken->setIdentifier('abcdef'); + $refreshToken->setAccessToken($accessToken); + $refreshToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H'))); + + $responseType->setAccessToken($accessToken); + $responseType->setRefreshToken($refreshToken); + + $response = $responseType->generateHttpResponse(new Response()); + + $this->assertTrue($response instanceof ResponseInterface); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('no-cache', $response->getHeader('pragma')[0]); + $this->assertEquals('no-store', $response->getHeader('cache-control')[0]); + $this->assertEquals('application/json; charset=UTF-8', $response->getHeader('content-type')[0]); + + $response->getBody()->rewind(); + $json = json_decode($response->getBody()->getContents()); + $this->assertEquals('Bearer', $json->token_type); + $this->assertTrue(isset($json->expires_in)); + $this->assertTrue(isset($json->access_token)); + $this->assertTrue(isset($json->refresh_token)); + } + + public function testDetermineAccessTokenInHeaderValidToken() + { + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + + $responseType = new BearerTokenResponse( + 'file://' . __DIR__ . '/../Utils/private.key', + 'file://' . __DIR__ . '/../Utils/public.key', + $accessTokenRepositoryMock + ); + + $client = new ClientEntity(); + $client->setIdentifier('clientName'); + + $accessToken = new AccessTokenEntity(); + $accessToken->setIdentifier('abcdef'); + $accessToken->setUserIdentifier(123); + $accessToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H'))); + $accessToken->setClient($client); + + $refreshToken = new RefreshTokenEntity(); + $refreshToken->setIdentifier('abcdef'); + $refreshToken->setAccessToken($accessToken); + $refreshToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H'))); + + $responseType->setAccessToken($accessToken); + $responseType->setRefreshToken($refreshToken); + + $response = $responseType->generateHttpResponse(new Response()); + $response->getBody()->rewind(); + $json = json_decode($response->getBody()->getContents()); + + $request = new ServerRequest(); + $request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token)); + + $request = $responseType->determineAccessTokenInHeader($request); + + $this->assertEquals('abcdef', $request->getAttribute('oauth_access_token_id')); + $this->assertEquals('clientName', $request->getAttribute('oauth_client_id')); + $this->assertEquals('123', $request->getAttribute('oauth_user_id')); + $this->assertEquals([], $request->getAttribute('oauth_scopes')); + } + + public function testDetermineAccessTokenInHeaderInvalidJWT() + { + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + + $responseType = new BearerTokenResponse( + 'file://' . __DIR__ . '/../Utils/private.key', + 'file://' . __DIR__ . '/../Utils/public.key', + $accessTokenRepositoryMock + ); + + $client = new ClientEntity(); + $client->setIdentifier('clientName'); + + $accessToken = new AccessTokenEntity(); + $accessToken->setIdentifier('abcdef'); + $accessToken->setUserIdentifier(123); + $accessToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H'))); + $accessToken->setClient($client); + + $refreshToken = new RefreshTokenEntity(); + $refreshToken->setIdentifier('abcdef'); + $refreshToken->setAccessToken($accessToken); + $refreshToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H'))); + + $responseType->setAccessToken($accessToken); + $responseType->setRefreshToken($refreshToken); + + $response = $responseType->generateHttpResponse(new Response()); + $response->getBody()->rewind(); + $json = json_decode($response->getBody()->getContents()); + + $request = new ServerRequest(); + $request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token.'foo')); + + try { + $responseType->determineAccessTokenInHeader($request); + } catch (OAuthServerException $e) { + $this->assertEquals( + 'Access token could not be verified', + $e->getHint() + ); + } + } + + public function testDetermineAccessTokenInHeaderRevokedToken() + { + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->expects($this->once())->method('isAccessTokenRevoked')->willReturn(true); + + + $responseType = new BearerTokenResponse( + 'file://' . __DIR__ . '/../Utils/private.key', + 'file://' . __DIR__ . '/../Utils/public.key', + $accessTokenRepositoryMock + ); + + $client = new ClientEntity(); + $client->setIdentifier('clientName'); + + $accessToken = new AccessTokenEntity(); + $accessToken->setIdentifier('abcdef'); + $accessToken->setUserIdentifier(123); + $accessToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H'))); + $accessToken->setClient($client); + + $refreshToken = new RefreshTokenEntity(); + $refreshToken->setIdentifier('abcdef'); + $refreshToken->setAccessToken($accessToken); + $refreshToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H'))); + + $responseType->setAccessToken($accessToken); + $responseType->setRefreshToken($refreshToken); + + $response = $responseType->generateHttpResponse(new Response()); + $response->getBody()->rewind(); + $json = json_decode($response->getBody()->getContents()); + + $request = new ServerRequest(); + $request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token)); + + try { + $responseType->determineAccessTokenInHeader($request); + } catch (OAuthServerException $e) { + $this->assertEquals( + 'Access token has been revoked', + $e->getHint() + ); + } + } + + public function testDetermineAccessTokenInHeaderInvalidToken() + { + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + + $responseType = new BearerTokenResponse( + 'file://' . __DIR__ . '/../Utils/private.key', + 'file://' . __DIR__ . '/../Utils/public.key', + $accessTokenRepositoryMock + ); + + $request = new ServerRequest(); + $request = $request->withHeader('authorization', 'Bearer blah'); + + try { + $responseType->determineAccessTokenInHeader($request); + } catch (OAuthServerException $e) { + $this->assertEquals( + 'The JWT string must have two dots', + $e->getHint() + ); + } + } +} From fb1fa71b5deaba1e370ee4c746f7595e6c5b5573 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 10 Mar 2016 16:34:21 +0000 Subject: [PATCH 283/444] Improved BearerResponseType test --- tests/ResponseTypes/BearerResponseTypeTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index 8a960214..b5ca3ebb 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -5,6 +5,7 @@ namespace LeagueTests\ResponseTypes; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\ClientEntity; 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\ResponseTypes\BearerTokenResponse; @@ -28,10 +29,14 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $client = new ClientEntity(); $client->setIdentifier('clientName'); + $scope = new ScopeEntity(); + $scope->setIdentifier('basic'); + $accessToken = new AccessTokenEntity(); $accessToken->setIdentifier('abcdef'); $accessToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H'))); $accessToken->setClient($client); + $accessToken->addScope($scope); $refreshToken = new RefreshTokenEntity(); $refreshToken->setIdentifier('abcdef'); From 8f0cb0e78cc1a48c41b4dbfec0aef53af53c3e2a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 10 Mar 2016 16:34:32 +0000 Subject: [PATCH 284/444] Updated server test --- tests/ServerTest.php | 84 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 3f823a17..2251258a 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -3,13 +3,21 @@ namespace LeagueTests; use League\OAuth2\Server\Entities\ClientEntity; +use League\OAuth2\Server\Exception\OAuthServerException; +use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\ClientCredentialsGrant; 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\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use League\OAuth2\Server\Server; use LeagueTests\Stubs\StubResponseType; +use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; +use Zend\Diactoros\ServerRequest; class ServerTest extends \PHPUnit_Framework_TestCase { @@ -53,4 +61,80 @@ class ServerTest extends \PHPUnit_Framework_TestCase $response = $server->respondToRequest(); $this->assertEquals(200, $response->getStatusCode()); } + + public function testRespondToRequestPsrResponse() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setIdentifier('http://bar.com'); + + $clientRepository = $this->getMock(ClientRepositoryInterface::class); + $clientRepository->method('getClientEntity')->willReturn($client); + + $server = new Server( + $clientRepository, + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + '', + '', + new StubResponseType() + ); + + $server->enableGrantType( + new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $this->getMock(UserRepositoryInterface::class), + new \DateInterval('PT1H') + ), + new \DateInterval('PT1M') + ); + + $_SERVER['HTTP_HOST'] = 'http://auth.com'; + $_SERVER['REQUEST_URI'] = '/auth'; + $_GET['response_type'] = 'code'; + $_GET['client_id'] = $client->getIdentifier(); + $_GET['redirect_uri'] = $client->getRedirectUri(); + $response = $server->respondToRequest(); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertTrue($response instanceof ResponseInterface); + } + + public function testGetResponseType() + { + $clientRepository = $this->getMock(ClientRepositoryInterface::class); + + $server = new Server( + $clientRepository, + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + '', + '' + ); + + $abstractGrantReflection = new \ReflectionClass($server); + $method = $abstractGrantReflection->getMethod('getResponseType'); + $method->setAccessible(true); + + $this->assertTrue($method->invoke($server) instanceof BearerTokenResponse); + } + + public function testValidateRequest() + { + $clientRepository = $this->getMock(ClientRepositoryInterface::class); + + $server = new Server( + $clientRepository, + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + '', + '' + ); + + try { + $server->validateRequest(new ServerRequest()); + } catch (OAuthServerException $e) { + $this->assertEquals('Missing "Authorization" header', $e->getHint()); + } + } } From 3b4a8cf5f3a383aade5ea512018733e2bf767a92 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 10 Mar 2016 17:22:10 +0000 Subject: [PATCH 285/444] Added code coverage ignore comments --- src/Middleware/AuthenticationServerMiddleware.php | 2 ++ src/Middleware/ResourceServerMiddleware.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/Middleware/AuthenticationServerMiddleware.php b/src/Middleware/AuthenticationServerMiddleware.php index 2dd553e3..8a68527d 100644 --- a/src/Middleware/AuthenticationServerMiddleware.php +++ b/src/Middleware/AuthenticationServerMiddleware.php @@ -38,11 +38,13 @@ class AuthenticationServerMiddleware $response = $this->server->respondToRequest($request, $response); } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); + // @codeCoverageIgnoreStart } catch (\Exception $exception) { $body = new Stream('php://temp', 'r+'); $body->write($exception->getMessage()); return $response->withStatus(500)->withBody($body); + // @codeCoverageIgnoreEnd } if (in_array($response->getStatusCode(), [400, 401, 500])) { diff --git a/src/Middleware/ResourceServerMiddleware.php b/src/Middleware/ResourceServerMiddleware.php index 0f0b20ae..65d6e8e4 100644 --- a/src/Middleware/ResourceServerMiddleware.php +++ b/src/Middleware/ResourceServerMiddleware.php @@ -38,11 +38,13 @@ class ResourceServerMiddleware $request = $this->server->validateRequest($request); } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); + // @codeCoverageIgnoreStart } catch (\Exception $exception) { $body = new Stream('php://temp', 'r+'); $body->write($exception->getMessage()); return $response->withStatus(500)->withBody($body); + // @codeCoverageIgnoreEnd } // Pass the request and response on to the next responder in the chain From a716a08be6855670e7a1db0d66a17c35179090ad Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 10 Mar 2016 17:22:38 +0000 Subject: [PATCH 286/444] Completed stub response --- tests/Stubs/StubResponseType.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/Stubs/StubResponseType.php b/tests/Stubs/StubResponseType.php index 22d093a0..74385303 100644 --- a/tests/Stubs/StubResponseType.php +++ b/tests/Stubs/StubResponseType.php @@ -4,6 +4,7 @@ namespace LeagueTests\Stubs; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\ResponseTypes\AbstractResponseType; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -44,11 +45,16 @@ class StubResponseType extends AbstractResponseType /** * @param ServerRequestInterface $request * - * @return ServerRequestInterface + * @return \Psr\Http\Message\ServerRequestInterface + * @throws \League\OAuth2\Server\Exception\OAuthServerException */ public function determineAccessTokenInHeader(ServerRequestInterface $request) { - // TODO: Implement determineAccessTokenInHeader() method. + if ($request->getHeader('authorization')[0] === 'Basic test') { + return $request->withAttribute('oauth_access_token_id', 'test'); + } + + throw OAuthServerException::accessDenied(); } /** From c490cd4ef28ff8ed7a5f3f92d4c8b5ca6134cf55 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 10 Mar 2016 17:22:48 +0000 Subject: [PATCH 287/444] Added middleware tests --- .../AuthenticationServerMiddlewareTest.php | 85 +++++++++++++++++++ .../ResourceServerMiddlewareTest.php | 73 ++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 tests/Middleware/AuthenticationServerMiddlewareTest.php create mode 100644 tests/Middleware/ResourceServerMiddlewareTest.php diff --git a/tests/Middleware/AuthenticationServerMiddlewareTest.php b/tests/Middleware/AuthenticationServerMiddlewareTest.php new file mode 100644 index 00000000..ca2c430a --- /dev/null +++ b/tests/Middleware/AuthenticationServerMiddlewareTest.php @@ -0,0 +1,85 @@ +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'; + + $request = ServerRequestFactory::fromGlobals(); + + $middleware = new AuthenticationServerMiddleware($server); + $response = $middleware->__invoke( + $request, + new Response(), + function () { + return func_get_args()[1]; + } + ); + $this->assertEquals(200, $response->getStatusCode()); + } + + public function testOAuthErrorResponse() + { + $clientRepository = $this->getMock(ClientRepositoryInterface::class); + $clientRepository->method('getClientEntity')->willReturn(null); + + $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'; + + $request = ServerRequestFactory::fromGlobals(); + + $middleware = new AuthenticationServerMiddleware($server); + + $response = $middleware->__invoke( + $request, + new Response(), + function () { + return func_get_args()[1]; + } + ); + + $this->assertEquals(401, $response->getStatusCode()); + } +} diff --git a/tests/Middleware/ResourceServerMiddlewareTest.php b/tests/Middleware/ResourceServerMiddlewareTest.php new file mode 100644 index 00000000..37c6287f --- /dev/null +++ b/tests/Middleware/ResourceServerMiddlewareTest.php @@ -0,0 +1,73 @@ +getMock(ClientRepositoryInterface::class); + + $server = new Server( + $clientRepository, + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + '', + '', + new StubResponseType() + ); + + $request = new ServerRequest(); + $request = $request->withHeader('authorization', 'Basic test'); + + $middleware = new ResourceServerMiddleware($server); + $response = $middleware->__invoke( + $request, + new Response(), + function () { + $this->assertEquals('test', func_get_args()[0]->getAttribute('oauth_access_token_id')); + return func_get_args()[1]; + } + ); + + $this->assertEquals(200, $response->getStatusCode()); + } + + public function testErrorResponse() + { + $clientRepository = $this->getMock(ClientRepositoryInterface::class); + + $server = new Server( + $clientRepository, + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + '', + '', + new StubResponseType() + ); + + $request = new ServerRequest(); + $request = $request->withHeader('authorization', ''); + + $middleware = new ResourceServerMiddleware($server); + $response = $middleware->__invoke( + $request, + new Response(), + function () { + return func_get_args()[1]; + } + ); + + $this->assertEquals(401, $response->getStatusCode()); + } + +} From edf0ee862241df736d9f6f850ace7464e9186e90 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 10 Mar 2016 17:34:25 +0000 Subject: [PATCH 288/444] Removed unused code --- src/Entities/Interfaces/TokenInterface.php | 9 --------- src/Entities/Traits/TokenEntityTrait.php | 12 ------------ src/Exception/OAuthServerException.php | 16 +--------------- .../AuthenticationServerMiddleware.php | 4 ---- 4 files changed, 1 insertion(+), 40 deletions(-) diff --git a/src/Entities/Interfaces/TokenInterface.php b/src/Entities/Interfaces/TokenInterface.php index dfa4e44e..a78db090 100644 --- a/src/Entities/Interfaces/TokenInterface.php +++ b/src/Entities/Interfaces/TokenInterface.php @@ -67,15 +67,6 @@ interface TokenInterface */ public function addScope(ScopeEntityInterface $scope); - /** - * Get an associated scope by the scope's identifier. - * - * @param string $identifier - * - * @return ScopeEntityInterface|null The scope or null if not found - */ - public function getScopeWithIdentifier($identifier); - /** * Return an array of scopes associated with the token. * diff --git a/src/Entities/Traits/TokenEntityTrait.php b/src/Entities/Traits/TokenEntityTrait.php index 35230b26..e7b9d29f 100644 --- a/src/Entities/Traits/TokenEntityTrait.php +++ b/src/Entities/Traits/TokenEntityTrait.php @@ -38,18 +38,6 @@ trait TokenEntityTrait $this->scopes[$scope->getIdentifier()] = $scope; } - /** - * Get an associated scope by the scope's identifier. - * - * @param string $identifier - * - * @return ScopeEntityInterface|null The scope or null if not found - */ - public function getScopeWithIdentifier($identifier) - { - return (isset($this->scopes[$identifier])) ? $this->scopes[$identifier] : null; - } - /** * Return an array of scopes associated with the token. * diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 7b8a1016..b61d1183 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -48,20 +48,6 @@ class OAuthServerException extends \Exception $this->redirectUri = $redirectUri; } - /** - * Invalid grant type error. - * - * @return static - */ - 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, 1, 'invalid_grant', 400, $hint); - } - /** * Unsupported grant type error. * @@ -206,7 +192,7 @@ class OAuthServerException extends \Exception $headers = $this->getHttpHeaders(); $payload = [ - 'error' => $this->errorType, + 'error' => $this->getErrorType(), 'message' => $this->getMessage(), ]; diff --git a/src/Middleware/AuthenticationServerMiddleware.php b/src/Middleware/AuthenticationServerMiddleware.php index 8a68527d..4038d95e 100644 --- a/src/Middleware/AuthenticationServerMiddleware.php +++ b/src/Middleware/AuthenticationServerMiddleware.php @@ -47,10 +47,6 @@ class AuthenticationServerMiddleware // @codeCoverageIgnoreEnd } - if (in_array($response->getStatusCode(), [400, 401, 500])) { - return $response; - } - // Pass the request and response on to the next responder in the chain return $next($request, $response); } From f7f3cdee2483e89078d610379a9bf3b8eacdfdae Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 10 Mar 2016 17:34:36 +0000 Subject: [PATCH 289/444] Use client->setName method --- tests/Grant/AuthCodeGrantTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 1508329c..2772527d 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -515,6 +515,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase { $client = new ClientEntity(); $client->setRedirectUri('http://foo/bar'); + $client->setName('Test Client'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); From c40a10a07133f014d6dfd3a011925ebfb0be51fb Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 10 Mar 2016 12:40:28 -0500 Subject: [PATCH 290/444] Applied fixes from StyleCI --- tests/Grant/ImplicitGrantTest.php | 2 +- tests/Middleware/ResourceServerMiddlewareTest.php | 2 +- tests/ResponseTypes/BearerResponseTypeTest.php | 3 +-- tests/ServerTest.php | 1 - tests/Stubs/StubResponseType.php | 3 ++- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 592d0df0..85371d82 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -44,7 +44,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase [], [], [ - 'response_type' => 'token' + 'response_type' => 'token', ] ); diff --git a/tests/Middleware/ResourceServerMiddlewareTest.php b/tests/Middleware/ResourceServerMiddlewareTest.php index 37c6287f..590ae438 100644 --- a/tests/Middleware/ResourceServerMiddlewareTest.php +++ b/tests/Middleware/ResourceServerMiddlewareTest.php @@ -35,6 +35,7 @@ class ResourceServerMiddlewareTest extends \PHPUnit_Framework_TestCase new Response(), function () { $this->assertEquals('test', func_get_args()[0]->getAttribute('oauth_access_token_id')); + return func_get_args()[1]; } ); @@ -69,5 +70,4 @@ class ResourceServerMiddlewareTest extends \PHPUnit_Framework_TestCase $this->assertEquals(401, $response->getStatusCode()); } - } diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index b5ca3ebb..b0c35fc6 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -10,7 +10,6 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use Psr\Http\Message\ResponseInterface; -use Zend\Diactoros\Request; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; @@ -136,7 +135,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $json = json_decode($response->getBody()->getContents()); $request = new ServerRequest(); - $request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token.'foo')); + $request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token . 'foo')); try { $responseType->determineAccessTokenInHeader($request); diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 2251258a..38850ec8 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -15,7 +15,6 @@ use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use League\OAuth2\Server\Server; use LeagueTests\Stubs\StubResponseType; -use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Zend\Diactoros\ServerRequest; diff --git a/tests/Stubs/StubResponseType.php b/tests/Stubs/StubResponseType.php index 74385303..5be07f62 100644 --- a/tests/Stubs/StubResponseType.php +++ b/tests/Stubs/StubResponseType.php @@ -45,8 +45,9 @@ class StubResponseType extends AbstractResponseType /** * @param ServerRequestInterface $request * - * @return \Psr\Http\Message\ServerRequestInterface * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \Psr\Http\Message\ServerRequestInterface */ public function determineAccessTokenInHeader(ServerRequestInterface $request) { From 0ae8863322d61296a18c10c7ea789fba36032b4c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 10 Mar 2016 17:45:31 +0000 Subject: [PATCH 291/444] Ignore TemplateRenderer method --- phpunit.xml.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 943b7857..92564086 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -11,6 +11,7 @@ src src/ResponseTypes/DefaultTemplates + src/TemplateRenderer From 6e74de50e5afb4e9b0070d9808fe637ae4628bfc Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 10 Mar 2016 19:01:57 +0000 Subject: [PATCH 292/444] Test fixes --- tests/ResponseTypes/BearerResponseTypeTest.php | 8 ++++---- tests/ServerTest.php | 2 +- tests/Stubs/StubResponseType.php | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index b0c35fc6..de4ac7fa 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -95,7 +95,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest(); $request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token)); - $request = $responseType->determineAccessTokenInHeader($request); + $request = $responseType->validateAccessToken($request); $this->assertEquals('abcdef', $request->getAttribute('oauth_access_token_id')); $this->assertEquals('clientName', $request->getAttribute('oauth_client_id')); @@ -138,7 +138,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token . 'foo')); try { - $responseType->determineAccessTokenInHeader($request); + $responseType->validateAccessToken($request); } catch (OAuthServerException $e) { $this->assertEquals( 'Access token could not be verified', @@ -184,7 +184,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token)); try { - $responseType->determineAccessTokenInHeader($request); + $responseType->validateAccessToken($request); } catch (OAuthServerException $e) { $this->assertEquals( 'Access token has been revoked', @@ -207,7 +207,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $request = $request->withHeader('authorization', 'Bearer blah'); try { - $responseType->determineAccessTokenInHeader($request); + $responseType->validateAccessToken($request); } catch (OAuthServerException $e) { $this->assertEquals( 'The JWT string must have two dots', diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 38850ec8..74d88740 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -131,7 +131,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase ); try { - $server->validateRequest(new ServerRequest()); + $server->validateAuthenticatedRequest(new ServerRequest()); } catch (OAuthServerException $e) { $this->assertEquals('Missing "Authorization" header', $e->getHint()); } diff --git a/tests/Stubs/StubResponseType.php b/tests/Stubs/StubResponseType.php index 5be07f62..04e09d62 100644 --- a/tests/Stubs/StubResponseType.php +++ b/tests/Stubs/StubResponseType.php @@ -49,7 +49,7 @@ class StubResponseType extends AbstractResponseType * * @return \Psr\Http\Message\ServerRequestInterface */ - public function determineAccessTokenInHeader(ServerRequestInterface $request) + public function validateAccessToken(ServerRequestInterface $request) { if ($request->getHeader('authorization')[0] === 'Basic test') { return $request->withAttribute('oauth_access_token_id', 'test'); From a0402f1994608f261a76dacc3b578e8443a70e95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Fri, 11 Mar 2016 00:01:19 +0100 Subject: [PATCH 293/444] throw exception instead of return Response --- src/Server.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Server.php b/src/Server.php index 9d328d3c..13765727 100644 --- a/src/Server.php +++ b/src/Server.php @@ -128,7 +128,8 @@ class Server implements EmitterAwareInterface } $tokenResponse = null; - foreach ($this->enabledGrantTypes as $grantType) { + while ($tokenResponse === null && $grantType = array_shift($this->enabledGrantTypes)) { + /** @var \League\OAuth2\Server\Grant\GrantTypeInterface $grantType */ if ($grantType->canRespondToRequest($request)) { $tokenResponse = $grantType->respondToRequest( $request, @@ -142,11 +143,11 @@ class Server implements EmitterAwareInterface return $tokenResponse; } - if ($tokenResponse instanceof ResponseTypeInterface === false) { - return OAuthServerException::unsupportedGrantType()->generateHttpResponse($response); + if ($tokenResponse instanceof ResponseTypeInterface) { + return $tokenResponse->generateHttpResponse($response); } - return $tokenResponse->generateHttpResponse($response); + throw OAuthServerException::unsupportedGrantType(); } /** From ecad2b98ae1336e7263cdf4dabdd687fb8a827fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Fri, 11 Mar 2016 00:23:29 +0100 Subject: [PATCH 294/444] update invalid grant type test --- tests/ServerTest.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 74d88740..66eadc27 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -33,9 +33,12 @@ class ServerTest extends \PHPUnit_Framework_TestCase $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M')); - $response = $server->respondToRequest(); - $this->assertTrue($response instanceof ResponseInterface); - $this->assertEquals(400, $response->getStatusCode()); + try { + $server->respondToRequest(); + } catch (OAuthServerException $e) { + $this->assertEquals('unsupported_grant_type', $e->getErrorType()); + $this->assertEquals(400, $e->getHttpStatusCode()); + } } public function testRespondToRequest() From ced63e205108f2f4f85f6abebde0abfc187666a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Mon, 14 Mar 2016 00:12:14 +0100 Subject: [PATCH 295/444] allow scopes extraction on GET requests for auth_code and implicit grants --- src/Grant/AbstractGrant.php | 7 +++---- src/Grant/AuthCodeGrant.php | 6 +++++- src/Grant/ClientCredentialsGrant.php | 2 +- src/Grant/ImplicitGrant.php | 6 +++++- src/Grant/PasswordGrant.php | 2 +- src/Grant/RefreshTokenGrant.php | 2 +- tests/Grant/AbstractGrantTest.php | 18 ++---------------- 7 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index f700c57b..9b3592c5 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -226,7 +226,7 @@ abstract class AbstractGrant implements GrantTypeInterface /** * Validate scopes in the request. * - * @param \Psr\Http\Message\ServerRequestInterface $request + * @param string $scopes * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client * @param string $redirectUri * @@ -235,13 +235,12 @@ abstract class AbstractGrant implements GrantTypeInterface * @return \League\OAuth2\Server\Entities\ScopeEntity[] */ public function validateScopes( - ServerRequestInterface $request, + $scopes, ClientEntityInterface $client, $redirectUri = null ) { - $requestedScopes = $this->getRequestParameter('scope', $request); $scopesList = array_filter( - explode(self::SCOPE_DELIMITER_STRING, trim($requestedScopes)), + explode(self::SCOPE_DELIMITER_STRING, trim($scopes)), function ($scope) { return !empty($scope); } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index ca54b824..6f3d6dfb 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -94,7 +94,11 @@ class AuthCodeGrant extends AbstractAuthorizeGrant throw OAuthServerException::invalidClient(); } - $scopes = $this->validateScopes($request, $client, $client->getRedirectUri()); + $scopes = $this->validateScopes( + $this->getQueryStringParameter('scope', $request), + $client, + $client->getRedirectUri() + ); $queryString = http_build_query($request->getQueryParams()); $postbackUri = new Uri( sprintf( diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 6da17f21..1b15defd 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -28,7 +28,7 @@ class ClientCredentialsGrant extends AbstractGrant ) { // Validate request $client = $this->validateClient($request); - $scopes = $this->validateScopes($request, $client); + $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client); // Issue and persist access token $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $client->getIdentifier(), $scopes); diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 56124305..3db1e703 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -94,7 +94,11 @@ class ImplicitGrant extends AbstractAuthorizeGrant throw OAuthServerException::invalidClient(); } - $scopes = $this->validateScopes($request, $client, $client->getRedirectUri()); + $scopes = $this->validateScopes( + $this->getQueryStringParameter('scope', $request), + $client, + $client->getRedirectUri() + ); $queryString = http_build_query($request->getQueryParams()); $postbackUri = new Uri( sprintf( diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 1145e6ab..d7328f71 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -53,7 +53,7 @@ class PasswordGrant extends AbstractGrant // Validate request $client = $this->validateClient($request); $user = $this->validateUser($request); - $scopes = $this->validateScopes($request, $client); + $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client); // Issue and persist new tokens $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $scopes); diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 83ffe5ed..efcc6454 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -44,7 +44,7 @@ class RefreshTokenGrant extends AbstractGrant // Validate request $client = $this->validateClient($request); $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier()); - $scopes = $this->validateScopes($request, $client); + $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client); // If no new scopes are requested then give the access token the original session scopes if (count($scopes) === 0) { diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index a2b764d2..8fbf7626 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -343,14 +343,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); $grantMock->setScopeRepository($scopeRepositoryMock); - $serverRequest = new ServerRequest(); - $serverRequest = $serverRequest->withParsedBody( - [ - 'scope' => 'basic ', - ] - ); - - $this->assertEquals([$scope], $grantMock->validateScopes($serverRequest, new ClientEntity())); + $this->assertEquals([$scope], $grantMock->validateScopes('basic ', new ClientEntity())); } /** @@ -365,14 +358,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); $grantMock->setScopeRepository($scopeRepositoryMock); - $serverRequest = new ServerRequest(); - $serverRequest = $serverRequest->withParsedBody( - [ - 'scope' => 'basic ', - ] - ); - - $grantMock->validateScopes($serverRequest, new ClientEntity()); + $grantMock->validateScopes('basic ', new ClientEntity()); } public function testGenerateUniqueIdentifier() From 9b665f494f4061a70d39c0b42b44e8729ead2c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Mon, 14 Mar 2016 01:00:06 +0100 Subject: [PATCH 296/444] convert JWT to string for http_build_query --- src/Grant/ImplicitGrant.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 56124305..c3541ad3 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -197,7 +197,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant $scopes ); - $redirectPayload['access_token'] = $accessToken->convertToJWT($this->pathToPrivateKey); + $redirectPayload['access_token'] = (string) $accessToken->convertToJWT($this->pathToPrivateKey); $redirectPayload['token_type'] = 'bearer'; $redirectPayload['expires_in'] = time() - $accessToken->getExpiryDateTime()->getTimestamp(); From 592f60de704a11be2fea2d9836e9088144d9d145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Tue, 15 Mar 2016 01:10:47 +0100 Subject: [PATCH 297/444] allways extract scopes from repository --- src/Entities/ClientEntity.php | 15 ---------- src/Grant/AbstractGrant.php | 30 ++++++++----------- src/Grant/AuthCodeGrant.php | 22 ++++++++++---- src/Grant/RefreshTokenGrant.php | 13 ++++++-- tests/Bootstrap.php | 8 ++++- tests/Grant/AbstractGrantTest.php | 4 +-- tests/Grant/AuthCodeGrantTest.php | 10 ++++++- tests/Grant/ClientCredentialsGrantTest.php | 2 +- tests/Grant/ImplicitGrantTest.php | 2 +- tests/Grant/PasswordGrantTest.php | 2 +- tests/Grant/RefreshTokenGrantTest.php | 9 ++++-- .../AuthenticationServerMiddlewareTest.php | 2 +- .../ResponseTypes/BearerResponseTypeTest.php | 4 +-- tests/ServerTest.php | 2 +- .../Stubs/ClientEntity.php | 9 ++++-- {src/Entities => tests/Stubs}/ScopeEntity.php | 8 +---- 16 files changed, 78 insertions(+), 64 deletions(-) delete mode 100644 src/Entities/ClientEntity.php rename src/Entities/Traits/ClientEntityTrait.php => tests/Stubs/ClientEntity.php (82%) rename {src/Entities => tests/Stubs}/ScopeEntity.php (73%) diff --git a/src/Entities/ClientEntity.php b/src/Entities/ClientEntity.php deleted file mode 100644 index d72b6b3f..00000000 --- a/src/Entities/ClientEntity.php +++ /dev/null @@ -1,15 +0,0 @@ -getIdentifier() ); - if (($scope instanceof ScopeEntity) === false) { + if (($scope instanceof ScopeEntityInterface) === false) { throw OAuthServerException::invalidScope($scopeItem, $redirectUri); } @@ -325,10 +324,10 @@ abstract class AbstractGrant implements GrantTypeInterface /** * Issue an access token. * - * @param \DateInterval $tokenTTL - * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client - * @param string $userIdentifier - * @param array $scopes + * @param \DateInterval $tokenTTL + * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client + * @param string $userIdentifier + * @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] $scopes * * @return \League\OAuth2\Server\Entities\AccessTokenEntity */ @@ -345,11 +344,6 @@ abstract class AbstractGrant implements GrantTypeInterface $accessToken->setUserIdentifier($userIdentifier); foreach ($scopes as $scope) { - if (is_string($scope)) { - $s = new ScopeEntity(); - $s->setIdentifier($scope); - $scope = $s; - } $accessToken->addScope($scope); } @@ -361,11 +355,11 @@ abstract class AbstractGrant implements GrantTypeInterface /** * Issue an auth code. * - * @param \DateInterval $tokenTTL - * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client - * @param string $userIdentifier - * @param string $redirectUri - * @param array $scopes + * @param \DateInterval $tokenTTL + * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client + * @param string $userIdentifier + * @param string $redirectUri + * @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] $scopes * * @throws \League\OAuth2\Server\Exception\OAuthServerException * diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 6f3d6dfb..bc65dc9a 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -273,17 +273,27 @@ class AuthCodeGrant extends AbstractAuthorizeGrant if ($authCodePayload->redirect_uri !== $redirectUri) { throw OAuthServerException::invalidRequest('redirect_uri', 'Invalid redirect URI'); } + + $scopes = []; + foreach ($authCodePayload->scopes as $scopeId) { + $scope = $this->scopeRepository->getScopeEntityByIdentifier( + $scopeId, + $this->getIdentifier(), + $client->getIdentifier() + ); + + if (!$scope) { + throw OAuthServerException::invalidScope($scopeId); + } + + $scopes[] = $scope; + } } catch (\LogicException $e) { throw OAuthServerException::invalidRequest('code', 'Cannot decrypt the authorization code'); } // Issue and persist access + refresh tokens - $accessToken = $this->issueAccessToken( - $accessTokenTTL, - $client, - $authCodePayload->user_id, - $authCodePayload->scopes - ); + $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes); $refreshToken = $this->issueRefreshToken($accessToken); // Inject tokens into response type diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index efcc6454..75d1cee4 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -48,9 +48,16 @@ class RefreshTokenGrant extends AbstractGrant // If no new scopes are requested then give the access token the original session scopes if (count($scopes) === 0) { - $scopes = array_map(function ($scopeId) { - $scope = new ScopeEntity(); - $scope->setIdentifier($scopeId); + $scopes = array_map(function ($scopeId) use ($client) { + $scope = $this->scopeRepository->getScopeEntityByIdentifier( + $scopeId, + $this->getIdentifier(), + $client->getIdentifier() + ); + + if (!$scope) { + throw OAuthServerException::invalidScope($scopeId); + } return $scope; }, $oldRefreshToken['scopes']); diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php index 99c00e16..b02cb7be 100644 --- a/tests/Bootstrap.php +++ b/tests/Bootstrap.php @@ -1,5 +1,11 @@ wget http://getcomposer.org/composer.phar\n> php composer.phar install\n"); + $message = << wget http://getcomposer.org/composer.phar +> php composer.phar install +MSG; + + exit($message); } diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 8fbf7626..4820e3a2 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -4,17 +4,17 @@ namespace LeagueTests\Grant; use League\Event\Emitter; use League\OAuth2\Server\Entities\AccessTokenEntity; -use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; -use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Grant\AbstractGrant; 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 LeagueTests\Stubs\ClientEntity; +use LeagueTests\Stubs\ScopeEntity; use Zend\Diactoros\ServerRequest; class AbstractGrantTest extends \PHPUnit_Framework_TestCase diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 2772527d..22323388 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -2,17 +2,20 @@ namespace LeagueTests\Grant; -use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; 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\Repositories\UserRepositoryInterface; use League\OAuth2\Server\Utils\KeyCrypt; +use LeagueTests\Stubs\ClientEntity; +use LeagueTests\Stubs\ScopeEntity; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; use Psr\Http\Message\ResponseInterface; @@ -577,6 +580,10 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $userEntity = new UserEntity(); $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeEntity = new ScopeEntity(); + $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); @@ -590,6 +597,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); + $grant->setScopeRepository($scopeRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); diff --git a/tests/Grant/ClientCredentialsGrantTest.php b/tests/Grant/ClientCredentialsGrantTest.php index c67e889c..7ca1487d 100644 --- a/tests/Grant/ClientCredentialsGrantTest.php +++ b/tests/Grant/ClientCredentialsGrantTest.php @@ -2,11 +2,11 @@ namespace LeagueTests\Grant; -use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; use Zend\Diactoros\ServerRequest; diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 85371d82..9d075a69 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -2,13 +2,13 @@ namespace LeagueTests\Grant; -use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ImplicitGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\Utils\KeyCrypt; +use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; use Psr\Http\Message\ResponseInterface; diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php index e4f9e3a9..d7938b94 100644 --- a/tests/Grant/PasswordGrantTest.php +++ b/tests/Grant/PasswordGrantTest.php @@ -2,7 +2,6 @@ namespace LeagueTests\Grant; -use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Grant\PasswordGrant; @@ -10,6 +9,7 @@ use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; use Zend\Diactoros\ServerRequest; diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index c9edebe2..d6b63203 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -2,16 +2,16 @@ namespace LeagueTests\Grant; -use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; -use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Utils\KeyCrypt; +use LeagueTests\Stubs\ClientEntity; +use LeagueTests\Stubs\ScopeEntity; use LeagueTests\Stubs\StubResponseType; use Zend\Diactoros\ServerRequest; @@ -33,6 +33,10 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeEntity = new ScopeEntity(); + $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); @@ -41,6 +45,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); + $grant->setScopeRepository($scopeRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); diff --git a/tests/Middleware/AuthenticationServerMiddlewareTest.php b/tests/Middleware/AuthenticationServerMiddlewareTest.php index ca2c430a..8fb8a553 100644 --- a/tests/Middleware/AuthenticationServerMiddlewareTest.php +++ b/tests/Middleware/AuthenticationServerMiddlewareTest.php @@ -2,13 +2,13 @@ namespace LeagueTests\Middleware; -use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Middleware\AuthenticationServerMiddleware; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Server; +use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequestFactory; diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index de4ac7fa..ce7620ea 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -3,12 +3,12 @@ namespace LeagueTests\ResponseTypes; use League\OAuth2\Server\Entities\AccessTokenEntity; -use League\OAuth2\Server\Entities\ClientEntity; 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\ResponseTypes\BearerTokenResponse; +use LeagueTests\Stubs\ClientEntity; +use LeagueTests\Stubs\ScopeEntity; use Psr\Http\Message\ResponseInterface; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 66eadc27..1563e34a 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -2,7 +2,6 @@ namespace LeagueTests; -use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\ClientCredentialsGrant; @@ -14,6 +13,7 @@ use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use League\OAuth2\Server\Server; +use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; use Psr\Http\Message\ResponseInterface; use Zend\Diactoros\ServerRequest; diff --git a/src/Entities/Traits/ClientEntityTrait.php b/tests/Stubs/ClientEntity.php similarity index 82% rename from src/Entities/Traits/ClientEntityTrait.php rename to tests/Stubs/ClientEntity.php index 88e1188f..74775ab0 100644 --- a/src/Entities/Traits/ClientEntityTrait.php +++ b/tests/Stubs/ClientEntity.php @@ -1,9 +1,14 @@ getIdentifier(); From 9e04da01de8b48c5cd48e0cb779e6cce618e6494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Tue, 15 Mar 2016 01:18:54 +0100 Subject: [PATCH 298/444] unused use statements --- src/Grant/RefreshTokenGrant.php | 1 - tests/Grant/AuthCodeGrantTest.php | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 75d1cee4..f1aebd3d 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -11,7 +11,6 @@ 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; diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 22323388..230c9442 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -4,7 +4,6 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; From 91c8daeb99849c0a0aaf519fc0709f5859ad01d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Tue, 15 Mar 2016 20:54:59 +0100 Subject: [PATCH 299/444] normalize repositories visibility --- src/Grant/AbstractGrant.php | 42 +++++++++++++-------------------- src/Grant/AuthCodeGrant.php | 9 ++----- src/Grant/ImplicitGrant.php | 7 +----- src/Grant/PasswordGrant.php | 7 +----- src/Grant/RefreshTokenGrant.php | 6 ++--- 5 files changed, 23 insertions(+), 48 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 6a9390f3..37dc9aca 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -24,6 +24,7 @@ use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use League\OAuth2\Server\Repositories\UserRepositoryInterface; use Psr\Http\Message\ServerRequestInterface; /** @@ -58,12 +59,17 @@ abstract class AbstractGrant implements GrantTypeInterface /** * @var \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface */ - private $authCodeRepository; + protected $authCodeRepository; /** * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface */ - private $refreshTokenRepository; + protected $refreshTokenRepository; + + /** + * @var \League\OAuth2\Server\Repositories\UserRepositoryInterface + */ + protected $userRepository; /** * @var string @@ -120,6 +126,14 @@ abstract class AbstractGrant implements GrantTypeInterface $this->authCodeRepository = $authCodeRepository; } + /** + * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository + */ + public function setUserRepository(UserRepositoryInterface $userRepository) + { + $this->userRepository = $userRepository; + } + /** * @param string $pathToPrivateKey */ @@ -136,14 +150,6 @@ abstract class AbstractGrant implements GrantTypeInterface $this->pathToPublicKey = $pathToPublicKey; } - /** - * {@inheritdoc} - */ - public function setEmitter(EmitterInterface $emitter = null) - { - $this->emitter = $emitter; - } - /** * {@inheritdoc} */ @@ -152,22 +158,6 @@ abstract class AbstractGrant implements GrantTypeInterface $this->refreshTokenTTL = $refreshTokenTTL; } - /** - * @return AuthCodeRepositoryInterface - */ - protected function getAuthCodeRepository() - { - return $this->authCodeRepository; - } - - /** - * @return RefreshTokenRepositoryInterface - */ - protected function getRefreshTokenRepository() - { - return $this->refreshTokenRepository; - } - /** * Validate the client. * diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index bc65dc9a..f1db4921 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -24,11 +24,6 @@ class AuthCodeGrant extends AbstractAuthorizeGrant */ private $authCodeTTL; - /** - * @var \League\OAuth2\Server\Repositories\UserRepositoryInterface - */ - private $userRepository; - /** * @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository @@ -49,7 +44,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant ) { $this->setAuthCodeRepository($authCodeRepository); $this->setRefreshTokenRepository($refreshTokenRepository); - $this->userRepository = $userRepository; + $this->setUserRepository($userRepository); $this->authCodeTTL = $authCodeTTL; $this->refreshTokenTTL = new \DateInterval('P1M'); $this->loginTemplate = $loginTemplate; @@ -262,7 +257,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant throw OAuthServerException::invalidRequest('code', 'Authorization code has expired'); } - if ($this->getAuthCodeRepository()->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) { + if ($this->authCodeRepository->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) { throw OAuthServerException::invalidRequest('code', 'Authorization code has been revoked'); } diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 7f846f90..4e306d76 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -16,11 +16,6 @@ use Zend\Diactoros\Uri; class ImplicitGrant extends AbstractAuthorizeGrant { - /** - * @var \League\OAuth2\Server\Repositories\UserRepositoryInterface - */ - private $userRepository; - /** * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository * @param string|null $loginTemplate @@ -33,7 +28,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant $authorizeTemplate = null, RendererInterface $templateRenderer = null ) { - $this->userRepository = $userRepository; + $this->setUserRepository($userRepository); $this->refreshTokenTTL = new \DateInterval('P1M'); $this->loginTemplate = $loginTemplate; $this->authorizeTemplate = $authorizeTemplate; diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index d7328f71..f9298722 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -23,11 +23,6 @@ use Psr\Http\Message\ServerRequestInterface; */ class PasswordGrant extends AbstractGrant { - /** - * @var \League\OAuth2\Server\Repositories\UserRepositoryInterface - */ - private $userRepository; - /** * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository @@ -36,7 +31,7 @@ class PasswordGrant extends AbstractGrant UserRepositoryInterface $userRepository, RefreshTokenRepositoryInterface $refreshTokenRepository ) { - $this->userRepository = $userRepository; + $this->setUserRepository($userRepository); $this->setRefreshTokenRepository($refreshTokenRepository); $this->refreshTokenTTL = new \DateInterval('P1M'); diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index f1aebd3d..04d078e4 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -74,13 +74,13 @@ class RefreshTokenGrant extends AbstractGrant // Expire old tokens $this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']); - $this->getRefreshTokenRepository()->revokeRefreshToken($oldRefreshToken['refresh_token_id']); + $this->refreshTokenRepository->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->getRefreshTokenRepository()->persistNewRefreshToken($refreshToken); + $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); // Inject tokens into response $responseType->setAccessToken($accessToken); @@ -126,7 +126,7 @@ class RefreshTokenGrant extends AbstractGrant throw OAuthServerException::invalidRefreshToken('Token has expired'); } - if ($this->getRefreshTokenRepository()->isRefreshTokenRevoked($refreshTokenData['refresh_token_id']) === true) { + if ($this->refreshTokenRepository->isRefreshTokenRevoked($refreshTokenData['refresh_token_id']) === true) { throw OAuthServerException::invalidRefreshToken('Token has been revoked'); } From 66e473b1f0fbc8230099e421ea2071ba07092956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Tue, 15 Mar 2016 20:57:32 +0100 Subject: [PATCH 300/444] clean use statment --- src/Grant/AbstractGrant.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 37dc9aca..7fe30e5f 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -11,7 +11,6 @@ namespace League\OAuth2\Server\Grant; use League\Event\EmitterAwareTrait; -use League\Event\EmitterInterface; use League\Event\Event; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\AuthCodeEntity; From e946c1e106bad8e5b6ff05b3abded17a55296e72 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 15 Mar 2016 21:20:46 +0000 Subject: [PATCH 301/444] Remove old MAC output type --- src/ResponseTypes/MAC.php | 146 -------------------------------------- 1 file changed, 146 deletions(-) delete mode 100644 src/ResponseTypes/MAC.php diff --git a/src/ResponseTypes/MAC.php b/src/ResponseTypes/MAC.php deleted file mode 100644 index 106d7330..00000000 --- a/src/ResponseTypes/MAC.php +++ /dev/null @@ -1,146 +0,0 @@ - - * @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; -use Symfony\Component\HttpFoundation\ParameterBag; -use Symfony\Component\HttpFoundation\Request; - -/** - * MAC Token Type. - */ -class MAC extends AbstractTokenType implements TokenTypeInterface -{ - /** - * {@inheritdoc} - */ - public function generateResponse() - { - $macKey = SecureKey::generate(); - $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', - ]; - - return $response; - } - - /** - * {@inheritdoc} - */ - public function validateAccessToken(Request $request) - { - if ($request->headers->has('Authorization') === false) { - return; - } - - $header = $request->headers->get('Authorization'); - - if (substr($header, 0, 4) !== 'MAC ') { - return; - } - - // Find all the parameters expressed in the header - $paramsRaw = explode(',', substr($header, 4)); - $params = new ParameterBag(); - - array_map(function ($param) use (&$params) { - $param = trim($param); - - preg_match_all('/([a-zA-Z]*)="([\w=]*)"/', $param, $matches); - - // @codeCoverageIgnoreStart - if (count($matches) !== 3) { - return; - } - // @codeCoverageIgnoreEnd - - $key = reset($matches[1]); - $value = trim(reset($matches[2])); - - if (empty($value)) { - return; - } - - $params->set($key, $value); - }, $paramsRaw); - - // Validate parameters - if ($params->has('id') === false || $params->has('ts') === false || $params->has('nonce') === false || $params->has('mac') === false) { - return; - } - - if ((int) $params->get('ts') !== time()) { - return; - } - - $accessToken = $params->get('id'); - $timestamp = (int) $params->get('ts'); - $nonce = $params->get('nonce'); - $signature = $params->get('mac'); - - // Try to find the MAC key for the access token - $macKey = $this->server->getMacStorage()->getByAccessToken($accessToken); - - if ($macKey === null) { - return; - } - - // Calculate and compare the signature - $calculatedSignatureParts = [ - $timestamp, - $nonce, - strtoupper($request->getMethod()), - $request->getUri(), - $request->getHost(), - $request->getPort(), - ]; - - if ($params->has('ext')) { - $calculatedSignatureParts[] = $params->get('ext'); - } - - $calculatedSignature = base64_encode(hash_hmac('sha256', implode("\n", $calculatedSignatureParts), $macKey)); - - // Return the access token if the signature matches - return ($this->hash_equals($calculatedSignature, $signature)) ? $accessToken : null; - } - - /** - * Prevent timing attack. - * - * @param string $knownString - * @param string $userString - * - * @return bool - */ - private function hash_equals($knownString, $userString) - { - if (function_exists('\hash_equals')) { - return \hash_equals($knownString, $userString); - } - if (strlen($knownString) !== strlen($userString)) { - return false; - } - $len = strlen($knownString); - $result = 0; - for ($i = 0; $i < $len; $i++) { - $result |= (ord($knownString[$i]) ^ ord($userString[$i])); - } - // They are only identical strings if $result is exactly 0... - return 0 === $result; - } -} From 472ec68bbe026a017eb7a775c6b67c3f2b5c119d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 15 Mar 2016 21:20:59 +0000 Subject: [PATCH 302/444] Removed validateAccessToken from abstract response type --- src/ResponseTypes/AbstractResponseType.php | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/ResponseTypes/AbstractResponseType.php b/src/ResponseTypes/AbstractResponseType.php index b0e8dfc0..847f8ecf 100644 --- a/src/ResponseTypes/AbstractResponseType.php +++ b/src/ResponseTypes/AbstractResponseType.php @@ -73,16 +73,4 @@ abstract class AbstractResponseType implements ResponseTypeInterface { $this->refreshToken = $refreshToken; } - - /** - * {@inheritdoc} - */ - public function validateAccessToken(ServerRequestInterface $request) - { - if ($request->hasHeader('authorization') === false) { - throw OAuthServerException::accessDenied('Missing "Authorization" header'); - } - - return $request; - } } From 7159352108032e2df17c16b9bc3a821c1f4e25b4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 15 Mar 2016 17:21:21 -0400 Subject: [PATCH 303/444] Applied fixes from StyleCI --- src/ResponseTypes/AbstractResponseType.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ResponseTypes/AbstractResponseType.php b/src/ResponseTypes/AbstractResponseType.php index 847f8ecf..a64bfded 100644 --- a/src/ResponseTypes/AbstractResponseType.php +++ b/src/ResponseTypes/AbstractResponseType.php @@ -12,9 +12,7 @@ namespace League\OAuth2\Server\ResponseTypes; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; -use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; -use Psr\Http\Message\ServerRequestInterface; abstract class AbstractResponseType implements ResponseTypeInterface { From ae0edc40aa85c19505cff7405ec6ff41ab81fe07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Tue, 15 Mar 2016 22:25:28 +0100 Subject: [PATCH 304/444] clarify names and return types --- src/Grant/AbstractGrant.php | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 6a9390f3..da4c2e75 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -15,6 +15,7 @@ use League\Event\EmitterInterface; use League\Event\Event; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\AuthCodeEntity; +use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntity; @@ -324,22 +325,22 @@ abstract class AbstractGrant implements GrantTypeInterface /** * Issue an access token. * - * @param \DateInterval $tokenTTL + * @param \DateInterval $accessTokenTTL * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client * @param string $userIdentifier * @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] $scopes * - * @return \League\OAuth2\Server\Entities\AccessTokenEntity + * @return \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface */ protected function issueAccessToken( - \DateInterval $tokenTTL, + \DateInterval $accessTokenTTL, ClientEntityInterface $client, $userIdentifier, array $scopes = [] ) { $accessToken = new AccessTokenEntity(); $accessToken->setIdentifier($this->generateUniqueIdentifier()); - $accessToken->setExpiryDateTime((new \DateTime())->add($tokenTTL)); + $accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL)); $accessToken->setClient($client); $accessToken->setUserIdentifier($userIdentifier); @@ -355,18 +356,16 @@ abstract class AbstractGrant implements GrantTypeInterface /** * Issue an auth code. * - * @param \DateInterval $tokenTTL + * @param \DateInterval $authCodeTTL * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client * @param string $userIdentifier * @param string $redirectUri * @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] $scopes * - * @throws \League\OAuth2\Server\Exception\OAuthServerException - * - * @return \League\OAuth2\Server\Entities\AuthCodeEntity + * @return \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface */ protected function issueAuthCode( - \DateInterval $tokenTTL, + \DateInterval $authCodeTTL, ClientEntityInterface $client, $userIdentifier, $redirectUri, @@ -374,7 +373,7 @@ abstract class AbstractGrant implements GrantTypeInterface ) { $authCode = new AuthCodeEntity(); $authCode->setIdentifier($this->generateUniqueIdentifier()); - $authCode->setExpiryDateTime((new \DateTime())->add($tokenTTL)); + $authCode->setExpiryDateTime((new \DateTime())->add($authCodeTTL)); $authCode->setClient($client); $authCode->setUserIdentifier($userIdentifier); $authCode->setRedirectUri($redirectUri); @@ -389,11 +388,11 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @param \League\OAuth2\Server\Entities\AccessTokenEntity $accessToken + * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken * - * @return \League\OAuth2\Server\Entities\RefreshTokenEntity + * @return \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface */ - protected function issueRefreshToken(AccessTokenEntity $accessToken) + protected function issueRefreshToken(AccessTokenEntityInterface $accessToken) { $refreshToken = new RefreshTokenEntity(); $refreshToken->setIdentifier($this->generateUniqueIdentifier()); From c7a5a57304d51e5447900a2251732c5872f4ce1b Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 15 Mar 2016 21:29:35 +0000 Subject: [PATCH 305/444] Added getSecret method to ClientEntityInterface --- src/Entities/Interfaces/ClientEntityInterface.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Entities/Interfaces/ClientEntityInterface.php b/src/Entities/Interfaces/ClientEntityInterface.php index a3ab3b99..180719b1 100644 --- a/src/Entities/Interfaces/ClientEntityInterface.php +++ b/src/Entities/Interfaces/ClientEntityInterface.php @@ -38,13 +38,11 @@ interface ClientEntityInterface public function setSecret($secret); /** - * Validate the secret provided by the client. + * Get the hashed client secret * - * @param string $submittedSecret - * - * @return bool + * @return string */ - public function validateSecret($submittedSecret); + public function getSecret(); /** * Set the client's redirect uri. From 9e828f8f3c71ae457a6a00b03fa7d07d33b82a05 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 15 Mar 2016 21:29:45 +0000 Subject: [PATCH 306/444] Updated stub client entity --- tests/Stubs/ClientEntity.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/Stubs/ClientEntity.php b/tests/Stubs/ClientEntity.php index 74775ab0..4956b62b 100644 --- a/tests/Stubs/ClientEntity.php +++ b/tests/Stubs/ClientEntity.php @@ -53,7 +53,7 @@ class ClientEntity implements ClientEntityInterface */ public function setSecret($secret) { - $this->secret = $secret; + $this->secret = password_hash($secret, PASSWORD_DEFAULT); } /** @@ -79,4 +79,14 @@ class ClientEntity implements ClientEntityInterface { return $this->redirectUri; } + + /** + * Get the hashed client secret + * + * @return string + */ + public function getSecret() + { + return $this->secret; + } } From 3365f3d733ace22e71d700b32b010f1ec3cbd2e7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 15 Mar 2016 21:30:13 +0000 Subject: [PATCH 307/444] Moved client secret validation to abstract grant. Fixes #460 --- src/Grant/AbstractGrant.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 7fe30e5f..1a787761 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -197,7 +197,7 @@ abstract class AbstractGrant implements GrantTypeInterface throw OAuthServerException::invalidRequest('client_secret', '`%s` parameter is missing'); } - if ($client->canKeepASecret() && $client->validateSecret($clientSecret) === false) { + if ($client->canKeepASecret() && password_verify($clientSecret, $client->getSecret()) === false) { $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); throw OAuthServerException::invalidClient(); } From d635b3484bdf41b494b6e6107f88ad61f9859af7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 15 Mar 2016 21:30:18 +0000 Subject: [PATCH 308/444] Fix broken code --- src/ResponseTypes/BearerTokenResponse.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index c161bd3c..04295895 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -69,7 +69,9 @@ class BearerTokenResponse extends AbstractResponseType */ public function validateAccessToken(ServerRequestInterface $request) { - $request = parent::validateAccessToken($request); + if ($request->hasHeader('authorization') === false) { + throw OAuthServerException::accessDenied('Missing "Authorization" header'); + } $header = $request->getHeader('authorization'); $jwt = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header[0])); From 5bbf703711cf1764ca1e9cc6bc22e88b399487b8 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 15 Mar 2016 21:54:36 +0000 Subject: [PATCH 309/444] Fixes for examples --- examples/composer.lock | 165 ++++-------------- examples/src/Entities/ClientEntity.php | 85 +++++++++ examples/src/Entities/ScopeEntity.php | 16 ++ .../src/Repositories/ClientRepository.php | 16 +- examples/src/Repositories/ScopeRepository.php | 4 +- 5 files changed, 139 insertions(+), 147 deletions(-) create mode 100644 examples/src/Entities/ClientEntity.php create mode 100644 examples/src/Entities/ScopeEntity.php diff --git a/examples/composer.lock b/examples/composer.lock index 776fb37a..a866769a 100644 --- a/examples/composer.lock +++ b/examples/composer.lock @@ -145,21 +145,16 @@ { "name": "league/oauth2-server", "version": "dev-V5-WIP", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/oauth2-server.git", - "reference": "95919a688e29c911d1e4e83112cacd18f719700f" - }, "dist": { "type": "path", - "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/95919a688e29c911d1e4e83112cacd18f719700f", - "reference": "168e7640c6e8217b7e961151de522810b3edce6e", + "url": "../", + "reference": "d635b3484bdf41b494b6e6107f88ad61f9859af7", "shasum": null }, "require": { "lcobucci/jwt": "^3.1", "league/event": "~2.1", - "namshi/jose": "^6.0", + "paragonie/random_compat": "^1.1", "php": ">=5.5.9", "zendframework/zend-diactoros": "~1.1" }, @@ -168,10 +163,14 @@ "lncd/oauth2": "*" }, "require-dev": { - "codeception/codeception": "~2.0", - "flow/jsonpath": "0.2.*", - "mockery/mockery": "0.9.*", - "phpunit/phpunit": "4.8.*" + "league/plates": "^3.1", + "phpunit/phpunit": "^4.8" + }, + "suggest": { + "league/plates": "Used for parsing authorization code templates", + "mustache/mustache": "Used for parsing authorization code templates", + "smarty/smarty": "Used for parsing authorization code templates", + "twig/twig": "Used for parsing authorization code templates" }, "type": "library", "extra": { @@ -186,7 +185,7 @@ }, "autoload-dev": { "psr-4": { - "LeagueTests\\": "tests/unit/" + "LeagueTests\\": "tests/" } }, "license": [ @@ -271,66 +270,6 @@ ], "time": "2015-07-09 02:14:40" }, - { - "name": "namshi/jose", - "version": "6.1.0", - "source": { - "type": "git", - "url": "https://github.com/namshi/jose.git", - "reference": "0ae1eae2be4f7e31a649ab9e3b782c3aedf81ebd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/namshi/jose/zipball/0ae1eae2be4f7e31a649ab9e3b782c3aedf81ebd", - "reference": "0ae1eae2be4f7e31a649ab9e3b782c3aedf81ebd", - "shasum": "" - }, - "require": { - "ext-date": "*", - "ext-hash": "*", - "ext-json": "*", - "ext-openssl": "*", - "ext-pcre": "*", - "ext-spl": "*", - "php": ">=5.5", - "phpseclib/phpseclib": "2.0.*" - }, - "require-dev": { - "phpunit/phpunit": "^4.5|^5.0", - "satooshi/php-coveralls": "^1.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "Namshi\\JOSE": "src/", - "Namshi\\JOSE\\Test": "test/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Alessandro Nadalin", - "email": "alessandro.nadalin@gmail.com" - }, - { - "name": "Alessandro Cinelli (cirpo)", - "email": "alessandro.cinelli@gmail.com" - } - ], - "description": "JSON Object Signing and Encryption library for PHP.", - "keywords": [ - "JSON Web Signature", - "JSON Web Token", - "JWS", - "json", - "jwt", - "token" - ], - "time": "2016-01-13 10:17:13" - }, { "name": "nikic/fast-route", "version": "v0.6.0", @@ -375,92 +314,52 @@ "time": "2015-06-18 19:15:47" }, { - "name": "phpseclib/phpseclib", - "version": "2.0.0", + "name": "paragonie/random_compat", + "version": "v1.2.2", "source": { "type": "git", - "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "a74aa9efbe61430fcb60157c8e025a48ec8ff604" + "url": "https://github.com/paragonie/random_compat.git", + "reference": "b3313b618f4edd76523572531d5d7e22fe747430" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/a74aa9efbe61430fcb60157c8e025a48ec8ff604", - "reference": "a74aa9efbe61430fcb60157c8e025a48ec8ff604", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/b3313b618f4edd76523572531d5d7e22fe747430", + "reference": "b3313b618f4edd76523572531d5d7e22fe747430", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.2.0" }, "require-dev": { - "phing/phing": "~2.7", - "phpunit/phpunit": "~4.0", - "sami/sami": "~2.0", - "squizlabs/php_codesniffer": "~2.0" + "phpunit/phpunit": "4.*|5.*" }, "suggest": { - "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", - "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", - "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", - "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations.", - "pear-pear/PHP_Compat": "Install PHP_Compat to get phpseclib working on PHP < 5.0.0." + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." }, "type": "library", "autoload": { - "psr-4": { - "phpseclib\\": "phpseclib/" - } + "files": [ + "lib/random.php" + ] }, "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "phpseclib/" - ], "license": [ "MIT" ], "authors": [ { - "name": "Jim Wigginton", - "email": "terrafrost@php.net", - "role": "Lead Developer" - }, - { - "name": "Patrick Monnerat", - "email": "pm@datasphere.ch", - "role": "Developer" - }, - { - "name": "Andreas Fischer", - "email": "bantu@phpbb.com", - "role": "Developer" - }, - { - "name": "Hans-Jürgen Petrich", - "email": "petrich@tronic-media.com", - "role": "Developer" + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" } ], - "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", - "homepage": "http://phpseclib.sourceforge.net", + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", "keywords": [ - "BigInteger", - "aes", - "asn.1", - "asn1", - "blowfish", - "crypto", - "cryptography", - "encryption", - "rsa", - "security", - "sftp", - "signature", - "signing", - "ssh", - "twofish", - "x.509", - "x509" + "csprng", + "pseudorandom", + "random" ], - "time": "2015-08-04 04:48:03" + "time": "2016-03-11 19:54:08" }, { "name": "pimple/pimple", diff --git a/examples/src/Entities/ClientEntity.php b/examples/src/Entities/ClientEntity.php new file mode 100644 index 00000000..2427b4e7 --- /dev/null +++ b/examples/src/Entities/ClientEntity.php @@ -0,0 +1,85 @@ +name; + } + + /** + * Set the client's name. + * + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @param string $secret + */ + public function setSecret($secret) + { + $this->secret = $secret; + } + + /** + * Get the hashed client secret + * + * @return string + */ + public function getSecret() + { + return $this->secret; + } + + /** + * Set the client's redirect uri. + * + * @param string $redirectUri + */ + public function setRedirectUri($redirectUri) + { + $this->redirectUri = $redirectUri; + } + + /** + * Returns the registered redirect URI. + * + * @return string + */ + public function getRedirectUri() + { + return $this->redirectUri; + } + + /** + * Returns true if the client is capable of keeping it's secrets secret. + * + * @return bool + */ + public function canKeepASecret() + { + return $this->secret !== null; + } +} \ No newline at end of file diff --git a/examples/src/Entities/ScopeEntity.php b/examples/src/Entities/ScopeEntity.php new file mode 100644 index 00000000..35611da2 --- /dev/null +++ b/examples/src/Entities/ScopeEntity.php @@ -0,0 +1,16 @@ +getIdentifier(); + } +} \ No newline at end of file diff --git a/examples/src/Repositories/ClientRepository.php b/examples/src/Repositories/ClientRepository.php index 86167154..5a5a32f7 100644 --- a/examples/src/Repositories/ClientRepository.php +++ b/examples/src/Repositories/ClientRepository.php @@ -2,8 +2,8 @@ namespace OAuth2ServerExamples\Repositories; -use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use OAuth2ServerExamples\Entities\ClientEntity; class ClientRepository implements ClientRepositoryInterface { @@ -22,22 +22,14 @@ class ClientRepository implements ClientRepositoryInterface // Check if client is registered if (array_key_exists($clientIdentifier, $clients) === false) { - return; - } - - // Check if client secret is valid - if ($clientSecret !== null && password_verify($clientSecret, $clients[$clientIdentifier]['secret']) === false) { - return; - } - - // Check if redirect URI is valid - if ($redirectUri !== null && $redirectUri !== $clients[$clientIdentifier]['redirect_uri']) { - return; + return null; } $client = new ClientEntity(); $client->setIdentifier($clientIdentifier); $client->setName($clients[$clientIdentifier]['name']); + $client->setRedirectUri($clients[$clientIdentifier]['redirect_uri']); + $client->setSecret($clients[$clientIdentifier]['secret']); return $client; } diff --git a/examples/src/Repositories/ScopeRepository.php b/examples/src/Repositories/ScopeRepository.php index f48aac5b..f9b50dbb 100644 --- a/examples/src/Repositories/ScopeRepository.php +++ b/examples/src/Repositories/ScopeRepository.php @@ -2,8 +2,8 @@ namespace OAuth2ServerExamples\Repositories; -use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use OAuth2ServerExamples\Entities\ScopeEntity; class ScopeRepository implements ScopeRepositoryInterface { @@ -22,7 +22,7 @@ class ScopeRepository implements ScopeRepositoryInterface ]; if (array_key_exists($scopeIdentifier, $scopes) === false) { - return; + return null; } $scope = new ScopeEntity(); From 079ed0040a8cf1a8744623b8acdb23d7572e4464 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 15 Mar 2016 17:54:45 -0400 Subject: [PATCH 310/444] Applied fixes from StyleCI --- examples/src/Entities/ClientEntity.php | 2 +- examples/src/Entities/ScopeEntity.php | 4 ++-- examples/src/Repositories/ClientRepository.php | 2 +- examples/src/Repositories/ScopeRepository.php | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/src/Entities/ClientEntity.php b/examples/src/Entities/ClientEntity.php index 2427b4e7..822a3f64 100644 --- a/examples/src/Entities/ClientEntity.php +++ b/examples/src/Entities/ClientEntity.php @@ -82,4 +82,4 @@ class ClientEntity implements ClientEntityInterface { return $this->secret !== null; } -} \ No newline at end of file +} diff --git a/examples/src/Entities/ScopeEntity.php b/examples/src/Entities/ScopeEntity.php index 35611da2..23d12a44 100644 --- a/examples/src/Entities/ScopeEntity.php +++ b/examples/src/Entities/ScopeEntity.php @@ -9,8 +9,8 @@ class ScopeEntity implements ScopeEntityInterface { use EntityTrait; - function jsonSerialize() + public function jsonSerialize() { return $this->getIdentifier(); } -} \ No newline at end of file +} diff --git a/examples/src/Repositories/ClientRepository.php b/examples/src/Repositories/ClientRepository.php index 5a5a32f7..4727871b 100644 --- a/examples/src/Repositories/ClientRepository.php +++ b/examples/src/Repositories/ClientRepository.php @@ -22,7 +22,7 @@ class ClientRepository implements ClientRepositoryInterface // Check if client is registered if (array_key_exists($clientIdentifier, $clients) === false) { - return null; + return; } $client = new ClientEntity(); diff --git a/examples/src/Repositories/ScopeRepository.php b/examples/src/Repositories/ScopeRepository.php index f9b50dbb..014ca3dd 100644 --- a/examples/src/Repositories/ScopeRepository.php +++ b/examples/src/Repositories/ScopeRepository.php @@ -22,7 +22,7 @@ class ScopeRepository implements ScopeRepositoryInterface ]; if (array_key_exists($scopeIdentifier, $scopes) === false) { - return null; + return; } $scope = new ScopeEntity(); From ee910724550e5f644b0a9a7fc7f1a11b1ef52cdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Wed, 16 Mar 2016 12:32:21 +0100 Subject: [PATCH 311/444] template renderer holds template related information --- src/Grant/AbstractAuthorizeGrant.php | 62 ++-------------- src/Grant/AuthCodeGrant.php | 16 ++--- src/Grant/ImplicitGrant.php | 22 ++---- src/TemplateRenderer/AbstractRenderer.php | 70 +++++++++++++++++++ .../DefaultTemplates/authorize_client.php | 0 .../DefaultTemplates/login_user.php | 0 src/TemplateRenderer/MustacheRenderer.php | 12 ++-- src/TemplateRenderer/PlatesRenderer.php | 10 ++- src/TemplateRenderer/RendererInterface.php | 22 ------ src/TemplateRenderer/SmartyRenderer.php | 14 ++-- src/TemplateRenderer/TwigRenderer.php | 14 ++-- tests/Grant/AuthCodeGrantTest.php | 24 ++----- tests/Grant/ImplicitGrantTest.php | 38 ++-------- 13 files changed, 133 insertions(+), 171 deletions(-) create mode 100644 src/TemplateRenderer/AbstractRenderer.php rename src/{ResponseTypes => TemplateRenderer}/DefaultTemplates/authorize_client.php (100%) rename src/{ResponseTypes => TemplateRenderer}/DefaultTemplates/login_user.php (100%) delete mode 100644 src/TemplateRenderer/RendererInterface.php diff --git a/src/Grant/AbstractAuthorizeGrant.php b/src/Grant/AbstractAuthorizeGrant.php index 9914e989..bab3ee01 100644 --- a/src/Grant/AbstractAuthorizeGrant.php +++ b/src/Grant/AbstractAuthorizeGrant.php @@ -18,73 +18,25 @@ use League\Plates\Engine; abstract class AbstractAuthorizeGrant extends AbstractGrant { /** - * @var null|\League\OAuth2\Server\TemplateRenderer\RendererInterface + * @var \League\OAuth2\Server\TemplateRenderer\RendererInterface */ protected $templateRenderer; /** - * @var null|string - */ - protected $loginTemplate; - - /** - * @var null|string - */ - protected $authorizeTemplate; - - /** - * @param array $data + * Retrieve template renderer. * - * @return string - */ - protected function renderLoginTemplate(array $data = []) - { - return $this->getTemplateRenderer()->render($this->getLoginTemplate(), $data); - } - - /** - * @param array $data - * - * @return string - */ - protected function renderAuthorizeTemplate(array $data = []) - { - return $this->getTemplateRenderer()->render($this->getAuthorizeTemplate(), $data); - } - - /** * @return \League\OAuth2\Server\TemplateRenderer\RendererInterface */ protected function getTemplateRenderer() { if (!$this->templateRenderer instanceof RendererInterface) { - $this->templateRenderer = new PlatesRenderer(new Engine(__DIR__ . '/../ResponseTypes/DefaultTemplates')); + $this->templateRenderer = new PlatesRenderer( + new Engine(__DIR__ . '/../TemplateRenderer/DefaultTemplates'), + 'login_user', + 'authorize_client' + ); } return $this->templateRenderer; } - - /** - * @return string - */ - protected function getLoginTemplate() - { - if (empty($this->loginTemplate)) { - $this->loginTemplate = 'login_user'; - } - - return $this->loginTemplate; - } - - /** - * @return string - */ - protected function getAuthorizeTemplate() - { - if (empty($this->authorizeTemplate)) { - $this->authorizeTemplate = 'authorize_client'; - } - - return $this->authorizeTemplate; - } } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index f1db4921..a3fb2e34 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -11,7 +11,7 @@ use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; -use League\OAuth2\Server\TemplateRenderer\RendererInterface; +use League\OAuth2\Server\TemplateRenderer\AbstractRenderer; use League\OAuth2\Server\Utils\KeyCrypt; use Psr\Http\Message\ServerRequestInterface; use Zend\Diactoros\Response; @@ -29,26 +29,20 @@ class AuthCodeGrant extends AbstractAuthorizeGrant * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository * @param \DateInterval $authCodeTTL - * @param string|null $loginTemplate - * @param string|null $authorizeTemplate - * @param \League\OAuth2\Server\TemplateRenderer\RendererInterface|null $templateRenderer + * @param \League\OAuth2\Server\TemplateRenderer\AbstractRenderer|null $templateRenderer */ public function __construct( AuthCodeRepositoryInterface $authCodeRepository, RefreshTokenRepositoryInterface $refreshTokenRepository, UserRepositoryInterface $userRepository, \DateInterval $authCodeTTL, - $loginTemplate = null, - $authorizeTemplate = null, - RendererInterface $templateRenderer = null + AbstractRenderer $templateRenderer = null ) { $this->setAuthCodeRepository($authCodeRepository); $this->setRefreshTokenRepository($refreshTokenRepository); $this->setUserRepository($userRepository); $this->authCodeTTL = $authCodeTTL; $this->refreshTokenTTL = new \DateInterval('P1M'); - $this->loginTemplate = $loginTemplate; - $this->authorizeTemplate = $authorizeTemplate; $this->templateRenderer = $templateRenderer; } @@ -144,7 +138,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant // The user hasn't logged in yet so show a login form if ($userId === null) { - $html = $this->renderLoginTemplate([ + $html = $this->getTemplateRenderer()->renderLogin([ 'error' => $loginError, 'postback_uri' => (string) $postbackUri->withQuery($queryString), ]); @@ -154,7 +148,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant // The user hasn't approved the client yet so show an authorize form if ($userId !== null && $userHasApprovedClient === null) { - $html = $this->renderAuthorizeTemplate([ + $html = $this->getTemplateRenderer()->renderAuthorize([ 'client' => $client, 'scopes' => $scopes, 'postback_uri' => (string) $postbackUri->withQuery($queryString), diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 4e306d76..89a3c2e6 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -8,7 +8,7 @@ use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; -use League\OAuth2\Server\TemplateRenderer\RendererInterface; +use League\OAuth2\Server\TemplateRenderer\AbstractRenderer; use League\OAuth2\Server\Utils\KeyCrypt; use Psr\Http\Message\ServerRequestInterface; use Zend\Diactoros\Response; @@ -17,21 +17,13 @@ use Zend\Diactoros\Uri; class ImplicitGrant extends AbstractAuthorizeGrant { /** - * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository - * @param string|null $loginTemplate - * @param string|null $authorizeTemplate - * @param \League\OAuth2\Server\TemplateRenderer\RendererInterface|null $templateRenderer + * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository + * @param \League\OAuth2\Server\TemplateRenderer\AbstractRenderer|null $templateRenderer */ - public function __construct( - UserRepositoryInterface $userRepository, - $loginTemplate = null, - $authorizeTemplate = null, - RendererInterface $templateRenderer = null - ) { + public function __construct(UserRepositoryInterface $userRepository, AbstractRenderer $templateRenderer = null) + { $this->setUserRepository($userRepository); $this->refreshTokenTTL = new \DateInterval('P1M'); - $this->loginTemplate = $loginTemplate; - $this->authorizeTemplate = $authorizeTemplate; $this->templateRenderer = $templateRenderer; } @@ -144,7 +136,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant // The user hasn't logged in yet so show a login form if ($userId === null) { - $html = $this->renderLoginTemplate([ + $html = $this->getTemplateRenderer()->renderLogin([ 'error' => $loginError, 'postback_uri' => (string) $postbackUri->withQuery($queryString), ]); @@ -154,7 +146,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant // The user hasn't approved the client yet so show an authorize form if ($userId !== null && $userHasApprovedClient === null) { - $html = $this->renderAuthorizeTemplate([ + $html = $this->getTemplateRenderer()->renderAuthorize([ 'client' => $client, 'scopes' => $scopes, 'postback_uri' => (string) $postbackUri->withQuery($queryString), diff --git a/src/TemplateRenderer/AbstractRenderer.php b/src/TemplateRenderer/AbstractRenderer.php new file mode 100644 index 00000000..b8c3fa63 --- /dev/null +++ b/src/TemplateRenderer/AbstractRenderer.php @@ -0,0 +1,70 @@ + + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ +namespace League\OAuth2\Server\TemplateRenderer; + +abstract class AbstractRenderer +{ + /** + * @var string + */ + protected $loginTemplate; + + /** + * @var string + */ + protected $authorizeTemplate; + + /** + * PlatesRenderer constructor. + * + * @param string $loginTemplate + * @param string $authorizeTemplate + */ + public function __construct($loginTemplate, $authorizeTemplate) + { + $this->loginTemplate = $loginTemplate; + $this->authorizeTemplate = $authorizeTemplate; + } + + /** + * Render login template. + * + * @param array $data + * + * @return string + */ + public function renderLogin(array $data = []) + { + return $this->render($this->loginTemplate, $data); + } + + /** + * Render authorize template. + * + * @param array $data + * + * @return string + */ + public function renderAuthorize(array $data = []) + { + return $this->render($this->authorizeTemplate, $data); + } + + /** + * Render template. + * + * @param string $template + * @param array $data + * + * @return string + */ + abstract protected function render($template, array $data = []); +} diff --git a/src/ResponseTypes/DefaultTemplates/authorize_client.php b/src/TemplateRenderer/DefaultTemplates/authorize_client.php similarity index 100% rename from src/ResponseTypes/DefaultTemplates/authorize_client.php rename to src/TemplateRenderer/DefaultTemplates/authorize_client.php diff --git a/src/ResponseTypes/DefaultTemplates/login_user.php b/src/TemplateRenderer/DefaultTemplates/login_user.php similarity index 100% rename from src/ResponseTypes/DefaultTemplates/login_user.php rename to src/TemplateRenderer/DefaultTemplates/login_user.php diff --git a/src/TemplateRenderer/MustacheRenderer.php b/src/TemplateRenderer/MustacheRenderer.php index e5287eac..fbc0abe9 100644 --- a/src/TemplateRenderer/MustacheRenderer.php +++ b/src/TemplateRenderer/MustacheRenderer.php @@ -10,9 +10,7 @@ */ namespace League\OAuth2\Server\TemplateRenderer; -use Mustache_Engine; - -class MustacheRenderer implements RendererInterface +class MustacheRenderer extends AbstractRenderer { /** * @var \Mustache_Engine @@ -20,12 +18,16 @@ class MustacheRenderer implements RendererInterface private $engine; /** - * TwigRenderer constructor. + * PlatesRenderer constructor. * * @param \Mustache_Engine $engine + * @param string $loginTemplate + * @param string $authorizeTemplate */ - public function __construct(Mustache_Engine $engine) + public function __construct(\Mustache_Engine $engine, $loginTemplate, $authorizeTemplate) { + parent::__construct($loginTemplate, $authorizeTemplate); + $this->engine = $engine; } diff --git a/src/TemplateRenderer/PlatesRenderer.php b/src/TemplateRenderer/PlatesRenderer.php index 114815af..6cd4a77b 100644 --- a/src/TemplateRenderer/PlatesRenderer.php +++ b/src/TemplateRenderer/PlatesRenderer.php @@ -12,7 +12,7 @@ namespace League\OAuth2\Server\TemplateRenderer; use League\Plates\Engine; -class PlatesRenderer implements RendererInterface +class PlatesRenderer extends AbstractRenderer { /** * @var \League\Plates\Engine @@ -23,16 +23,20 @@ class PlatesRenderer implements RendererInterface * PlatesRenderer constructor. * * @param \League\Plates\Engine $engine + * @param string $loginTemplate + * @param string $authorizeTemplate */ - public function __construct(Engine $engine) + public function __construct(Engine $engine, $loginTemplate, $authorizeTemplate) { + parent::__construct($loginTemplate, $authorizeTemplate); + $this->engine = $engine; } /** * {@inheritdoc} */ - public function render($template, array $data = []) + protected function render($template, array $data = []) { if ($this->engine->getFileExtension()) { $template = preg_replace(sprintf('/\.%s$/', $this->engine->getFileExtension()), '', $template); diff --git a/src/TemplateRenderer/RendererInterface.php b/src/TemplateRenderer/RendererInterface.php deleted file mode 100644 index 676334ab..00000000 --- a/src/TemplateRenderer/RendererInterface.php +++ /dev/null @@ -1,22 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * - * @link https://github.com/thephpleague/oauth2-server - */ -namespace League\OAuth2\Server\TemplateRenderer; - -interface RendererInterface -{ - /** - * @param string $template - * @param array $data - * - * @return string - */ - public function render($template, array $data = []); -} diff --git a/src/TemplateRenderer/SmartyRenderer.php b/src/TemplateRenderer/SmartyRenderer.php index a54a4719..a69185e1 100644 --- a/src/TemplateRenderer/SmartyRenderer.php +++ b/src/TemplateRenderer/SmartyRenderer.php @@ -10,9 +10,7 @@ */ namespace League\OAuth2\Server\TemplateRenderer; -use Smarty; - -class SmartyRenderer implements RendererInterface +class SmartyRenderer extends AbstractRenderer { /** * Smarty class. @@ -22,17 +20,23 @@ class SmartyRenderer implements RendererInterface private $smarty; /** + * PlatesRenderer constructor. + * * @param \Smarty $smarty + * @param string $loginTemplate + * @param string $authorizeTemplate */ - public function __construct(Smarty $smarty) + public function __construct(\Smarty $smarty, $loginTemplate, $authorizeTemplate) { + parent::__construct($loginTemplate, $authorizeTemplate); + $this->smarty = $smarty; } /** * {@inheritdoc} */ - public function render($template, array $data = []) + protected function render($template, array $data = []) { $this->smarty->assign($data); diff --git a/src/TemplateRenderer/TwigRenderer.php b/src/TemplateRenderer/TwigRenderer.php index 37e3f565..e4e0c13d 100644 --- a/src/TemplateRenderer/TwigRenderer.php +++ b/src/TemplateRenderer/TwigRenderer.php @@ -10,9 +10,7 @@ */ namespace League\OAuth2\Server\TemplateRenderer; -use Twig_Environment; - -class TwigRenderer implements RendererInterface +class TwigRenderer extends AbstractRenderer { /** * @var \Twig_Environment @@ -20,19 +18,23 @@ class TwigRenderer implements RendererInterface private $environment; /** - * TwigRenderer constructor. + * PlatesRenderer constructor. * * @param \Twig_Environment $environment + * @param string $loginTemplate + * @param string $authorizeTemplate */ - public function __construct(Twig_Environment $environment) + public function __construct(\Twig_Environment $environment, $loginTemplate, $authorizeTemplate) { + parent::__construct($loginTemplate, $authorizeTemplate); + $this->environment = $environment; } /** * {@inheritdoc} */ - public function render($template, array $data = []) + protected function render($template, array $data = []) { return $this->environment->loadTemplate($template)->render($data); } diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 230c9442..54973d8e 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -28,9 +28,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), $this->getMock(UserRepositoryInterface::class), - new \DateInterval('PT10M'), - 'foo/bar.php', - 'foo/bar.php' + new \DateInterval('PT10M') ); $this->assertEquals('authorization_code', $grant->getIdentifier()); @@ -77,9 +75,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), $userRepositoryMock, - new \DateInterval('PT10M'), - '', - '' + new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); @@ -134,9 +130,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), $userRepositoryMock, - new \DateInterval('PT10M'), - '', - '' + new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); @@ -196,9 +190,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), $userRepositoryMock, - new \DateInterval('PT10M'), - '', - '' + new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); @@ -365,9 +357,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), $userRepositoryMock, - new \DateInterval('PT10M'), - '', - '' + new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); @@ -417,9 +407,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), $userRepositoryMock, - new \DateInterval('PT10M'), - '', - '' + new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 9d075a69..5bc1156e 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -18,22 +18,14 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase { public function testGetIdentifier() { - $grant = new ImplicitGrant( - $this->getMock(UserRepositoryInterface::class), - 'foo/bar.php', - 'foo/bar.php' - ); + $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $this->assertEquals('implicit', $grant->getIdentifier()); } public function testCanRespondToRequest() { - $grant = new ImplicitGrant( - $this->getMock(UserRepositoryInterface::class), - 'foo/bar.php', - 'foo/bar.php' - ); + $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $request = new ServerRequest( [], @@ -65,7 +57,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); - $grant = new ImplicitGrant($userRepositoryMock, 'foo', 'foo'); + $grant = new ImplicitGrant($userRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); @@ -106,11 +98,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase */ public function testRespondToAuthorizationRequestMissingClientId() { - $grant = new ImplicitGrant( - $this->getMock(UserRepositoryInterface::class), - 'foo/bar.php', - 'foo/bar.php' - ); + $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); @@ -151,11 +139,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); - $grant = new ImplicitGrant( - $this->getMock(UserRepositoryInterface::class), - 'foo/bar.php', - 'foo/bar.php' - ); + $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); @@ -205,11 +189,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $userEntity = new UserEntity(); $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); - $grant = new ImplicitGrant( - $this->getMock(UserRepositoryInterface::class), - 'foo/bar.php', - 'foo/bar.php' - ); + $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); @@ -265,11 +245,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $userEntity = new UserEntity(); $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); - $grant = new ImplicitGrant( - $this->getMock(UserRepositoryInterface::class), - 'foo/bar.php', - 'foo/bar.php' - ); + $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); From bd12c8b1a97a435913d6b8fa18e1c26f25211d4c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 17 Mar 2016 11:18:59 +0000 Subject: [PATCH 312/444] Fix exception usage --- src/Grant/PasswordGrant.php | 4 ++-- src/Grant/RefreshTokenGrant.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index f9298722..a2ce660b 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -72,12 +72,12 @@ class PasswordGrant extends AbstractGrant { $username = $this->getRequestParameter('username', $request); if (is_null($username)) { - throw OAuthServerException::invalidRequest('username', null, '`%s` parameter is missing'); + throw OAuthServerException::invalidRequest('username', '`%s` parameter is missing'); } $password = $this->getRequestParameter('password', $request); if (is_null($password)) { - throw OAuthServerException::invalidRequest('password', null, '`%s` parameter is missing'); + throw OAuthServerException::invalidRequest('password', '`%s` parameter is missing'); } $user = $this->userRepository->getUserEntityByUserCredentials($username, $password); diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 04d078e4..a03bdc90 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -101,7 +101,7 @@ class RefreshTokenGrant extends AbstractGrant { $encryptedRefreshToken = $this->getRequestParameter('refresh_token', $request); if (is_null($encryptedRefreshToken)) { - throw OAuthServerException::invalidRequest('refresh_token', null, '`%s` parameter is missing'); + throw OAuthServerException::invalidRequest('refresh_token', '`%s` parameter is missing'); } // Validate refresh token From 15b6506644b1c050563e3a02e1030f1298aff207 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 17 Mar 2016 11:21:53 +0000 Subject: [PATCH 313/444] No need to use Zend\Diactoros\Stream --- src/Middleware/AuthenticationServerMiddleware.php | 7 ++----- src/Middleware/ResourceServerMiddleware.php | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/Middleware/AuthenticationServerMiddleware.php b/src/Middleware/AuthenticationServerMiddleware.php index 4038d95e..2be5ca63 100644 --- a/src/Middleware/AuthenticationServerMiddleware.php +++ b/src/Middleware/AuthenticationServerMiddleware.php @@ -6,7 +6,6 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Server; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Zend\Diactoros\Stream; class AuthenticationServerMiddleware { @@ -40,10 +39,8 @@ class AuthenticationServerMiddleware return $exception->generateHttpResponse($response); // @codeCoverageIgnoreStart } catch (\Exception $exception) { - $body = new Stream('php://temp', 'r+'); - $body->write($exception->getMessage()); - - return $response->withStatus(500)->withBody($body); + $response->getBody()->write($exception->getMessage()); + return $response->withStatus(500); // @codeCoverageIgnoreEnd } diff --git a/src/Middleware/ResourceServerMiddleware.php b/src/Middleware/ResourceServerMiddleware.php index eecaabbe..e30ded8a 100644 --- a/src/Middleware/ResourceServerMiddleware.php +++ b/src/Middleware/ResourceServerMiddleware.php @@ -6,7 +6,6 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Server; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Zend\Diactoros\Stream; class ResourceServerMiddleware { @@ -40,10 +39,8 @@ class ResourceServerMiddleware return $exception->generateHttpResponse($response); // @codeCoverageIgnoreStart } catch (\Exception $exception) { - $body = new Stream('php://temp', 'r+'); - $body->write($exception->getMessage()); - - return $response->withStatus(500)->withBody($body); + $response->getBody()->write($exception->getMessage()); + return $response->withStatus(500); // @codeCoverageIgnoreEnd } From 7b8d9c9af3dad3eb55a00a262fa6f2a84842e99d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 17 Mar 2016 11:22:04 +0000 Subject: [PATCH 314/444] Added missing RendererInterface --- src/TemplateRenderer/AbstractRenderer.php | 2 +- src/TemplateRenderer/RendererInterface.php | 24 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/TemplateRenderer/RendererInterface.php diff --git a/src/TemplateRenderer/AbstractRenderer.php b/src/TemplateRenderer/AbstractRenderer.php index b8c3fa63..0dc3e1ae 100644 --- a/src/TemplateRenderer/AbstractRenderer.php +++ b/src/TemplateRenderer/AbstractRenderer.php @@ -10,7 +10,7 @@ */ namespace League\OAuth2\Server\TemplateRenderer; -abstract class AbstractRenderer +abstract class AbstractRenderer implements RendererInterface { /** * @var string diff --git a/src/TemplateRenderer/RendererInterface.php b/src/TemplateRenderer/RendererInterface.php new file mode 100644 index 00000000..0a270c56 --- /dev/null +++ b/src/TemplateRenderer/RendererInterface.php @@ -0,0 +1,24 @@ + Date: Thu, 17 Mar 2016 07:22:59 -0400 Subject: [PATCH 315/444] Applied fixes from StyleCI --- src/Middleware/AuthenticationServerMiddleware.php | 1 + src/Middleware/ResourceServerMiddleware.php | 1 + src/TemplateRenderer/RendererInterface.php | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Middleware/AuthenticationServerMiddleware.php b/src/Middleware/AuthenticationServerMiddleware.php index 2be5ca63..2d5ffe41 100644 --- a/src/Middleware/AuthenticationServerMiddleware.php +++ b/src/Middleware/AuthenticationServerMiddleware.php @@ -40,6 +40,7 @@ class AuthenticationServerMiddleware // @codeCoverageIgnoreStart } catch (\Exception $exception) { $response->getBody()->write($exception->getMessage()); + return $response->withStatus(500); // @codeCoverageIgnoreEnd } diff --git a/src/Middleware/ResourceServerMiddleware.php b/src/Middleware/ResourceServerMiddleware.php index e30ded8a..1b127608 100644 --- a/src/Middleware/ResourceServerMiddleware.php +++ b/src/Middleware/ResourceServerMiddleware.php @@ -40,6 +40,7 @@ class ResourceServerMiddleware // @codeCoverageIgnoreStart } catch (\Exception $exception) { $response->getBody()->write($exception->getMessage()); + return $response->withStatus(500); // @codeCoverageIgnoreEnd } diff --git a/src/TemplateRenderer/RendererInterface.php b/src/TemplateRenderer/RendererInterface.php index 0a270c56..74d9b48f 100644 --- a/src/TemplateRenderer/RendererInterface.php +++ b/src/TemplateRenderer/RendererInterface.php @@ -21,4 +21,4 @@ interface RendererInterface * @return string */ public function renderAuthorize(array $data = []); -} \ No newline at end of file +} From 7293ff9e9dd88bae777c84549edf191e7e1bfe44 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 17 Mar 2016 11:49:05 +0000 Subject: [PATCH 316/444] Updated zendframework/zend-diactoros from ~1.1 to ^1.1 --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 1c129543..1834d999 100644 --- a/composer.json +++ b/composer.json @@ -5,8 +5,8 @@ "license": "MIT", "require": { "php": ">=5.5.9", - "league/event": "~2.1", - "zendframework/zend-diactoros": "~1.1", + "league/event": "^2.1", + "zendframework/zend-diactoros": "^1.1", "lcobucci/jwt": "^3.1", "paragonie/random_compat": "^1.1" }, From 251190d8282cda89a37f688e172776153df811f6 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 17 Mar 2016 14:37:21 +0000 Subject: [PATCH 317/444] Fix #468 and #473 --- composer.json | 4 +- .../AuthorizationValidatorInterface.php | 18 ++++ .../BearerTokenValidator.php | 66 ++++++++++++ src/{Utils/KeyCrypt.php => CryptTrait.php} | 60 ++++++++--- src/Exception/OAuthServerException.php | 47 ++------ src/Grant/AbstractAuthorizeGrant.php | 13 +++ src/Grant/AbstractGrant.php | 29 +---- src/Grant/AuthCodeGrant.php | 89 +++++++++------- src/Grant/GrantTypeInterface.php | 4 +- src/Grant/ImplicitGrant.php | 75 +++++++------ src/Grant/RefreshTokenGrant.php | 3 +- src/ResponseTypes/AbstractResponseType.php | 22 +--- src/ResponseTypes/BearerTokenResponse.php | 48 +-------- src/ResponseTypes/HtmlResponse.php | 66 ++++++++++++ src/ResponseTypes/RedirectResponse.php | 31 ++++++ src/ResponseTypes/ResponseTypeInterface.php | 11 -- src/Server.php | 100 ++++++++++-------- 17 files changed, 415 insertions(+), 271 deletions(-) create mode 100644 src/AuthorizationValidators/AuthorizationValidatorInterface.php create mode 100644 src/AuthorizationValidators/BearerTokenValidator.php rename src/{Utils/KeyCrypt.php => CryptTrait.php} (64%) create mode 100644 src/ResponseTypes/HtmlResponse.php create mode 100644 src/ResponseTypes/RedirectResponse.php diff --git a/composer.json b/composer.json index 1834d999..c5a6cbbd 100644 --- a/composer.json +++ b/composer.json @@ -6,9 +6,9 @@ "require": { "php": ">=5.5.9", "league/event": "^2.1", - "zendframework/zend-diactoros": "^1.1", "lcobucci/jwt": "^3.1", - "paragonie/random_compat": "^1.1" + "paragonie/random_compat": "^1.1", + "psr/http-message": "^1.0" }, "require-dev": { "phpunit/phpunit": "^4.8", diff --git a/src/AuthorizationValidators/AuthorizationValidatorInterface.php b/src/AuthorizationValidators/AuthorizationValidatorInterface.php new file mode 100644 index 00000000..2ed2a1ee --- /dev/null +++ b/src/AuthorizationValidators/AuthorizationValidatorInterface.php @@ -0,0 +1,18 @@ +accessTokenRepository = $accessTokenRepository; + } + + /** + * {@inheritdoc} + */ + public function validateAuthorization(ServerRequestInterface $request) + { + if ($request->hasHeader('authorization') === false) { + throw OAuthServerException::accessDenied('Missing "Authorization" header'); + } + + $header = $request->getHeader('authorization'); + $jwt = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header[0])); + + try { + // Attempt to parse and validate the JWT + $token = (new Parser())->parse($jwt); + if ($token->verify(new Sha256(), $this->publicKeyPath) === false) { + throw OAuthServerException::accessDenied('Access token could not be verified'); + } + + // Check if token has been revoked + if ($this->accessTokenRepository->isAccessTokenRevoked($token->getClaim('jti'))) { + throw OAuthServerException::accessDenied('Access token has been revoked'); + } + + // Return the request with additional attributes + return $request + ->withAttribute('oauth_access_token_id', $token->getClaim('jti')) + ->withAttribute('oauth_client_id', $token->getClaim('aud')) + ->withAttribute('oauth_user_id', $token->getClaim('sub')) + ->withAttribute('oauth_scopes', $token->getClaim('scopes')); + } catch (\InvalidArgumentException $exception) { + // JWT couldn't be parsed so return the request as is + throw OAuthServerException::accessDenied($exception->getMessage()); + } + } +} \ No newline at end of file diff --git a/src/Utils/KeyCrypt.php b/src/CryptTrait.php similarity index 64% rename from src/Utils/KeyCrypt.php rename to src/CryptTrait.php index 48659bde..3c649762 100644 --- a/src/Utils/KeyCrypt.php +++ b/src/CryptTrait.php @@ -8,24 +8,61 @@ * * @link https://github.com/thephpleague/oauth2-server */ -namespace League\OAuth2\Server\Utils; +namespace League\OAuth2\Server; -class KeyCrypt +trait CryptTrait { + /** + * @var string + */ + protected $privateKeyPath; + + /** + * @var string + */ + protected $publicKeyPath; + + /** + * Set path to private key. + * + * @param string $privateKeyPath + */ + public function setPrivateKeyPath($privateKeyPath) + { + if (strpos($privateKeyPath, 'file://') !== 0) { + $privateKeyPath = 'file://' . $privateKeyPath; + } + + $this->privateKeyPath = $privateKeyPath; + } + + /** + * Set path to public key. + * + * @param string $publicKeyPath + */ + public function setPublicKeyPath($publicKeyPath) + { + if (strpos($publicKeyPath, 'file://') !== 0) { + $publicKeyPath = 'file://' . $publicKeyPath; + } + + $this->publicKeyPath = $publicKeyPath; + } + /** * Encrypt data with a private key. * * @param string $unencryptedData - * @param string $pathToPrivateKey * * @return string */ - public static function encrypt($unencryptedData, $pathToPrivateKey) + protected function encrypt($unencryptedData) { - $privateKey = openssl_pkey_get_private($pathToPrivateKey); + $privateKey = openssl_pkey_get_private($this->privateKeyPath); $privateKeyDetails = @openssl_pkey_get_details($privateKey); if ($privateKeyDetails === null) { - throw new \LogicException(sprintf('Could not get details of private key: %s', $pathToPrivateKey)); + throw new \LogicException(sprintf('Could not get details of private key: %s', $this->privateKeyPath)); } $chunkSize = ceil($privateKeyDetails['bits'] / 8) - 11; @@ -50,18 +87,17 @@ class KeyCrypt * Decrypt data with a public key. * * @param string $encryptedData - * @param string $pathToPublicKey * * @throws \LogicException * * @return string */ - public static function decrypt($encryptedData, $pathToPublicKey) + protected function decrypt($encryptedData) { - $publicKey = openssl_pkey_get_public($pathToPublicKey); + $publicKey = openssl_pkey_get_public($this->publicKeyPath); $publicKeyDetails = @openssl_pkey_get_details($publicKey); if ($publicKeyDetails === null) { - throw new \LogicException(sprintf('Could not get details of public key: %s', $pathToPublicKey)); + throw new \LogicException(sprintf('Could not get details of public key: %s', $this->publicKeyPath)); } $chunkSize = ceil($publicKeyDetails['bits'] / 8); @@ -72,7 +108,7 @@ class KeyCrypt while ($encryptedData) { $chunk = substr($encryptedData, 0, $chunkSize); $encryptedData = substr($encryptedData, $chunkSize); - if (openssl_public_decrypt($chunk, $decrypted, $publicKey) === false) { + if (openssl_public_decrypt($chunk, $decrypted, $publicKey, OPENSSL_PKCS1_OAEP_PADDING) === false) { // @codeCoverageIgnoreStart throw new \LogicException('Failed to decrypt data'); // @codeCoverageIgnoreEnd @@ -83,4 +119,4 @@ class KeyCrypt return $output; } -} +} \ No newline at end of file diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index b61d1183..1f08919c 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -3,9 +3,6 @@ namespace League\OAuth2\Server\Exception; use Psr\Http\Message\ResponseInterface; -use Zend\Diactoros\Response; -use Zend\Diactoros\ServerRequest; -use Zend\Diactoros\Uri; class OAuthServerException extends \Exception { @@ -183,12 +180,8 @@ class OAuthServerException extends \Exception * * @return \Psr\Http\Message\ResponseInterface */ - public function generateHttpResponse(ResponseInterface $response = null, $useFragment = false) + public function generateHttpResponse(ResponseInterface $response, $useFragment = false) { - if (!$response instanceof ResponseInterface) { - $response = new Response(); - } - $headers = $this->getHttpHeaders(); $payload = [ @@ -201,18 +194,13 @@ class OAuthServerException extends \Exception } if ($this->redirectUri !== null) { - $redirectUri = new Uri($this->redirectUri); - parse_str($redirectUri->getQuery(), $redirectPayload); - if ($useFragment === true) { - $headers['Location'] = (string) $redirectUri->withFragment(http_build_query( - array_merge($redirectPayload, $payload) - )); + $this->redirectUri .= (strstr($this->redirectUri, '#') === false) ? '#' : '&'; } else { - $headers['Location'] = (string) $redirectUri->withQuery(http_build_query( - array_merge($redirectPayload, $payload) - )); + $this->redirectUri .= (strstr($this->redirectUri, '?') === false) ? '?' : '&'; } + + return $response->withStatus(302)->withHeader('Location', $this->redirectUri . http_build_query($payload)); } foreach ($headers as $header => $content) { @@ -245,29 +233,14 @@ class OAuthServerException extends \Exception // matching the authentication scheme used by the client. // @codeCoverageIgnoreStart if ($this->errorType === 'invalid_client') { - $authScheme = null; - $request = new ServerRequest(); - if (isset($request->getServerParams()['PHP_AUTH_USER']) && - $request->getServerParams()['PHP_AUTH_USER'] !== null + $authScheme = 'Basic'; + if (array_key_exists('HTTP_AUTHORIZATION', $_SERVER) !== false + && strpos($_SERVER['HTTP_AUTHORIZATION'], 'Bearer') === 0 ) { - $authScheme = 'Basic'; - } else { - $authHeader = $request->getHeader('authorization'); - if ($authHeader !== []) { - if (strpos($authHeader[0], 'Bearer') === 0) { - $authScheme = 'Bearer'; - } elseif (strpos($authHeader[0], 'MAC') === 0) { - $authScheme = 'MAC'; - } elseif (strpos($authHeader[0], 'Basic') === 0) { - $authScheme = 'Basic'; - } - } - } - if ($authScheme !== null) { - $headers[] = 'WWW-Authenticate: ' . $authScheme . ' realm="OAuth"'; + $authScheme = 'Bearer'; } + $headers[] = 'WWW-Authenticate: ' . $authScheme . ' realm="OAuth"'; } - // @codeCoverageIgnoreEnd return $headers; } diff --git a/src/Grant/AbstractAuthorizeGrant.php b/src/Grant/AbstractAuthorizeGrant.php index bab3ee01..7c08dccf 100644 --- a/src/Grant/AbstractAuthorizeGrant.php +++ b/src/Grant/AbstractAuthorizeGrant.php @@ -39,4 +39,17 @@ abstract class AbstractAuthorizeGrant extends AbstractGrant return $this->templateRenderer; } + + /** + * @param string $uri + * @param array $params + * @param string $queryDelimiter + * + * @return string + */ + public function makeRedirectUri($uri, $params = [], $queryDelimiter = '?') + { + $uri .= (strstr($uri, $queryDelimiter) === false) ? $queryDelimiter : '&'; + return $uri . http_build_query($params); + } } diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 6b3f21ba..49b03741 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -12,6 +12,7 @@ namespace League\OAuth2\Server\Grant; use League\Event\EmitterAwareTrait; use League\Event\Event; +use League\OAuth2\Server\CryptTrait; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\AuthCodeEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; @@ -32,7 +33,7 @@ use Psr\Http\Message\ServerRequestInterface; */ abstract class AbstractGrant implements GrantTypeInterface { - use EmitterAwareTrait; + use EmitterAwareTrait, CryptTrait; const SCOPE_DELIMITER_STRING = ' '; @@ -71,16 +72,6 @@ abstract class AbstractGrant implements GrantTypeInterface */ protected $userRepository; - /** - * @var string - */ - protected $pathToPrivateKey; - - /** - * @var string - */ - protected $pathToPublicKey; - /** * @var \DateInterval */ @@ -134,22 +125,6 @@ abstract class AbstractGrant implements GrantTypeInterface $this->userRepository = $userRepository; } - /** - * @param string $pathToPrivateKey - */ - public function setPathToPrivateKey($pathToPrivateKey) - { - $this->pathToPrivateKey = $pathToPrivateKey; - } - - /** - * @param string $pathToPublicKey - */ - public function setPathToPublicKey($pathToPublicKey) - { - $this->pathToPublicKey = $pathToPublicKey; - } - /** * {@inheritdoc} */ diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index a3fb2e34..10ccb1e8 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -10,12 +10,11 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\ResponseTypes\HtmlResponse; +use League\OAuth2\Server\ResponseTypes\RedirectResponse; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\TemplateRenderer\AbstractRenderer; -use League\OAuth2\Server\Utils\KeyCrypt; use Psr\Http\Message\ServerRequestInterface; -use Zend\Diactoros\Response; -use Zend\Diactoros\Uri; class AuthCodeGrant extends AbstractAuthorizeGrant { @@ -88,13 +87,11 @@ class AuthCodeGrant extends AbstractAuthorizeGrant $client, $client->getRedirectUri() ); - $queryString = http_build_query($request->getQueryParams()); - $postbackUri = new Uri( - sprintf( - '//%s%s', - $request->getServerParams()['HTTP_HOST'], - $request->getServerParams()['REQUEST_URI'] - ) + + $postbackUri = sprintf( + '//%s%s', + $request->getServerParams()['HTTP_HOST'], + $request->getServerParams()['REQUEST_URI'] ); $userId = null; @@ -107,7 +104,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant $oauthCookie = $this->getCookieParameter('oauth_authorize_request', $request, null); if ($oauthCookie !== null) { try { - $oauthCookiePayload = json_decode(KeyCrypt::decrypt($oauthCookie, $this->pathToPublicKey)); + $oauthCookiePayload = json_decode($this->decrypt($oauthCookie)); if (is_object($oauthCookiePayload)) { $userId = $oauthCookiePayload->user_id; } @@ -140,10 +137,16 @@ class AuthCodeGrant extends AbstractAuthorizeGrant if ($userId === null) { $html = $this->getTemplateRenderer()->renderLogin([ 'error' => $loginError, - 'postback_uri' => (string) $postbackUri->withQuery($queryString), + 'postback_uri' => $this->makeRedirectUri( + $postbackUri, + $request->getQueryParams() + ), ]); - return new Response\HtmlResponse($html); + $htmlResponse = new HtmlResponse($this->accessTokenRepository); + $htmlResponse->setStatusCode(403); + $htmlResponse->setHtml($html); + return $htmlResponse; } // The user hasn't approved the client yet so show an authorize form @@ -151,30 +154,31 @@ class AuthCodeGrant extends AbstractAuthorizeGrant $html = $this->getTemplateRenderer()->renderAuthorize([ 'client' => $client, 'scopes' => $scopes, - 'postback_uri' => (string) $postbackUri->withQuery($queryString), + 'postback_uri' => $this->makeRedirectUri( + $postbackUri, + $request->getQueryParams() + ), ]); - 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') - ), - ] - ); + $htmlResponse = new HtmlResponse($this->accessTokenRepository); + $htmlResponse->setStatusCode(200); + $htmlResponse->setHtml($html); + $htmlResponse->setHeader('set-cookie', sprintf( + 'oauth_authorize_request=%s; Expires=%s', + urlencode($this->encrypt( + json_encode([ + 'user_id' => $userId, + ]) + )), + (new \DateTime())->add(new \DateInterval('PT5M'))->format('D, d M Y H:i:s e') + )); + + return $htmlResponse; } // The user has either approved or denied the client, so redirect them back - $redirectUri = new Uri($client->getRedirectUri()); - parse_str($redirectUri->getQuery(), $redirectPayload); + $redirectUri = $client->getRedirectUri(); + $redirectPayload = []; $stateParameter = $this->getQueryStringParameter('state', $request); if ($stateParameter !== null) { @@ -191,7 +195,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant $scopes ); - $redirectPayload['code'] = KeyCrypt::encrypt( + $redirectPayload['code'] = $this->encrypt( json_encode( [ 'client_id' => $authCode->getClient()->getIdentifier(), @@ -201,17 +205,22 @@ class AuthCodeGrant extends AbstractAuthorizeGrant 'user_id' => $authCode->getUserIdentifier(), 'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'), ] - ), - $this->pathToPrivateKey + ) ); - return new Response\RedirectResponse($redirectUri->withQuery(http_build_query($redirectPayload))); + $response = new RedirectResponse($this->accessTokenRepository); + $response->setRedirectUri( + $this->makeRedirectUri( + $redirectUri, + $redirectPayload + ) + ); + + return $response; } // The user denied the client, redirect them back with an error - $exception = OAuthServerException::accessDenied('The user denied the request', (string) $redirectUri); - - return $exception->generateHttpResponse(); + throw OAuthServerException::accessDenied('The user denied the request', (string) $redirectUri); } /** @@ -246,7 +255,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant // Validate the authorization code try { - $authCodePayload = json_decode(KeyCrypt::decrypt($encryptedAuthCode, $this->pathToPublicKey)); + $authCodePayload = json_decode($this->decrypt($encryptedAuthCode)); if (time() > $authCodePayload->expire_time) { throw OAuthServerException::invalidRequest('code', 'Authorization code has expired'); } diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 5ddd81b8..8e7572c2 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -91,12 +91,12 @@ interface GrantTypeInterface extends EmitterAwareInterface * * @param string $pathToPrivateKey */ - public function setPathToPrivateKey($pathToPrivateKey); + public function setPrivateKeyPath($pathToPrivateKey); /** * Set the path to the public key. * * @param string $pathToPublicKey */ - public function setPathToPublicKey($pathToPublicKey); + public function setPublicKeyPath($pathToPublicKey); } diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 89a3c2e6..3fd567d4 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -7,12 +7,11 @@ use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\ResponseTypes\HtmlResponse; +use League\OAuth2\Server\ResponseTypes\RedirectResponse; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\TemplateRenderer\AbstractRenderer; -use League\OAuth2\Server\Utils\KeyCrypt; use Psr\Http\Message\ServerRequestInterface; -use Zend\Diactoros\Response; -use Zend\Diactoros\Uri; class ImplicitGrant extends AbstractAuthorizeGrant { @@ -86,13 +85,11 @@ class ImplicitGrant extends AbstractAuthorizeGrant $client, $client->getRedirectUri() ); - $queryString = http_build_query($request->getQueryParams()); - $postbackUri = new Uri( - sprintf( - '//%s%s', - $request->getServerParams()['HTTP_HOST'], - $request->getServerParams()['REQUEST_URI'] - ) + + $postbackUri = sprintf( + '//%s%s', + $request->getServerParams()['HTTP_HOST'], + $request->getServerParams()['REQUEST_URI'] ); $userId = null; @@ -105,7 +102,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant $oauthCookie = $this->getCookieParameter('oauth_authorize_request', $request, null); if ($oauthCookie !== null) { try { - $oauthCookiePayload = json_decode(KeyCrypt::decrypt($oauthCookie, $this->pathToPublicKey)); + $oauthCookiePayload = json_decode($this->decrypt($oauthCookie)); if (is_object($oauthCookiePayload)) { $userId = $oauthCookiePayload->user_id; } @@ -138,10 +135,16 @@ class ImplicitGrant extends AbstractAuthorizeGrant if ($userId === null) { $html = $this->getTemplateRenderer()->renderLogin([ 'error' => $loginError, - 'postback_uri' => (string) $postbackUri->withQuery($queryString), + 'postback_uri' => $this->makeRedirectUri( + $postbackUri, + $request->getQueryParams() + ), ]); - return new Response\HtmlResponse($html); + $htmlResponse = new HtmlResponse($this->accessTokenRepository); + $htmlResponse->setStatusCode(403); + $htmlResponse->setHtml($html); + return $htmlResponse; } // The user hasn't approved the client yet so show an authorize form @@ -149,25 +152,26 @@ class ImplicitGrant extends AbstractAuthorizeGrant $html = $this->getTemplateRenderer()->renderAuthorize([ 'client' => $client, 'scopes' => $scopes, - 'postback_uri' => (string) $postbackUri->withQuery($queryString), + 'postback_uri' => $this->makeRedirectUri( + $postbackUri, + $request->getQueryParams() + ) ]); - 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') - ), - ] - ); + $htmlResponse = new HtmlResponse($this->accessTokenRepository); + $htmlResponse->setStatusCode(200); + $htmlResponse->setHtml($html); + $htmlResponse->setHeader('set-cookie', sprintf( + 'oauth_authorize_request=%s; Expires=%s', + urlencode($this->encrypt( + json_encode([ + 'user_id' => $userId, + ]) + )), + (new \DateTime())->add(new \DateInterval('PT5M'))->format('D, d M Y H:i:s e') + )); + + return $htmlResponse; } // The user has either approved or denied the client, so redirect them back @@ -188,11 +192,18 @@ class ImplicitGrant extends AbstractAuthorizeGrant $scopes ); - $redirectPayload['access_token'] = (string) $accessToken->convertToJWT($this->pathToPrivateKey); + $redirectPayload['access_token'] = (string) $accessToken->convertToJWT($this->privateKeyPath); $redirectPayload['token_type'] = 'bearer'; $redirectPayload['expires_in'] = time() - $accessToken->getExpiryDateTime()->getTimestamp(); - return new Response\RedirectResponse($redirectUri->withFragment(http_build_query($redirectPayload))); + $response = new RedirectResponse($this->accessTokenRepository); + $response->setRedirectUri( + $this->makeRedirectUri( + $redirectUri, + $redirectPayload, + '#' + ) + ); } // The user denied the client, redirect them back with an error diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index a03bdc90..be0d803e 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -14,7 +14,6 @@ use League\Event\Event; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; -use League\OAuth2\Server\Utils\KeyCrypt; use Psr\Http\Message\ServerRequestInterface; /** @@ -106,7 +105,7 @@ class RefreshTokenGrant extends AbstractGrant // Validate refresh token try { - $refreshToken = KeyCrypt::decrypt($encryptedRefreshToken, $this->pathToPublicKey); + $refreshToken = $this->decrypt($encryptedRefreshToken); } catch (\LogicException $e) { throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: ' . $e->getMessage()); } diff --git a/src/ResponseTypes/AbstractResponseType.php b/src/ResponseTypes/AbstractResponseType.php index a64bfded..e693d85b 100644 --- a/src/ResponseTypes/AbstractResponseType.php +++ b/src/ResponseTypes/AbstractResponseType.php @@ -10,21 +10,14 @@ */ namespace League\OAuth2\Server\ResponseTypes; +use League\OAuth2\Server\CryptTrait; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; abstract class AbstractResponseType implements ResponseTypeInterface { - /** - * @var string - */ - protected $pathToPrivateKey; - - /** - * @var string - */ - protected $pathToPublicKey; + use CryptTrait; /** * @var \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface @@ -42,17 +35,10 @@ abstract class AbstractResponseType implements ResponseTypeInterface protected $accessTokenRepository; /** - * @param string $pathToPrivateKey - * @param string $pathToPublicKey * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository */ - public function __construct( - $pathToPrivateKey, - $pathToPublicKey, - AccessTokenRepositoryInterface $accessTokenRepository - ) { - $this->pathToPrivateKey = $pathToPrivateKey; - $this->pathToPublicKey = $pathToPublicKey; + public function __construct(AccessTokenRepositoryInterface $accessTokenRepository) + { $this->accessTokenRepository = $accessTokenRepository; } diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index 04295895..17675b88 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -10,13 +10,8 @@ */ namespace League\OAuth2\Server\ResponseTypes; -use Lcobucci\JWT\Parser; -use Lcobucci\JWT\Signer\Rsa\Sha256; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; -use League\OAuth2\Server\Exception\OAuthServerException; -use League\OAuth2\Server\Utils\KeyCrypt; use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\ServerRequestInterface; class BearerTokenResponse extends AbstractResponseType { @@ -27,7 +22,7 @@ class BearerTokenResponse extends AbstractResponseType { $expireDateTime = $this->accessToken->getExpiryDateTime()->getTimestamp(); - $jwtAccessToken = $this->accessToken->convertToJWT($this->pathToPrivateKey); + $jwtAccessToken = $this->accessToken->convertToJWT($this->privateKeyPath); $responseParams = [ 'token_type' => 'Bearer', @@ -36,7 +31,7 @@ class BearerTokenResponse extends AbstractResponseType ]; if ($this->refreshToken instanceof RefreshTokenEntityInterface) { - $refreshToken = KeyCrypt::encrypt( + $refreshToken = $this->encrypt( json_encode( [ 'client_id' => $this->accessToken->getClient()->getIdentifier(), @@ -46,8 +41,7 @@ class BearerTokenResponse extends AbstractResponseType 'user_id' => $this->accessToken->getUserIdentifier(), 'expire_time' => $expireDateTime, ] - ), - $this->pathToPrivateKey + ) ); $responseParams['refresh_token'] = $refreshToken; @@ -63,40 +57,4 @@ class BearerTokenResponse extends AbstractResponseType return $response; } - - /** - * {@inheritdoc} - */ - public function validateAccessToken(ServerRequestInterface $request) - { - if ($request->hasHeader('authorization') === false) { - throw OAuthServerException::accessDenied('Missing "Authorization" header'); - } - - $header = $request->getHeader('authorization'); - $jwt = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header[0])); - - try { - // Attempt to parse and validate the JWT - $token = (new Parser())->parse($jwt); - if ($token->verify(new Sha256(), $this->pathToPublicKey) === false) { - throw OAuthServerException::accessDenied('Access token could not be verified'); - } - - // Check if token has been revoked - if ($this->accessTokenRepository->isAccessTokenRevoked($token->getClaim('jti'))) { - throw OAuthServerException::accessDenied('Access token has been revoked'); - } - - // Return the request with additional attributes - return $request - ->withAttribute('oauth_access_token_id', $token->getClaim('jti')) - ->withAttribute('oauth_client_id', $token->getClaim('aud')) - ->withAttribute('oauth_user_id', $token->getClaim('sub')) - ->withAttribute('oauth_scopes', $token->getClaim('scopes')); - } catch (\InvalidArgumentException $exception) { - // JWT couldn't be parsed so return the request as is - throw OAuthServerException::accessDenied($exception->getMessage()); - } - } } diff --git a/src/ResponseTypes/HtmlResponse.php b/src/ResponseTypes/HtmlResponse.php new file mode 100644 index 00000000..ad05f53e --- /dev/null +++ b/src/ResponseTypes/HtmlResponse.php @@ -0,0 +1,66 @@ +html = $html; + } + + /** + * @param int $statusCode + */ + public function setStatusCode($statusCode = 200) + { + $this->statusCode = $statusCode; + } + + /** + * @param ResponseInterface $response + * + * @return ResponseInterface + */ + public function generateHttpResponse(ResponseInterface $response) + { + $response->getBody()->write($this->html); + + foreach ($this->headers as $key => $value) { + $response = $response->withHeader($key, $value); + } + + return $response + ->withStatus($this->statusCode) + ->withHeader('content-type', 'text/html'); + } + + /** + * @param string $key + * @param string $value + */ + public function setHeader($key, $value) + { + $this->headers[$key] = $value; + } +} \ No newline at end of file diff --git a/src/ResponseTypes/RedirectResponse.php b/src/ResponseTypes/RedirectResponse.php new file mode 100644 index 00000000..d171a12d --- /dev/null +++ b/src/ResponseTypes/RedirectResponse.php @@ -0,0 +1,31 @@ +redirectUri = $redirectUri; + } + + /** + * @param ResponseInterface $response + * + * @return ResponseInterface + */ + public function generateHttpResponse(ResponseInterface $response) + { + return $response->withStatus(302)->withHeader('location', $this->redirectUri); + } +} \ No newline at end of file diff --git a/src/ResponseTypes/ResponseTypeInterface.php b/src/ResponseTypes/ResponseTypeInterface.php index 982ef2b1..100e8cda 100644 --- a/src/ResponseTypes/ResponseTypeInterface.php +++ b/src/ResponseTypes/ResponseTypeInterface.php @@ -13,7 +13,6 @@ namespace League\OAuth2\Server\ResponseTypes; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\ServerRequestInterface; interface ResponseTypeInterface { @@ -27,16 +26,6 @@ interface ResponseTypeInterface */ public function setRefreshToken(RefreshTokenEntityInterface $refreshToken); - /** - * Determine the access token in the authorization header and append OAUth properties to the request - * as attributes. - * - * @param ServerRequestInterface $request - * - * @return ServerRequestInterface - */ - public function validateAccessToken(ServerRequestInterface $request); - /** * @param ResponseInterface $response * diff --git a/src/Server.php b/src/Server.php index 13765727..30bfd194 100644 --- a/src/Server.php +++ b/src/Server.php @@ -5,6 +5,8 @@ namespace League\OAuth2\Server; use DateInterval; use League\Event\EmitterAwareInterface; use League\Event\EmitterAwareTrait; +use League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface; +use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\GrantTypeInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -14,8 +16,6 @@ use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -use Zend\Diactoros\Response; -use Zend\Diactoros\ServerRequestFactory; class Server implements EmitterAwareInterface { @@ -61,15 +61,21 @@ class Server implements EmitterAwareInterface */ private $scopeRepository; + /** + * @var \League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface + */ + private $authorizationValidator; + /** * New server instance. * - * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository - * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository - * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository - * @param string $privateKeyPath - * @param string $publicKeyPath - * @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType + * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository + * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository + * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository + * @param string $privateKeyPath + * @param string $publicKeyPath + * @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType + * @param null|\League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface $authorizationValidator */ public function __construct( ClientRepositoryInterface $clientRepository, @@ -77,7 +83,8 @@ class Server implements EmitterAwareInterface ScopeRepositoryInterface $scopeRepository, $privateKeyPath, $publicKeyPath, - ResponseTypeInterface $responseType = null + ResponseTypeInterface $responseType = null, + AuthorizationValidatorInterface $authorizationValidator = null ) { $this->clientRepository = $clientRepository; $this->accessTokenRepository = $accessTokenRepository; @@ -85,6 +92,7 @@ class Server implements EmitterAwareInterface $this->privateKeyPath = $privateKeyPath; $this->publicKeyPath = $publicKeyPath; $this->responseType = $responseType; + $this->authorizationValidator = $authorizationValidator; } /** @@ -98,8 +106,8 @@ class Server implements EmitterAwareInterface $grantType->setAccessTokenRepository($this->accessTokenRepository); $grantType->setClientRepository($this->clientRepository); $grantType->setScopeRepository($this->scopeRepository); - $grantType->setPathToPrivateKey($this->privateKeyPath); - $grantType->setPathToPublicKey($this->publicKeyPath); + $grantType->setPrivateKeyPath($this->privateKeyPath); + $grantType->setPublicKeyPath($this->publicKeyPath); $grantType->setEmitter($this->getEmitter()); $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; @@ -117,37 +125,29 @@ class Server implements EmitterAwareInterface * * @return \Psr\Http\Message\ResponseInterface */ - public function respondToRequest(ServerRequestInterface $request = null, ResponseInterface $response = null) + public function respondToRequest(ServerRequestInterface $request, ResponseInterface $response) { - if (!$request instanceof ServerRequestInterface) { - $request = ServerRequestFactory::fromGlobals(); - } - - if (!$response instanceof ResponseInterface) { - $response = new Response(); - } - - $tokenResponse = null; - while ($tokenResponse === null && $grantType = array_shift($this->enabledGrantTypes)) { - /** @var \League\OAuth2\Server\Grant\GrantTypeInterface $grantType */ - if ($grantType->canRespondToRequest($request)) { - $tokenResponse = $grantType->respondToRequest( - $request, - $this->getResponseType(), - $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] - ); + try { + $tokenResponse = null; + while ($tokenResponse === null && $grantType = array_shift($this->enabledGrantTypes)) { + /** @var \League\OAuth2\Server\Grant\GrantTypeInterface $grantType */ + if ($grantType->canRespondToRequest($request)) { + $tokenResponse = $grantType->respondToRequest( + $request, + $this->getResponseType(), + $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] + ); + } } - } - if ($tokenResponse instanceof ResponseInterface) { - return $tokenResponse; - } + if ($tokenResponse instanceof ResponseTypeInterface) { + return $tokenResponse->generateHttpResponse($response); + } - if ($tokenResponse instanceof ResponseTypeInterface) { - return $tokenResponse->generateHttpResponse($response); + throw OAuthServerException::unsupportedGrantType(); + } catch (OAuthServerException $e) { + return $e->generateHttpResponse($response); } - - throw OAuthServerException::unsupportedGrantType(); } /** @@ -161,7 +161,7 @@ class Server implements EmitterAwareInterface */ public function validateAuthenticatedRequest(ServerRequestInterface $request) { - return $this->getResponseType()->validateAccessToken($request); + return $this->getAuthorizationValidator()->validateAuthorization($request); } /** @@ -172,13 +172,27 @@ class Server implements EmitterAwareInterface protected function getResponseType() { if (!$this->responseType instanceof ResponseTypeInterface) { - $this->responseType = new BearerTokenResponse( - $this->privateKeyPath, - $this->publicKeyPath, - $this->accessTokenRepository - ); + $this->responseType = new BearerTokenResponse($this->accessTokenRepository); } + $this->responseType->setPublicKeyPath($this->publicKeyPath); + $this->responseType->setPrivateKeyPath($this->privateKeyPath); + return $this->responseType; } + + /** + * @return \League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface + */ + protected function getAuthorizationValidator() + { + if (!$this->authorizationValidator instanceof AuthorizationValidatorInterface) { + $this->authorizationValidator = new BearerTokenValidator($this->accessTokenRepository); + } + + $this->authorizationValidator->setPublicKeyPath($this->publicKeyPath); + $this->authorizationValidator->setPrivateKeyPath($this->privateKeyPath); + + return $this->authorizationValidator; + } } From 51a1a75d37b23e41ea840d504cb996dc375323aa Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 17 Mar 2016 10:37:48 -0400 Subject: [PATCH 318/444] Applied fixes from StyleCI --- .../AuthorizationValidatorInterface.php | 2 +- src/AuthorizationValidators/BearerTokenValidator.php | 8 ++++---- src/CryptTrait.php | 2 +- src/Grant/AbstractAuthorizeGrant.php | 1 + src/Grant/AuthCodeGrant.php | 1 + src/Grant/ImplicitGrant.php | 3 ++- src/ResponseTypes/HtmlResponse.php | 2 +- src/ResponseTypes/RedirectResponse.php | 2 +- src/Server.php | 12 ++++++------ 9 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/AuthorizationValidators/AuthorizationValidatorInterface.php b/src/AuthorizationValidators/AuthorizationValidatorInterface.php index 2ed2a1ee..9fc24891 100644 --- a/src/AuthorizationValidators/AuthorizationValidatorInterface.php +++ b/src/AuthorizationValidators/AuthorizationValidatorInterface.php @@ -15,4 +15,4 @@ interface AuthorizationValidatorInterface * @return ServerRequestInterface */ public function validateAuthorization(ServerRequestInterface $request); -} \ No newline at end of file +} diff --git a/src/AuthorizationValidators/BearerTokenValidator.php b/src/AuthorizationValidators/BearerTokenValidator.php index 62d25abc..5dab2203 100644 --- a/src/AuthorizationValidators/BearerTokenValidator.php +++ b/src/AuthorizationValidators/BearerTokenValidator.php @@ -2,12 +2,12 @@ namespace League\OAuth2\Server\AuthorizationValidators; -use League\OAuth2\Server\CryptTrait; -use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; -use Psr\Http\Message\ServerRequestInterface; use Lcobucci\JWT\Parser; use Lcobucci\JWT\Signer\Rsa\Sha256; +use League\OAuth2\Server\CryptTrait; use League\OAuth2\Server\Exception\OAuthServerException; +use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; +use Psr\Http\Message\ServerRequestInterface; class BearerTokenValidator implements AuthorizationValidatorInterface { @@ -63,4 +63,4 @@ class BearerTokenValidator implements AuthorizationValidatorInterface throw OAuthServerException::accessDenied($exception->getMessage()); } } -} \ No newline at end of file +} diff --git a/src/CryptTrait.php b/src/CryptTrait.php index 3c649762..844f810f 100644 --- a/src/CryptTrait.php +++ b/src/CryptTrait.php @@ -119,4 +119,4 @@ trait CryptTrait return $output; } -} \ No newline at end of file +} diff --git a/src/Grant/AbstractAuthorizeGrant.php b/src/Grant/AbstractAuthorizeGrant.php index 7c08dccf..e409d2b2 100644 --- a/src/Grant/AbstractAuthorizeGrant.php +++ b/src/Grant/AbstractAuthorizeGrant.php @@ -50,6 +50,7 @@ abstract class AbstractAuthorizeGrant extends AbstractGrant public function makeRedirectUri($uri, $params = [], $queryDelimiter = '?') { $uri .= (strstr($uri, $queryDelimiter) === false) ? $queryDelimiter : '&'; + return $uri . http_build_query($params); } } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 10ccb1e8..05ea1f38 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -146,6 +146,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant $htmlResponse = new HtmlResponse($this->accessTokenRepository); $htmlResponse->setStatusCode(403); $htmlResponse->setHtml($html); + return $htmlResponse; } diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 3fd567d4..7da987d7 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -144,6 +144,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant $htmlResponse = new HtmlResponse($this->accessTokenRepository); $htmlResponse->setStatusCode(403); $htmlResponse->setHtml($html); + return $htmlResponse; } @@ -155,7 +156,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant 'postback_uri' => $this->makeRedirectUri( $postbackUri, $request->getQueryParams() - ) + ), ]); $htmlResponse = new HtmlResponse($this->accessTokenRepository); diff --git a/src/ResponseTypes/HtmlResponse.php b/src/ResponseTypes/HtmlResponse.php index ad05f53e..11a92b9c 100644 --- a/src/ResponseTypes/HtmlResponse.php +++ b/src/ResponseTypes/HtmlResponse.php @@ -63,4 +63,4 @@ class HtmlResponse extends AbstractResponseType { $this->headers[$key] = $value; } -} \ No newline at end of file +} diff --git a/src/ResponseTypes/RedirectResponse.php b/src/ResponseTypes/RedirectResponse.php index d171a12d..d37e58e6 100644 --- a/src/ResponseTypes/RedirectResponse.php +++ b/src/ResponseTypes/RedirectResponse.php @@ -28,4 +28,4 @@ class RedirectResponse extends AbstractResponseType { return $response->withStatus(302)->withHeader('location', $this->redirectUri); } -} \ No newline at end of file +} diff --git a/src/Server.php b/src/Server.php index 30bfd194..5e0f2190 100644 --- a/src/Server.php +++ b/src/Server.php @@ -69,12 +69,12 @@ class Server implements EmitterAwareInterface /** * New server instance. * - * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository - * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository - * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository - * @param string $privateKeyPath - * @param string $publicKeyPath - * @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType + * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository + * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository + * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository + * @param string $privateKeyPath + * @param string $publicKeyPath + * @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType * @param null|\League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface $authorizationValidator */ public function __construct( From 890fdeba160fa37c1d2603db688c720dde5081bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Thu, 17 Mar 2016 21:18:28 +0100 Subject: [PATCH 319/444] CryptTrait tests --- src/Entities/AccessTokenEntity.php | 6 +- .../Interfaces/AccessTokenEntityInterface.php | 4 +- src/Grant/GrantTypeInterface.php | 8 +- tests/CryptTraitTest.php | 46 +++++++ tests/Grant/AbstractGrantTest.php | 4 +- tests/Grant/AuthCodeGrantTest.php | 124 ++++++++++-------- tests/Grant/ImplicitGrantTest.php | 67 ++++++---- tests/Grant/RefreshTokenGrantTest.php | 67 ++++++---- .../ResponseTypes/BearerResponseTypeTest.php | 20 +-- tests/Stubs/CryptTraitStub.php | 26 ++++ tests/{Utils => Stubs}/private.key | 0 tests/{Utils => Stubs}/public.key | 0 tests/Utils/KeyCryptTest.php | 34 ----- 13 files changed, 236 insertions(+), 170 deletions(-) create mode 100644 tests/CryptTraitTest.php create mode 100644 tests/Stubs/CryptTraitStub.php rename tests/{Utils => Stubs}/private.key (100%) rename tests/{Utils => Stubs}/public.key (100%) delete mode 100644 tests/Utils/KeyCryptTest.php diff --git a/src/Entities/AccessTokenEntity.php b/src/Entities/AccessTokenEntity.php index fc31a9fd..5b4b34a1 100644 --- a/src/Entities/AccessTokenEntity.php +++ b/src/Entities/AccessTokenEntity.php @@ -16,11 +16,11 @@ class AccessTokenEntity implements AccessTokenEntityInterface /** * Generate a JWT from the access token * - * @param string $pathToPrivateKey + * @param string $privateKeyPath * * @return string */ - public function convertToJWT($pathToPrivateKey) + public function convertToJWT($privateKeyPath) { return (new Builder()) ->setAudience($this->getClient()->getIdentifier()) @@ -30,7 +30,7 @@ class AccessTokenEntity implements AccessTokenEntityInterface ->setExpiration($this->getExpiryDateTime()->getTimestamp()) ->setSubject($this->getUserIdentifier()) ->set('scopes', $this->getScopes()) - ->sign(new Sha256(), new Key($pathToPrivateKey)) + ->sign(new Sha256(), new Key($privateKeyPath)) ->getToken(); } } diff --git a/src/Entities/Interfaces/AccessTokenEntityInterface.php b/src/Entities/Interfaces/AccessTokenEntityInterface.php index 884c0187..86ad1107 100644 --- a/src/Entities/Interfaces/AccessTokenEntityInterface.php +++ b/src/Entities/Interfaces/AccessTokenEntityInterface.php @@ -7,9 +7,9 @@ interface AccessTokenEntityInterface extends TokenInterface /** * Generate a JWT from the access token * - * @param string $pathToPrivateKey + * @param string $privateKeyPath * * @return string */ - public function convertToJWT($pathToPrivateKey); + public function convertToJWT($privateKeyPath); } diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 8e7572c2..cb60bf90 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -89,14 +89,14 @@ interface GrantTypeInterface extends EmitterAwareInterface /** * Set the path to the private key. * - * @param string $pathToPrivateKey + * @param string $privateKeyPath */ - public function setPrivateKeyPath($pathToPrivateKey); + public function setPrivateKeyPath($privateKeyPath); /** * Set the path to the public key. * - * @param string $pathToPublicKey + * @param string $publicKeyPath */ - public function setPublicKeyPath($pathToPublicKey); + public function setPublicKeyPath($publicKeyPath); } diff --git a/tests/CryptTraitTest.php b/tests/CryptTraitTest.php new file mode 100644 index 00000000..fad2fdcf --- /dev/null +++ b/tests/CryptTraitTest.php @@ -0,0 +1,46 @@ +cryptStub = new CryptTraitStub; + } + + public function testEncryptDecrypt() + { + $payload = 'alex loves whisky'; + $encrypted = $this->cryptStub->doEncrypt($payload); + $plainText = $this->cryptStub->doDecrypt($encrypted); + + $this->assertNotEquals($payload, $encrypted); + $this->assertEquals($payload, $plainText); + } + + /** + * @expectedException \LogicException + */ + public function testBadPrivateKey() + { + $this->cryptStub->setPrivateKeyPath(__DIR__ . '/Stubs/public.key'); + $this->cryptStub->doEncrypt(''); + } + + /** + * @expectedException \LogicException + */ + public function testBadPublicKey() + { + $this->cryptStub->setPublicKeyPath(__DIR__ . '/Stubs/private.key'); + $this->cryptStub->doDecrypt(''); + } +} diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 4820e3a2..5e71bdf7 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -23,8 +23,8 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase { /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); - $grantMock->setPathToPrivateKey('./private.key'); - $grantMock->setPathToPublicKey('./public.key'); + $grantMock->setPrivateKeyPath('./private.key'); + $grantMock->setPublicKeyPath('./public.key'); $grantMock->setEmitter(new Emitter()); } diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 54973d8e..31cd2f53 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -12,8 +12,8 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; -use League\OAuth2\Server\Utils\KeyCrypt; use LeagueTests\Stubs\ClientEntity; +use LeagueTests\Stubs\CryptTraitStub; use LeagueTests\Stubs\ScopeEntity; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; @@ -22,6 +22,16 @@ use Zend\Diactoros\ServerRequest; class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase { + /** + * CryptTrait stub + */ + protected $cryptStub; + + public function setUp() + { + $this->cryptStub = new CryptTraitStub; + } + public function testGetIdentifier() { $grant = new AuthCodeGrant( @@ -78,8 +88,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -92,9 +102,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => KeyCrypt::encrypt( + 'oauth_authorize_request' => $this->cryptStub->doEncrypt( json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ], [ @@ -133,8 +143,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -147,9 +157,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => KeyCrypt::encrypt( + 'oauth_authorize_request' => $this->cryptStub->doEncrypt( json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ], [ @@ -193,8 +203,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -207,9 +217,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => KeyCrypt::encrypt( + 'oauth_authorize_request' => $this->cryptStub->doEncrypt( json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ], [ @@ -244,8 +254,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -258,9 +268,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => KeyCrypt::encrypt( + 'oauth_authorize_request' => $this->cryptStub->doEncrypt( json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ], [ @@ -299,8 +309,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -313,9 +323,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => KeyCrypt::encrypt( + 'oauth_authorize_request' => $this->cryptStub->doEncrypt( json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ], [ @@ -360,8 +370,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -410,8 +420,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -424,9 +434,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => KeyCrypt::encrypt( + 'oauth_authorize_request' => $this->cryptStub->doEncrypt( json_encode(['user_id' => null]), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ], [ @@ -464,8 +474,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -478,9 +488,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => KeyCrypt::encrypt( + 'oauth_authorize_request' => $this->cryptStub->doEncrypt( json_encode(['user_id' => null]), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ], [ @@ -520,8 +530,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -534,9 +544,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => KeyCrypt::encrypt( + 'oauth_authorize_request' => $this->cryptStub->doEncrypt( json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ], [ @@ -587,8 +597,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setScopeRepository($scopeRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [], @@ -603,7 +613,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'grant_type' => 'authorization_code', 'client_id' => 'foo', 'redirect_uri' => 'http://foo/bar', - 'code' => KeyCrypt::encrypt( + 'code' => $this->cryptStub->doEncrypt( json_encode( [ 'auth_code_id' => uniqid(), @@ -614,7 +624,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'redirect_uri' => 'http://foo/bar', ] ), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ] ); @@ -646,8 +656,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [], @@ -692,8 +702,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [], @@ -743,8 +753,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [], @@ -759,7 +769,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'grant_type' => 'authorization_code', 'client_id' => 'foo', 'redirect_uri' => 'http://foo/bar', - 'code' => KeyCrypt::encrypt( + 'code' => $this->cryptStub->doEncrypt( json_encode( [ 'auth_code_id' => uniqid(), @@ -770,7 +780,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'redirect_uri' => 'http://foo/bar', ] ), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ] ); @@ -813,8 +823,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [], @@ -829,7 +839,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'grant_type' => 'authorization_code', 'client_id' => 'foo', 'redirect_uri' => 'http://foo/bar', - 'code' => KeyCrypt::encrypt( + 'code' => $this->cryptStub->doEncrypt( json_encode( [ 'auth_code_id' => uniqid(), @@ -840,7 +850,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'redirect_uri' => 'http://foo/bar', ] ), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ] ); @@ -880,8 +890,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [], @@ -896,7 +906,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'grant_type' => 'authorization_code', 'client_id' => 'foo', 'redirect_uri' => 'http://foo/bar', - 'code' => KeyCrypt::encrypt( + 'code' => $this->cryptStub->doEncrypt( json_encode( [ 'auth_code_id' => uniqid(), @@ -907,7 +917,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'redirect_uri' => 'http://foo/bar', ] ), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ] ); @@ -947,8 +957,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [], diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 5bc1156e..3c597978 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -7,7 +7,6 @@ use League\OAuth2\Server\Grant\ImplicitGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; -use League\OAuth2\Server\Utils\KeyCrypt; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; @@ -16,6 +15,16 @@ use Zend\Diactoros\ServerRequest; class ImplicitGrantTest extends \PHPUnit_Framework_TestCase { + /** + * CryptTrait stub + */ + protected $cryptStub; + + public function setUp() + { + $this->cryptStub = new CryptTraitStub; + } + public function testGetIdentifier() { $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); @@ -60,8 +69,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant($userRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -99,8 +108,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase public function testRespondToAuthorizationRequestMissingClientId() { $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -113,9 +122,9 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => KeyCrypt::encrypt( + 'oauth_authorize_request' => $this->cryptStub->doEncrypt( json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ], [ @@ -141,8 +150,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -155,9 +164,9 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => KeyCrypt::encrypt( + 'oauth_authorize_request' => $this->cryptStub->doEncrypt( json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ], [ @@ -191,8 +200,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -205,9 +214,9 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => KeyCrypt::encrypt( + 'oauth_authorize_request' => $this->cryptStub->doEncrypt( json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ], [ @@ -247,8 +256,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -292,8 +301,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -306,9 +315,9 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => KeyCrypt::encrypt( + 'oauth_authorize_request' => $this->cryptStub->doEncrypt( json_encode(['user_id' => null]), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ], [ @@ -341,8 +350,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -355,9 +364,9 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => KeyCrypt::encrypt( + 'oauth_authorize_request' => $this->cryptStub->doEncrypt( json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ], [ @@ -389,8 +398,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $request = new ServerRequest( [ @@ -403,9 +412,9 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => KeyCrypt::encrypt( + 'oauth_authorize_request' => $this->cryptStub->doEncrypt( json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ), ], [ diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index d6b63203..dc2056cb 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -9,7 +9,6 @@ use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; -use League\OAuth2\Server\Utils\KeyCrypt; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\ScopeEntity; use LeagueTests\Stubs\StubResponseType; @@ -17,6 +16,16 @@ use Zend\Diactoros\ServerRequest; class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase { + /** + * CryptTrait stub + */ + protected $cryptStub; + + public function setUp() + { + $this->cryptStub = new CryptTraitStub; + } + public function testGetIdentifier() { $refreshTokenRepositoryMock = $this->getMock(RefreshTokenRepositoryInterface::class); @@ -47,10 +56,10 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $oldRefreshToken = KeyCrypt::encrypt( + $oldRefreshToken = $this->cryptStub->doEncrypt( json_encode( [ 'client_id' => 'foo', @@ -61,7 +70,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase 'expire_time' => time() + 3600, ] ), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ); $serverRequest = new ServerRequest(); @@ -103,10 +112,10 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $oldRefreshToken = KeyCrypt::encrypt( + $oldRefreshToken = $this->cryptStub->doEncrypt( json_encode( [ 'client_id' => 'foo', @@ -117,7 +126,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase 'expire_time' => time() + 3600, ] ), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ); $serverRequest = new ServerRequest(); @@ -164,10 +173,10 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $oldRefreshToken = KeyCrypt::encrypt( + $oldRefreshToken = $this->cryptStub->doEncrypt( json_encode( [ 'client_id' => 'foo', @@ -178,7 +187,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase 'expire_time' => time() + 3600, ] ), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ); $serverRequest = new ServerRequest(); @@ -213,8 +222,8 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $serverRequest = new ServerRequest(); $serverRequest = $serverRequest->withParsedBody( @@ -246,8 +255,8 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $oldRefreshToken = 'foobar'; @@ -286,10 +295,10 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $oldRefreshToken = KeyCrypt::encrypt( + $oldRefreshToken = $this->cryptStub->doEncrypt( json_encode( [ 'client_id' => 'bar', @@ -300,7 +309,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase 'expire_time' => time() + 3600, ] ), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ); $serverRequest = new ServerRequest(); @@ -334,10 +343,10 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $oldRefreshToken = KeyCrypt::encrypt( + $oldRefreshToken = $this->cryptStub->doEncrypt( json_encode( [ 'client_id' => 'foo', @@ -348,7 +357,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase 'expire_time' => time() - 3600, ] ), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ); $serverRequest = new ServerRequest(); @@ -383,10 +392,10 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); - $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $oldRefreshToken = KeyCrypt::encrypt( + $oldRefreshToken = $this->cryptStub->doEncrypt( json_encode( [ 'client_id' => 'foo', @@ -397,7 +406,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase 'expire_time' => time() + 3600, ] ), - 'file://' . __DIR__ . '/../Utils/private.key' + 'file://' . __DIR__ . '/../Stubs/private.key' ); $serverRequest = new ServerRequest(); diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index ce7620ea..fb9b91ca 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -20,8 +20,8 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $responseType = new BearerTokenResponse( - 'file://' . __DIR__ . '/../Utils/private.key', - 'file://' . __DIR__ . '/../Utils/public.key', + 'file://' . __DIR__ . '/../Stubs/private.key', + 'file://' . __DIR__ . '/../Stubs/public.key', $accessTokenRepositoryMock ); @@ -66,8 +66,8 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $responseType = new BearerTokenResponse( - 'file://' . __DIR__ . '/../Utils/private.key', - 'file://' . __DIR__ . '/../Utils/public.key', + 'file://' . __DIR__ . '/../Stubs/private.key', + 'file://' . __DIR__ . '/../Stubs/public.key', $accessTokenRepositoryMock ); @@ -108,8 +108,8 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $responseType = new BearerTokenResponse( - 'file://' . __DIR__ . '/../Utils/private.key', - 'file://' . __DIR__ . '/../Utils/public.key', + 'file://' . __DIR__ . '/../Stubs/private.key', + 'file://' . __DIR__ . '/../Stubs/public.key', $accessTokenRepositoryMock ); @@ -154,8 +154,8 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $responseType = new BearerTokenResponse( - 'file://' . __DIR__ . '/../Utils/private.key', - 'file://' . __DIR__ . '/../Utils/public.key', + 'file://' . __DIR__ . '/../Stubs/private.key', + 'file://' . __DIR__ . '/../Stubs/public.key', $accessTokenRepositoryMock ); @@ -198,8 +198,8 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $responseType = new BearerTokenResponse( - 'file://' . __DIR__ . '/../Utils/private.key', - 'file://' . __DIR__ . '/../Utils/public.key', + 'file://' . __DIR__ . '/../Stubs/private.key', + 'file://' . __DIR__ . '/../Stubs/public.key', $accessTokenRepositoryMock ); diff --git a/tests/Stubs/CryptTraitStub.php b/tests/Stubs/CryptTraitStub.php new file mode 100644 index 00000000..583a851c --- /dev/null +++ b/tests/Stubs/CryptTraitStub.php @@ -0,0 +1,26 @@ +setPrivateKeyPath('file://' . __DIR__ . '/private.key'); + $this->setPublicKeyPath('file://' . __DIR__ . '/public.key'); + } + + public function doEncrypt($unencryptedData) + { + return $this->encrypt($unencryptedData); + } + + public function doDecrypt($encryptedData) + { + return $this->decrypt($encryptedData); + } +} diff --git a/tests/Utils/private.key b/tests/Stubs/private.key similarity index 100% rename from tests/Utils/private.key rename to tests/Stubs/private.key diff --git a/tests/Utils/public.key b/tests/Stubs/public.key similarity index 100% rename from tests/Utils/public.key rename to tests/Stubs/public.key diff --git a/tests/Utils/KeyCryptTest.php b/tests/Utils/KeyCryptTest.php deleted file mode 100644 index 3fa1f17c..00000000 --- a/tests/Utils/KeyCryptTest.php +++ /dev/null @@ -1,34 +0,0 @@ -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'); - } -} From 8196f5c832eedf28fea97675ada5635b76b26cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Thu, 17 Mar 2016 21:33:04 +0100 Subject: [PATCH 320/444] code against interface --- src/Grant/AuthCodeGrant.php | 6 +++--- src/Grant/ImplicitGrant.php | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 05ea1f38..b031e6e6 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -13,7 +13,7 @@ use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\HtmlResponse; use League\OAuth2\Server\ResponseTypes\RedirectResponse; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; -use League\OAuth2\Server\TemplateRenderer\AbstractRenderer; +use League\OAuth2\Server\TemplateRenderer\RendererInterface; use Psr\Http\Message\ServerRequestInterface; class AuthCodeGrant extends AbstractAuthorizeGrant @@ -28,14 +28,14 @@ class AuthCodeGrant extends AbstractAuthorizeGrant * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository * @param \DateInterval $authCodeTTL - * @param \League\OAuth2\Server\TemplateRenderer\AbstractRenderer|null $templateRenderer + * @param \League\OAuth2\Server\TemplateRenderer\RendererInterface|null $templateRenderer */ public function __construct( AuthCodeRepositoryInterface $authCodeRepository, RefreshTokenRepositoryInterface $refreshTokenRepository, UserRepositoryInterface $userRepository, \DateInterval $authCodeTTL, - AbstractRenderer $templateRenderer = null + RendererInterface $templateRenderer = null ) { $this->setAuthCodeRepository($authCodeRepository); $this->setRefreshTokenRepository($refreshTokenRepository); diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 7da987d7..573d869f 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -10,16 +10,16 @@ use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\HtmlResponse; use League\OAuth2\Server\ResponseTypes\RedirectResponse; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; -use League\OAuth2\Server\TemplateRenderer\AbstractRenderer; +use League\OAuth2\Server\TemplateRenderer\RendererInterface; use Psr\Http\Message\ServerRequestInterface; class ImplicitGrant extends AbstractAuthorizeGrant { /** - * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository - * @param \League\OAuth2\Server\TemplateRenderer\AbstractRenderer|null $templateRenderer + * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository + * @param \League\OAuth2\Server\TemplateRenderer\RendererInterface|null $templateRenderer */ - public function __construct(UserRepositoryInterface $userRepository, AbstractRenderer $templateRenderer = null) + public function __construct(UserRepositoryInterface $userRepository, RendererInterface $templateRenderer = null) { $this->setUserRepository($userRepository); $this->refreshTokenTTL = new \DateInterval('P1M'); From 4b775fe24139f212e8f7a7fd3155383ff370cb97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Fri, 18 Mar 2016 00:25:32 +0100 Subject: [PATCH 321/444] include CryptTrait tests, allow Server::respondToRequest trhow exceptions and fix ResposeType tests --- src/CryptTrait.php | 2 +- src/Grant/AuthCodeGrant.php | 2 + src/Grant/ImplicitGrant.php | 6 +- src/Grant/RefreshTokenGrant.php | 2 + src/Server.php | 34 +++--- tests/Grant/AuthCodeGrantTest.php | 108 +++++++++--------- tests/Grant/ImplicitGrantTest.php | 82 ++++++------- tests/Grant/RefreshTokenGrantTest.php | 21 ++-- .../ResourceServerMiddlewareTest.php | 23 +++- .../ResponseTypes/BearerResponseTypeTest.php | 79 +++++++------ tests/ServerTest.php | 27 +++-- 11 files changed, 200 insertions(+), 186 deletions(-) diff --git a/src/CryptTrait.php b/src/CryptTrait.php index 844f810f..3c648b79 100644 --- a/src/CryptTrait.php +++ b/src/CryptTrait.php @@ -108,7 +108,7 @@ trait CryptTrait while ($encryptedData) { $chunk = substr($encryptedData, 0, $chunkSize); $encryptedData = substr($encryptedData, $chunkSize); - if (openssl_public_decrypt($chunk, $decrypted, $publicKey, OPENSSL_PKCS1_OAEP_PADDING) === false) { + if (openssl_public_decrypt($chunk, $decrypted, $publicKey/*, OPENSSL_PKCS1_OAEP_PADDING*/) === false) { // @codeCoverageIgnoreStart throw new \LogicException('Failed to decrypt data'); // @codeCoverageIgnoreEnd diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index b031e6e6..17ccf76c 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -282,7 +282,9 @@ class AuthCodeGrant extends AbstractAuthorizeGrant ); if (!$scope) { + // @codeCoverageIgnoreStart throw OAuthServerException::invalidScope($scopeId); + // @codeCoverageIgnoreEnd } $scopes[] = $scope; diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 573d869f..9b46d019 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -176,7 +176,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant } // The user has either approved or denied the client, so redirect them back - $redirectUri = new Uri($client->getRedirectUri()); + $redirectUri = $client->getRedirectUri(); $redirectPayload = []; $stateParameter = $this->getQueryStringParameter('state', $request); @@ -208,8 +208,6 @@ class ImplicitGrant extends AbstractAuthorizeGrant } // 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); + throw OAuthServerException::accessDenied('The user denied the request', (string) $redirectUri); } } diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index be0d803e..3dee1073 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -54,7 +54,9 @@ class RefreshTokenGrant extends AbstractGrant ); if (!$scope) { + // @codeCoverageIgnoreStart throw OAuthServerException::invalidScope($scopeId); + // @codeCoverageIgnoreEnd } return $scope; diff --git a/src/Server.php b/src/Server.php index 5e0f2190..e77a344b 100644 --- a/src/Server.php +++ b/src/Server.php @@ -127,27 +127,23 @@ class Server implements EmitterAwareInterface */ public function respondToRequest(ServerRequestInterface $request, ResponseInterface $response) { - try { - $tokenResponse = null; - while ($tokenResponse === null && $grantType = array_shift($this->enabledGrantTypes)) { - /** @var \League\OAuth2\Server\Grant\GrantTypeInterface $grantType */ - if ($grantType->canRespondToRequest($request)) { - $tokenResponse = $grantType->respondToRequest( - $request, - $this->getResponseType(), - $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] - ); - } + $tokenResponse = null; + while ($tokenResponse === null && $grantType = array_shift($this->enabledGrantTypes)) { + /** @var \League\OAuth2\Server\Grant\GrantTypeInterface $grantType */ + if ($grantType->canRespondToRequest($request)) { + $tokenResponse = $grantType->respondToRequest( + $request, + $this->getResponseType(), + $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] + ); } - - if ($tokenResponse instanceof ResponseTypeInterface) { - return $tokenResponse->generateHttpResponse($response); - } - - throw OAuthServerException::unsupportedGrantType(); - } catch (OAuthServerException $e) { - return $e->generateHttpResponse($response); } + + if ($tokenResponse instanceof ResponseTypeInterface) { + return $tokenResponse->generateHttpResponse($response); + } + + throw OAuthServerException::unsupportedGrantType(); } /** diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 31cd2f53..44bba0fc 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -12,12 +12,15 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\ResponseTypes\HtmlResponse; +use League\OAuth2\Server\ResponseTypes\RedirectResponse; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\CryptTraitStub; use LeagueTests\Stubs\ScopeEntity; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; use Psr\Http\Message\ResponseInterface; +use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase @@ -81,6 +84,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $userEntity = new UserEntity(); $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), @@ -88,6 +94,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); @@ -102,10 +109,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt( - json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Stubs/private.key' - ), + 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), ], [ 'response_type' => 'code', @@ -121,10 +125,16 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); - $this->assertTrue($response instanceof ResponseInterface); + $this->assertTrue($response instanceof RedirectResponse); + + $response = $response->generateHttpResponse(new Response); $this->assertTrue(strstr($response->getHeader('location')[0], 'http://foo/bar') !== false); } + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 9 + */ public function testRespondToAuthorizationRequestUserDenied() { $client = new ClientEntity(); @@ -136,6 +146,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $userEntity = new UserEntity(); $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), @@ -143,6 +156,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); @@ -157,10 +171,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt( - json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Stubs/private.key' - ), + 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), ], [ 'response_type' => 'code', @@ -174,11 +185,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ] ); - $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); + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } /** @@ -217,10 +224,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt( - json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Stubs/private.key' - ), + 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), ], [ 'response_type' => 'code', @@ -232,9 +236,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ] ); - $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); - - $this->assertTrue($response instanceof ResponseInterface); + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } public function testRespondToAuthorizationRequestBadClient() @@ -268,10 +270,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt( - json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Stubs/private.key' - ), + 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), ], [ 'response_type' => 'code', @@ -323,10 +322,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt( - json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Stubs/private.key' - ), + 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), ], [ 'response_type' => 'code', @@ -397,9 +393,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ] ); - $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); - - $this->assertTrue($response instanceof ResponseInterface); + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } public function testRespondToAuthorizationRequestTryLogin() @@ -413,6 +407,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $userEntity = new UserEntity(); $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), @@ -420,6 +417,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); @@ -434,10 +432,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt( - json_encode(['user_id' => null]), - 'file://' . __DIR__ . '/../Stubs/private.key' - ), + 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => null])), ], [ 'response_type' => 'code', @@ -452,7 +447,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); - $this->assertTrue($response instanceof ResponseInterface); + $this->assertTrue($response instanceof RedirectResponse); + + $response = $response->generateHttpResponse(new Response); $this->assertTrue(strstr($response->getHeader('location')[0], 'http://foo/bar') !== false); } @@ -467,6 +464,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $userEntity = null; $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), @@ -474,6 +474,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); @@ -488,10 +489,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt( - json_encode(['user_id' => null]), - 'file://' . __DIR__ . '/../Stubs/private.key' - ), + 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => null])), ], [ 'response_type' => 'code', @@ -506,9 +504,11 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); - $this->assertTrue($response instanceof ResponseInterface); + $this->assertTrue($response instanceof HtmlResponse); + + $response = $response->generateHttpResponse(new Response); $this->assertTrue(strstr($response->getHeader('content-type')[0], 'text/html') !== false); - $this->assertTrue(strstr($response->getBody()->getContents(), 'Incorrect username or password') !== false); + $this->assertTrue(strstr((string) $response->getBody(), 'Incorrect username or password') !== false); } public function testRespondToAuthorizationRequestShowAuthorizeForm() @@ -523,6 +523,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $userEntity = new UserEntity(); $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), @@ -530,6 +533,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); @@ -544,10 +548,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt( - json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Stubs/private.key' - ), + 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), ], [ 'response_type' => 'code', @@ -561,6 +562,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + $response = $response->generateHttpResponse(new Response); $this->assertTrue($response instanceof ResponseInterface); $this->assertTrue(strstr($response->getHeader('set-cookie')[0], 'oauth_authorize_request') !== false); } @@ -623,8 +625,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'scopes' => ['foo'], 'redirect_uri' => 'http://foo/bar', ] - ), - 'file://' . __DIR__ . '/../Stubs/private.key' + ) ), ] ); @@ -779,8 +780,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'scopes' => ['foo'], 'redirect_uri' => 'http://foo/bar', ] - ), - 'file://' . __DIR__ . '/../Stubs/private.key' + ) ), ] ); @@ -849,8 +849,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'scopes' => ['foo'], 'redirect_uri' => 'http://foo/bar', ] - ), - 'file://' . __DIR__ . '/../Stubs/private.key' + ) ), ] ); @@ -916,8 +915,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'scopes' => ['foo'], 'redirect_uri' => 'http://foo/bar', ] - ), - 'file://' . __DIR__ . '/../Stubs/private.key' + ) ), ] ); diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 3c597978..e4e10db0 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -7,10 +7,12 @@ use League\OAuth2\Server\Grant\ImplicitGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\ResponseTypes\HtmlResponse; use LeagueTests\Stubs\ClientEntity; +use LeagueTests\Stubs\CryptTraitStub; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; -use Psr\Http\Message\ResponseInterface; +use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; class ImplicitGrantTest extends \PHPUnit_Framework_TestCase @@ -22,7 +24,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->cryptStub = new CryptTraitStub; + $this->cryptStub = new CryptTraitStub(); } public function testGetIdentifier() @@ -52,6 +54,10 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $this->assertTrue($grant->canRespondToRequest($request)); } + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 9 + */ public function testRespondToAuthorizationRequest() { $client = new ClientEntity(); @@ -95,10 +101,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase ] ); - $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); + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } /** @@ -122,10 +125,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt( - json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Stubs/private.key' - ), + 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), ], [ 'response_type' => 'token', @@ -137,9 +137,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase ] ); - $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); - - $this->assertTrue($response instanceof ResponseInterface); + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } public function testRespondToAuthorizationRequestBadClient() @@ -164,10 +162,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt( - json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Stubs/private.key' - ), + 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), ], [ 'response_type' => 'token', @@ -214,10 +209,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt( - json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Stubs/private.key' - ), + 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), ], [ 'response_type' => 'token', @@ -283,9 +275,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase ] ); - $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); - - $this->assertTrue($response instanceof ResponseInterface); + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } public function testRespondToAuthorizationRequestTryLogin() @@ -299,8 +289,12 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $userEntity = new UserEntity(); $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); @@ -315,10 +309,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt( - json_encode(['user_id' => null]), - 'file://' . __DIR__ . '/../Stubs/private.key' - ), + 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => null])), ], [ 'response_type' => 'token', @@ -332,9 +323,10 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase ); $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); + $this->assertTrue($response instanceof HtmlResponse); + + $response = $response->generateHttpResponse(new Response); + $this->assertTrue(strstr((string) $response->getBody(), 'Incorrect username or password') !== false); } public function testRespondToAuthorizationRequestShowAuthorizeForm() @@ -348,8 +340,12 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $userEntity = new UserEntity(); $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); @@ -364,10 +360,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt( - json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Stubs/private.key' - ), + 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), ], [ 'response_type' => 'code', @@ -381,10 +374,16 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); - $this->assertTrue($response instanceof ResponseInterface); + $this->assertTrue($response instanceof HtmlResponse); + + $response = $response->generateHttpResponse(new Response); $this->assertTrue(strstr($response->getHeader('set-cookie')[0], 'oauth_authorize_request') !== false); } + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 9 + */ public function testRespondToAuthorizationRequestUserDenied() { $client = new ClientEntity(); @@ -412,10 +411,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase 'php://input', [], [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt( - json_encode(['user_id' => 123]), - 'file://' . __DIR__ . '/../Stubs/private.key' - ), + 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), ], [ 'response_type' => 'code', @@ -429,10 +425,6 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase ] ); - $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); + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } } diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index dc2056cb..0250855b 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -10,6 +10,7 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use LeagueTests\Stubs\ClientEntity; +use LeagueTests\Stubs\CryptTraitStub; use LeagueTests\Stubs\ScopeEntity; use LeagueTests\Stubs\StubResponseType; use Zend\Diactoros\ServerRequest; @@ -23,7 +24,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->cryptStub = new CryptTraitStub; + $this->cryptStub = new CryptTraitStub(); } public function testGetIdentifier() @@ -69,8 +70,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase 'user_id' => 123, 'expire_time' => time() + 3600, ] - ), - 'file://' . __DIR__ . '/../Stubs/private.key' + ) ); $serverRequest = new ServerRequest(); @@ -125,8 +125,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase 'user_id' => 123, 'expire_time' => time() + 3600, ] - ), - 'file://' . __DIR__ . '/../Stubs/private.key' + ) ); $serverRequest = new ServerRequest(); @@ -186,8 +185,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase 'user_id' => 123, 'expire_time' => time() + 3600, ] - ), - 'file://' . __DIR__ . '/../Stubs/private.key' + ) ); $serverRequest = new ServerRequest(); @@ -308,8 +306,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase 'user_id' => 123, 'expire_time' => time() + 3600, ] - ), - 'file://' . __DIR__ . '/../Stubs/private.key' + ) ); $serverRequest = new ServerRequest(); @@ -356,8 +353,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase 'user_id' => 123, 'expire_time' => time() - 3600, ] - ), - 'file://' . __DIR__ . '/../Stubs/private.key' + ) ); $serverRequest = new ServerRequest(); @@ -405,8 +401,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase 'user_id' => 123, 'expire_time' => time() + 3600, ] - ), - 'file://' . __DIR__ . '/../Stubs/private.key' + ) ); $serverRequest = new ServerRequest(); diff --git a/tests/Middleware/ResourceServerMiddlewareTest.php b/tests/Middleware/ResourceServerMiddlewareTest.php index 590ae438..aff01cce 100644 --- a/tests/Middleware/ResourceServerMiddlewareTest.php +++ b/tests/Middleware/ResourceServerMiddlewareTest.php @@ -2,11 +2,17 @@ namespace LeagueTests\Middleware; +use Lcobucci\JWT\Builder; +use Lcobucci\JWT\Signer\Key; +use Lcobucci\JWT\Signer\Rsa\Sha256; +use Lcobucci\JWT\Token; +use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Middleware\ResourceServerMiddleware; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Server; +use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; @@ -21,13 +27,24 @@ class ResourceServerMiddlewareTest extends \PHPUnit_Framework_TestCase $clientRepository, $this->getMock(AccessTokenRepositoryInterface::class), $this->getMock(ScopeRepositoryInterface::class), - '', - '', + 'file://' . __DIR__ . '/../Stubs/private.key', + 'file://' . __DIR__ . '/../Stubs/public.key', new StubResponseType() ); + $client = new ClientEntity(); + $client->setIdentifier('clientName'); + + $accessToken = new AccessTokenEntity(); + $accessToken->setIdentifier('test'); + $accessToken->setUserIdentifier(123); + $accessToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H'))); + $accessToken->setClient($client); + + $token = $accessToken->convertToJWT('file://' . __DIR__ . '/../Stubs/private.key'); + $request = new ServerRequest(); - $request = $request->withHeader('authorization', 'Basic test'); + $request = $request->withHeader('authorization', sprintf('Bearer %s', $token)); $middleware = new ResourceServerMiddleware($server); $response = $middleware->__invoke( diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index fb9b91ca..a8b62f0e 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -2,6 +2,7 @@ namespace LeagueTests\ResponseTypes; +use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; @@ -19,11 +20,9 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase { $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - $responseType = new BearerTokenResponse( - 'file://' . __DIR__ . '/../Stubs/private.key', - 'file://' . __DIR__ . '/../Stubs/public.key', - $accessTokenRepositoryMock - ); + $responseType = new BearerTokenResponse($accessTokenRepositoryMock); + $responseType->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $responseType->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $client = new ClientEntity(); $client->setIdentifier('clientName'); @@ -64,12 +63,11 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase public function testDetermineAccessTokenInHeaderValidToken() { $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(false); - $responseType = new BearerTokenResponse( - 'file://' . __DIR__ . '/../Stubs/private.key', - 'file://' . __DIR__ . '/../Stubs/public.key', - $accessTokenRepositoryMock - ); + $responseType = new BearerTokenResponse($accessTokenRepositoryMock); + $responseType->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $responseType->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $client = new ClientEntity(); $client->setIdentifier('clientName'); @@ -89,13 +87,16 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $responseType->setRefreshToken($refreshToken); $response = $responseType->generateHttpResponse(new Response()); - $response->getBody()->rewind(); - $json = json_decode($response->getBody()->getContents()); + $json = json_decode((string) $response->getBody()); + + $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); + $authorizationValidator->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $authorizationValidator->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $request = new ServerRequest(); $request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token)); - $request = $responseType->validateAccessToken($request); + $request = $authorizationValidator->validateAuthorization($request); $this->assertEquals('abcdef', $request->getAttribute('oauth_access_token_id')); $this->assertEquals('clientName', $request->getAttribute('oauth_client_id')); @@ -106,12 +107,11 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase public function testDetermineAccessTokenInHeaderInvalidJWT() { $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(false); - $responseType = new BearerTokenResponse( - 'file://' . __DIR__ . '/../Stubs/private.key', - 'file://' . __DIR__ . '/../Stubs/public.key', - $accessTokenRepositoryMock - ); + $responseType = new BearerTokenResponse($accessTokenRepositoryMock); + $responseType->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $responseType->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $client = new ClientEntity(); $client->setIdentifier('clientName'); @@ -131,14 +131,17 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $responseType->setRefreshToken($refreshToken); $response = $responseType->generateHttpResponse(new Response()); - $response->getBody()->rewind(); - $json = json_decode($response->getBody()->getContents()); + $json = json_decode((string) $response->getBody()); + + $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); + $authorizationValidator->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $authorizationValidator->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $request = new ServerRequest(); $request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token . 'foo')); try { - $responseType->validateAccessToken($request); + $authorizationValidator->validateAuthorization($request); } catch (OAuthServerException $e) { $this->assertEquals( 'Access token could not be verified', @@ -150,14 +153,11 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase public function testDetermineAccessTokenInHeaderRevokedToken() { $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - $accessTokenRepositoryMock->expects($this->once())->method('isAccessTokenRevoked')->willReturn(true); + $accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(true); - - $responseType = new BearerTokenResponse( - 'file://' . __DIR__ . '/../Stubs/private.key', - 'file://' . __DIR__ . '/../Stubs/public.key', - $accessTokenRepositoryMock - ); + $responseType = new BearerTokenResponse($accessTokenRepositoryMock); + $responseType->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $responseType->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $client = new ClientEntity(); $client->setIdentifier('clientName'); @@ -177,14 +177,17 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $responseType->setRefreshToken($refreshToken); $response = $responseType->generateHttpResponse(new Response()); - $response->getBody()->rewind(); - $json = json_decode($response->getBody()->getContents()); + $json = json_decode((string) $response->getBody()); + + $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); + $authorizationValidator->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $authorizationValidator->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $request = new ServerRequest(); $request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token)); try { - $responseType->validateAccessToken($request); + $authorizationValidator->validateAuthorization($request); } catch (OAuthServerException $e) { $this->assertEquals( 'Access token has been revoked', @@ -197,17 +200,19 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase { $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - $responseType = new BearerTokenResponse( - 'file://' . __DIR__ . '/../Stubs/private.key', - 'file://' . __DIR__ . '/../Stubs/public.key', - $accessTokenRepositoryMock - ); + $responseType = new BearerTokenResponse($accessTokenRepositoryMock); + $responseType->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $responseType->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + + $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); + $authorizationValidator->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $authorizationValidator->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $request = new ServerRequest(); $request = $request->withHeader('authorization', 'Bearer blah'); try { - $responseType->validateAccessToken($request); + $authorizationValidator->validateAuthorization($request); } catch (OAuthServerException $e) { $this->assertEquals( 'The JWT string must have two dots', diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 1563e34a..cf52cf8f 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -15,8 +15,10 @@ use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use League\OAuth2\Server\Server; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; +use LeagueTests\Stubs\UserEntity; use Psr\Http\Message\ResponseInterface; -use Zend\Diactoros\ServerRequest; +use Zend\Diactoros\Response; +use Zend\Diactoros\ServerRequestFactory; class ServerTest extends \PHPUnit_Framework_TestCase { @@ -34,7 +36,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M')); try { - $server->respondToRequest(); + $server->respondToRequest(ServerRequestFactory::fromGlobals(), new Response); } catch (OAuthServerException $e) { $this->assertEquals('unsupported_grant_type', $e->getErrorType()); $this->assertEquals(400, $e->getHttpStatusCode()); @@ -60,7 +62,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase $_POST['grant_type'] = 'client_credentials'; $_POST['client_id'] = 'foo'; $_POST['client_secret'] = 'bar'; - $response = $server->respondToRequest(); + $response = $server->respondToRequest(ServerRequestFactory::fromGlobals(), new Response); $this->assertEquals(200, $response->getStatusCode()); } @@ -77,16 +79,19 @@ class ServerTest extends \PHPUnit_Framework_TestCase $clientRepository, $this->getMock(AccessTokenRepositoryInterface::class), $this->getMock(ScopeRepositoryInterface::class), - '', - '', + 'file://' . __DIR__ . '/Stubs/private.key', + 'file://' . __DIR__ . '/Stubs/public.key', new StubResponseType() ); + $userRepository = $this->getMock(UserRepositoryInterface::class); + $userRepository->method('getUserEntityByUserCredentials')->willReturn(new UserEntity()); + $server->enableGrantType( new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $this->getMock(UserRepositoryInterface::class), + $userRepository, new \DateInterval('PT1H') ), new \DateInterval('PT1M') @@ -97,9 +102,13 @@ class ServerTest extends \PHPUnit_Framework_TestCase $_GET['response_type'] = 'code'; $_GET['client_id'] = $client->getIdentifier(); $_GET['redirect_uri'] = $client->getRedirectUri(); - $response = $server->respondToRequest(); - $this->assertEquals(200, $response->getStatusCode()); + $_POST['action'] = 'approve'; + $_POST['username'] = 'user'; + $_POST['password'] = 'pass'; + $response = $server->respondToRequest(ServerRequestFactory::fromGlobals(), new Response); $this->assertTrue($response instanceof ResponseInterface); + $this->assertEquals(302, $response->getStatusCode()); + $this->assertTrue(strstr($response->getHeaderLine('location'), 'code=') !== false); } public function testGetResponseType() @@ -134,7 +143,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase ); try { - $server->validateAuthenticatedRequest(new ServerRequest()); + $server->validateAuthenticatedRequest(ServerRequestFactory::fromGlobals()); } catch (OAuthServerException $e) { $this->assertEquals('Missing "Authorization" header', $e->getHint()); } From b629b5e53f9da1bd8c4089694d469bb79735d16d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Fri, 18 Mar 2016 00:38:37 +0100 Subject: [PATCH 322/444] styleCI request --- tests/Middleware/ResourceServerMiddlewareTest.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/Middleware/ResourceServerMiddlewareTest.php b/tests/Middleware/ResourceServerMiddlewareTest.php index aff01cce..960113db 100644 --- a/tests/Middleware/ResourceServerMiddlewareTest.php +++ b/tests/Middleware/ResourceServerMiddlewareTest.php @@ -2,10 +2,6 @@ namespace LeagueTests\Middleware; -use Lcobucci\JWT\Builder; -use Lcobucci\JWT\Signer\Key; -use Lcobucci\JWT\Signer\Rsa\Sha256; -use Lcobucci\JWT\Token; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Middleware\ResourceServerMiddleware; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; From 9ee2e7271f0bdfb4fe3cdc9b9f6cd95fe047f38f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Fri, 18 Mar 2016 00:41:38 +0100 Subject: [PATCH 323/444] require-dev zend-diactoros --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c5a6cbbd..e392d1e6 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ }, "require-dev": { "phpunit/phpunit": "^4.8", - "league/plates": "^3.1" + "league/plates": "^3.1", + "zendframework/zend-diactoros": "^1.0" }, "repositories": [ { From 400eae153b9d06f3fc0408ae8781c36600551c16 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 22 Mar 2016 14:18:02 +0000 Subject: [PATCH 324/444] Added grant and scopes to UserRepository getUserEntityByUserCredentials method --- src/Grant/AuthCodeGrant.php | 4 +++- src/Grant/ImplicitGrant.php | 4 +++- src/Grant/PasswordGrant.php | 15 +++++++++++---- src/Repositories/UserRepositoryInterface.php | 10 +++++++--- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 17ccf76c..5668f7be 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -123,7 +123,9 @@ class AuthCodeGrant extends AbstractAuthorizeGrant if ($userId === null && $usernameParameter !== null && $passwordParameter !== null) { $userEntity = $this->userRepository->getUserEntityByUserCredentials( $usernameParameter, - $passwordParameter + $passwordParameter, + $this->getIdentifier(), + $scopes ); if ($userEntity instanceof UserEntityInterface) { diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 9b46d019..3929560d 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -121,7 +121,9 @@ class ImplicitGrant extends AbstractAuthorizeGrant if ($userId === null && $usernameParameter !== null && $passwordParameter !== null) { $userEntity = $this->userRepository->getUserEntityByUserCredentials( $usernameParameter, - $passwordParameter + $passwordParameter, + $this->getIdentifier(), + $scopes ); if ($userEntity instanceof UserEntityInterface) { diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index a2ce660b..e2960072 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -11,6 +11,7 @@ namespace League\OAuth2\Server\Grant; use League\Event\Event; +use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; @@ -47,8 +48,8 @@ class PasswordGrant extends AbstractGrant ) { // Validate request $client = $this->validateClient($request); - $user = $this->validateUser($request); $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client); + $user = $this->validateUser($request, $scopes); // Issue and persist new tokens $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $scopes); @@ -64,11 +65,12 @@ class PasswordGrant extends AbstractGrant /** * @param \Psr\Http\Message\ServerRequestInterface $request * - * @throws \League\OAuth2\Server\Exception\OAuthServerException + * @param ScopeEntityInterface[] $scopes * * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface + * @throws \League\OAuth2\Server\Exception\OAuthServerException */ - protected function validateUser(ServerRequestInterface $request) + protected function validateUser(ServerRequestInterface $request, array $scopes) { $username = $this->getRequestParameter('username', $request); if (is_null($username)) { @@ -80,7 +82,12 @@ class PasswordGrant extends AbstractGrant throw OAuthServerException::invalidRequest('password', '`%s` parameter is missing'); } - $user = $this->userRepository->getUserEntityByUserCredentials($username, $password); + $user = $this->userRepository->getUserEntityByUserCredentials( + $username, + $password, + $this->getIdentifier(), + $scopes + ); if (!$user instanceof UserEntityInterface) { $this->getEmitter()->emit(new Event('user.authentication.failed', $request)); diff --git a/src/Repositories/UserRepositoryInterface.php b/src/Repositories/UserRepositoryInterface.php index d93c85a7..a2ae0701 100644 --- a/src/Repositories/UserRepositoryInterface.php +++ b/src/Repositories/UserRepositoryInterface.php @@ -2,15 +2,19 @@ namespace League\OAuth2\Server\Repositories; +use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; + interface UserRepositoryInterface extends RepositoryInterface { /** * Get a user entity. * - * @param string $username - * @param string $password + * @param string $username + * @param string $password + * @param string $grantType The grant type used + * @param ScopeEntityInterface[] $scopes * * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface */ - public function getUserEntityByUserCredentials($username, $password); + public function getUserEntityByUserCredentials($username, $password, $grantType, array &$scopes); } From 8685006743fb0af8700cc4adeab59702d2a5dc4d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 22 Mar 2016 10:18:21 -0400 Subject: [PATCH 325/444] Applied fixes from StyleCI --- src/Grant/PasswordGrant.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index e2960072..65f51bfe 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -64,11 +64,11 @@ class PasswordGrant extends AbstractGrant /** * @param \Psr\Http\Message\ServerRequestInterface $request - * * @param ScopeEntityInterface[] $scopes * - * @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, array $scopes) { From e27b13ee7d07933152beb8a1c19f22ecbfe23a12 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 22 Mar 2016 14:44:21 +0000 Subject: [PATCH 326/444] Accept scopes as reference --- src/Grant/PasswordGrant.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index e2960072..cc1c1d69 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -70,7 +70,7 @@ class PasswordGrant extends AbstractGrant * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface * @throws \League\OAuth2\Server\Exception\OAuthServerException */ - protected function validateUser(ServerRequestInterface $request, array $scopes) + protected function validateUser(ServerRequestInterface $request, array &$scopes) { $username = $this->getRequestParameter('username', $request); if (is_null($username)) { From ed17b6540ee320e72e163bf9dd8a882a1c961439 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 22 Mar 2016 14:44:39 +0000 Subject: [PATCH 327/444] Add additional repository --- examples/src/Repositories/UserRepository.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/examples/src/Repositories/UserRepository.php b/examples/src/Repositories/UserRepository.php index ec930500..257fe754 100644 --- a/examples/src/Repositories/UserRepository.php +++ b/examples/src/Repositories/UserRepository.php @@ -2,25 +2,34 @@ namespace OAuth2ServerExamples\Repositories; +use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use OAuth2ServerExamples\Entities\ScopeEntity; use OAuth2ServerExamples\Entities\UserEntity; class UserRepository implements UserRepositoryInterface { + /** * Get a user entity. * - * @param string $username - * @param string $password + * @param string $username + * @param string $password + * @param string $grantType The grant type used + * @param ScopeEntityInterface[] $scopes * * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface */ - public function getUserEntityByUserCredentials($username, $password) + public function getUserEntityByUserCredentials($username, $password, $grantType, array &$scopes) { if ($username === 'alex' && $password === 'whisky') { + $scope = new ScopeEntity(); + $scope->setIdentifier('email'); + $scopes[] = $scope; + return new UserEntity(); } - return; + return null; } } From 6fea0543815ae82b212927f5a50b6aca53cd76b7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 22 Mar 2016 14:44:58 +0000 Subject: [PATCH 328/444] Update examples/composer.lock --- examples/composer.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/composer.lock b/examples/composer.lock index a866769a..fd03f27b 100644 --- a/examples/composer.lock +++ b/examples/composer.lock @@ -315,16 +315,16 @@ }, { "name": "paragonie/random_compat", - "version": "v1.2.2", + "version": "v1.4.1", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "b3313b618f4edd76523572531d5d7e22fe747430" + "reference": "c7e26a21ba357863de030f0b9e701c7d04593774" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/b3313b618f4edd76523572531d5d7e22fe747430", - "reference": "b3313b618f4edd76523572531d5d7e22fe747430", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/c7e26a21ba357863de030f0b9e701c7d04593774", + "reference": "c7e26a21ba357863de030f0b9e701c7d04593774", "shasum": "" }, "require": { @@ -359,7 +359,7 @@ "pseudorandom", "random" ], - "time": "2016-03-11 19:54:08" + "time": "2016-03-18 20:34:03" }, { "name": "pimple/pimple", @@ -524,20 +524,20 @@ }, { "name": "zendframework/zend-diactoros", - "version": "1.3.3", + "version": "1.3.5", "source": { "type": "git", "url": "https://github.com/zendframework/zend-diactoros.git", - "reference": "4d54fde709664562eb63356f0250d527824d05de" + "reference": "b1d59735b672865dbeb930805029c24f226e3e77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/4d54fde709664562eb63356f0250d527824d05de", - "reference": "4d54fde709664562eb63356f0250d527824d05de", + "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/b1d59735b672865dbeb930805029c24f226e3e77", + "reference": "b1d59735b672865dbeb930805029c24f226e3e77", "shasum": "" }, "require": { - "php": ">=5.4", + "php": "^5.4 || ^7.0", "psr/http-message": "~1.0" }, "provide": { @@ -570,7 +570,7 @@ "psr", "psr-7" ], - "time": "2016-01-04 21:37:32" + "time": "2016-03-17 18:02:05" } ], "packages-dev": [], From 59e8785f507260ac1454550e7eaeb188e198991e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 22 Mar 2016 10:45:28 -0400 Subject: [PATCH 329/444] Applied fixes from StyleCI --- examples/src/Repositories/UserRepository.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/src/Repositories/UserRepository.php b/examples/src/Repositories/UserRepository.php index 257fe754..11a0bdec 100644 --- a/examples/src/Repositories/UserRepository.php +++ b/examples/src/Repositories/UserRepository.php @@ -9,7 +9,6 @@ use OAuth2ServerExamples\Entities\UserEntity; class UserRepository implements UserRepositoryInterface { - /** * Get a user entity. * @@ -30,6 +29,6 @@ class UserRepository implements UserRepositoryInterface return new UserEntity(); } - return null; + return; } } From 09770dc537150cce12d37ccc5ea069351c2d743b Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 22 Mar 2016 15:11:20 +0000 Subject: [PATCH 330/444] Inject client into getUserEntityByUserCredentials method --- examples/src/Repositories/UserRepository.php | 19 +++++++++++++------ src/Grant/AuthCodeGrant.php | 1 + src/Grant/ImplicitGrant.php | 1 + src/Grant/PasswordGrant.php | 14 ++++++++------ src/Repositories/UserRepositoryInterface.php | 18 +++++++++++++----- 5 files changed, 36 insertions(+), 17 deletions(-) diff --git a/examples/src/Repositories/UserRepository.php b/examples/src/Repositories/UserRepository.php index 257fe754..5bf1c433 100644 --- a/examples/src/Repositories/UserRepository.php +++ b/examples/src/Repositories/UserRepository.php @@ -2,6 +2,7 @@ namespace OAuth2ServerExamples\Repositories; +use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use OAuth2ServerExamples\Entities\ScopeEntity; @@ -13,15 +14,21 @@ class UserRepository implements UserRepositoryInterface /** * Get a user entity. * - * @param string $username - * @param string $password - * @param string $grantType The grant type used - * @param ScopeEntityInterface[] $scopes + * @param string $username + * @param string $password + * @param string $grantType The grant type used + * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $clientEntity + * @param ScopeEntityInterface[] $scopes * * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface */ - public function getUserEntityByUserCredentials($username, $password, $grantType, array &$scopes) - { + public function getUserEntityByUserCredentials( + $username, + $password, + $grantType, + ClientEntityInterface $clientEntity, + array &$scopes + ) { if ($username === 'alex' && $password === 'whisky') { $scope = new ScopeEntity(); $scope->setIdentifier('email'); diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 5668f7be..b08bf965 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -125,6 +125,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant $usernameParameter, $passwordParameter, $this->getIdentifier(), + $client, $scopes ); diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 3929560d..3f2f1cb5 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -123,6 +123,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant $usernameParameter, $passwordParameter, $this->getIdentifier(), + $client, $scopes ); diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index c5e269f0..a399e5f7 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -11,6 +11,7 @@ namespace League\OAuth2\Server\Grant; use League\Event\Event; +use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; @@ -49,7 +50,7 @@ class PasswordGrant extends AbstractGrant // Validate request $client = $this->validateClient($request); $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client); - $user = $this->validateUser($request, $scopes); + $user = $this->validateUser($request, $client, $scopes); // Issue and persist new tokens $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $scopes); @@ -63,14 +64,14 @@ class PasswordGrant extends AbstractGrant } /** - * @param \Psr\Http\Message\ServerRequestInterface $request - * @param ScopeEntityInterface[] $scopes - * - * @throws \League\OAuth2\Server\Exception\OAuthServerException + * @param \Psr\Http\Message\ServerRequestInterface $request + * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client + * @param ScopeEntityInterface[] $scopes * * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface + * @throws \League\OAuth2\Server\Exception\OAuthServerException */ - protected function validateUser(ServerRequestInterface $request, array &$scopes) + protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client, array &$scopes) { $username = $this->getRequestParameter('username', $request); if (is_null($username)) { @@ -86,6 +87,7 @@ class PasswordGrant extends AbstractGrant $username, $password, $this->getIdentifier(), + $client, $scopes ); if (!$user instanceof UserEntityInterface) { diff --git a/src/Repositories/UserRepositoryInterface.php b/src/Repositories/UserRepositoryInterface.php index a2ae0701..c0705649 100644 --- a/src/Repositories/UserRepositoryInterface.php +++ b/src/Repositories/UserRepositoryInterface.php @@ -2,6 +2,7 @@ namespace League\OAuth2\Server\Repositories; +use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; interface UserRepositoryInterface extends RepositoryInterface @@ -9,12 +10,19 @@ interface UserRepositoryInterface extends RepositoryInterface /** * Get a user entity. * - * @param string $username - * @param string $password - * @param string $grantType The grant type used - * @param ScopeEntityInterface[] $scopes + * @param string $username + * @param string $password + * @param string $grantType The grant type used + * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $clientEntity + * @param ScopeEntityInterface[] $scopes * * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface */ - public function getUserEntityByUserCredentials($username, $password, $grantType, array &$scopes); + public function getUserEntityByUserCredentials( + $username, + $password, + $grantType, + ClientEntityInterface $clientEntity, + array &$scopes + ); } From 945731cb3989b715bb2763c4d6adfe81c164bb1f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 22 Mar 2016 11:11:39 -0400 Subject: [PATCH 331/444] Applied fixes from StyleCI --- examples/src/Repositories/UserRepository.php | 2 +- src/Grant/PasswordGrant.php | 3 ++- src/Repositories/UserRepositoryInterface.php | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/src/Repositories/UserRepository.php b/examples/src/Repositories/UserRepository.php index 4038fc88..403a568d 100644 --- a/examples/src/Repositories/UserRepository.php +++ b/examples/src/Repositories/UserRepository.php @@ -15,7 +15,7 @@ class UserRepository implements UserRepositoryInterface * * @param string $username * @param string $password - * @param string $grantType The grant type used + * @param string $grantType The grant type used * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $clientEntity * @param ScopeEntityInterface[] $scopes * diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index a399e5f7..7f5b5407 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -68,8 +68,9 @@ class PasswordGrant extends AbstractGrant * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client * @param ScopeEntityInterface[] $scopes * - * @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, ClientEntityInterface $client, array &$scopes) { diff --git a/src/Repositories/UserRepositoryInterface.php b/src/Repositories/UserRepositoryInterface.php index c0705649..ad247a9b 100644 --- a/src/Repositories/UserRepositoryInterface.php +++ b/src/Repositories/UserRepositoryInterface.php @@ -12,7 +12,7 @@ interface UserRepositoryInterface extends RepositoryInterface * * @param string $username * @param string $password - * @param string $grantType The grant type used + * @param string $grantType The grant type used * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $clientEntity * @param ScopeEntityInterface[] $scopes * From 878afeb9f93b83d02696fbbb7b1ed42bcab21e54 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 22 Mar 2016 16:29:04 +0000 Subject: [PATCH 332/444] ClientRepository implementations are now responsible for dealing with client secret --- .../Interfaces/ClientEntityInterface.php | 12 ------------ src/Grant/AbstractGrant.php | 19 ++++++------------- src/Grant/AuthCodeGrant.php | 1 - .../ClientRepositoryInterface.php | 7 ++++--- tests/Grant/AbstractGrantTest.php | 8 ++------ 5 files changed, 12 insertions(+), 35 deletions(-) diff --git a/src/Entities/Interfaces/ClientEntityInterface.php b/src/Entities/Interfaces/ClientEntityInterface.php index 180719b1..4ca55442 100644 --- a/src/Entities/Interfaces/ClientEntityInterface.php +++ b/src/Entities/Interfaces/ClientEntityInterface.php @@ -32,18 +32,6 @@ interface ClientEntityInterface */ public function setName($name); - /** - * @param string $secret - */ - public function setSecret($secret); - - /** - * Get the hashed client secret - * - * @return string - */ - public function getSecret(); - /** * Set the client's redirect uri. * diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 49b03741..92a55a1f 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -153,15 +153,6 @@ abstract class AbstractGrant implements GrantTypeInterface 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', @@ -169,11 +160,13 @@ abstract class AbstractGrant implements GrantTypeInterface $this->getServerParameter('PHP_AUTH_PW', $request) ); - if ($client->canKeepASecret() && is_null($clientSecret)) { - throw OAuthServerException::invalidRequest('client_secret', '`%s` parameter is missing'); - } + $client = $this->clientRepository->getClientEntity( + $clientId, + $this->getIdentifier(), + $clientSecret + ); - if ($client->canKeepASecret() && password_verify($clientSecret, $client->getSecret()) === false) { + if (!$client instanceof ClientEntityInterface) { $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); throw OAuthServerException::invalidClient(); } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index b08bf965..d804b191 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -73,7 +73,6 @@ class AuthCodeGrant extends AbstractAuthorizeGrant if ($client instanceof ClientEntityInterface === false) { $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); - throw OAuthServerException::invalidClient(); } diff --git a/src/Repositories/ClientRepositoryInterface.php b/src/Repositories/ClientRepositoryInterface.php index 0c7ebe4f..a742b366 100644 --- a/src/Repositories/ClientRepositoryInterface.php +++ b/src/Repositories/ClientRepositoryInterface.php @@ -18,10 +18,11 @@ interface ClientRepositoryInterface extends RepositoryInterface /** * Get a client. * - * @param string $clientIdentifier The client's identifier - * @param string $grantType The grant type used + * @param string $clientIdentifier The client's identifier + * @param string $grantType The grant type used + * @param null|string $clientSecret The client's secret (if sent) * * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface */ - public function getClientEntity($clientIdentifier, $grantType); + public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null); } diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 5e71bdf7..1161ebc4 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -111,10 +111,8 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase */ public function testValidateClientMissingClientSecret() { - $client = new ClientEntity(); - $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); - $clientRepositoryMock->method('getClientEntity')->willReturn($client); + $clientRepositoryMock->method('getClientEntity')->willReturn(null); /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); @@ -138,10 +136,8 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase */ public function testValidateClientInvalidClientSecret() { - $client = new ClientEntity(); - $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); - $clientRepositoryMock->method('getClientEntity')->willReturn($client); + $clientRepositoryMock->method('getClientEntity')->willReturn(null); /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); From 95cdaae17f0b9bf0b3086bf9cda02031088fd3ab Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 22 Mar 2016 17:07:30 +0000 Subject: [PATCH 333/444] Removed unused method --- src/Entities/Interfaces/ClientEntityInterface.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Entities/Interfaces/ClientEntityInterface.php b/src/Entities/Interfaces/ClientEntityInterface.php index 4ca55442..4ed17162 100644 --- a/src/Entities/Interfaces/ClientEntityInterface.php +++ b/src/Entities/Interfaces/ClientEntityInterface.php @@ -45,11 +45,4 @@ interface ClientEntityInterface * @return string */ public function getRedirectUri(); - - /** - * Returns true if the client is capable of keeping it's secrets secret. - * - * @return bool - */ - public function canKeepASecret(); } From a698a4da7ec434e162f11187b9c088c2c5427421 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 23 Mar 2016 12:54:17 +0000 Subject: [PATCH 334/444] Added RequestEvent --- src/Grant/AbstractGrant.php | 4 ++-- src/Grant/AuthCodeGrant.php | 4 ++-- src/Grant/ImplicitGrant.php | 6 +++--- src/Grant/PasswordGrant.php | 3 ++- src/Grant/RefreshTokenGrant.php | 7 ++----- src/RequestEvent.php | 34 +++++++++++++++++++++++++++++++++ 6 files changed, 45 insertions(+), 13 deletions(-) create mode 100644 src/RequestEvent.php diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 92a55a1f..51661d1c 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -11,7 +11,6 @@ namespace League\OAuth2\Server\Grant; use League\Event\EmitterAwareTrait; -use League\Event\Event; use League\OAuth2\Server\CryptTrait; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\AuthCodeEntity; @@ -26,6 +25,7 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\RequestEvent; use Psr\Http\Message\ServerRequestInterface; /** @@ -167,7 +167,7 @@ abstract class AbstractGrant implements GrantTypeInterface ); if (!$client instanceof ClientEntityInterface) { - $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); + $this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request)); throw OAuthServerException::invalidClient(); } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index d804b191..8146a2d2 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -3,13 +3,13 @@ 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; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\RequestEvent; use League\OAuth2\Server\ResponseTypes\HtmlResponse; use League\OAuth2\Server\ResponseTypes\RedirectResponse; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; @@ -72,7 +72,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant ); if ($client instanceof ClientEntityInterface === false) { - $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); + $this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request)); throw OAuthServerException::invalidClient(); } diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 3f2f1cb5..c6a578e8 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -2,11 +2,11 @@ namespace League\OAuth2\Server\Grant; -use League\Event\Event; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\RequestEvent; use League\OAuth2\Server\ResponseTypes\HtmlResponse; use League\OAuth2\Server\ResponseTypes\RedirectResponse; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; @@ -68,14 +68,14 @@ class ImplicitGrant extends AbstractAuthorizeGrant ); if ($client instanceof ClientEntityInterface === false) { - $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); + $this->getEmitter()->emit(new RequestEvent('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)); + $this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request)); throw OAuthServerException::invalidClient(); } diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 7f5b5407..fb6d07f6 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -17,6 +17,7 @@ use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\RequestEvent; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ServerRequestInterface; @@ -92,7 +93,7 @@ class PasswordGrant extends AbstractGrant $scopes ); if (!$user instanceof UserEntityInterface) { - $this->getEmitter()->emit(new Event('user.authentication.failed', $request)); + $this->getEmitter()->emit(new RequestEvent('user.authentication.failed', $request)); throw OAuthServerException::invalidCredentials(); } diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 3dee1073..b25c1537 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -10,9 +10,9 @@ */ namespace League\OAuth2\Server\Grant; -use League\Event\Event; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; +use League\OAuth2\Server\RequestEvent; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ServerRequestInterface; @@ -66,8 +66,6 @@ class RefreshTokenGrant extends AbstractGrant // the request doesn't include any new scopes foreach ($scopes as $scope) { if (in_array($scope->getIdentifier(), $oldRefreshToken['scopes']) === false) { - $this->getEmitter()->emit(new Event('scope.selection.failed', $request)); - throw OAuthServerException::invalidScope($scope->getIdentifier()); } } @@ -114,8 +112,7 @@ class RefreshTokenGrant extends AbstractGrant $refreshTokenData = json_decode($refreshToken, true); if ($refreshTokenData['client_id'] !== $clientId) { - $this->getEmitter()->emit(new Event('refresh_token.client.failed', $request)); - + $this->getEmitter()->emit(new RequestEvent('refresh_token.client.failed', $request)); throw OAuthServerException::invalidRefreshToken( 'Token is not linked to client,' . ' got: ' . $clientId . diff --git a/src/RequestEvent.php b/src/RequestEvent.php new file mode 100644 index 00000000..f37847e0 --- /dev/null +++ b/src/RequestEvent.php @@ -0,0 +1,34 @@ +request = $request; + } + + /** + * @return ServerRequestInterface + */ + public function getRequest() + { + return $this->request; + } +} \ No newline at end of file From 864a27f2c827cc59b47e21e92a901f5d5776593f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 23 Mar 2016 08:54:30 -0400 Subject: [PATCH 335/444] Applied fixes from StyleCI --- src/Grant/PasswordGrant.php | 1 - src/RequestEvent.php | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index fb6d07f6..6e5812b9 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -10,7 +10,6 @@ */ namespace League\OAuth2\Server\Grant; -use League\Event\Event; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; diff --git a/src/RequestEvent.php b/src/RequestEvent.php index f37847e0..d8f7da08 100644 --- a/src/RequestEvent.php +++ b/src/RequestEvent.php @@ -18,7 +18,7 @@ class RequestEvent extends Event * @param string $name * @param \Psr\Http\Message\ServerRequestInterface $request */ - public function __construct($name, ServerRequestInterface $request) + public function __construct($name, ServerRequestInterface $request) { parent::__construct($name); $this->request = $request; @@ -31,4 +31,4 @@ class RequestEvent extends Event { return $this->request; } -} \ No newline at end of file +} From b5b5d9f34725084bdd1acc09016cfc6ce599aa71 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 23 Mar 2016 18:36:23 +0000 Subject: [PATCH 336/444] Added finalizeScopes method to ScopeRepositoryInterface --- src/Grant/AuthCodeGrant.php | 4 ++++ src/Grant/ClientCredentialsGrant.php | 3 +++ src/Grant/ImplicitGrant.php | 4 ++++ src/Grant/PasswordGrant.php | 11 ++++++----- src/Repositories/ScopeRepositoryInterface.php | 15 +++++++++++++++ 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 8146a2d2..d035001b 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -190,6 +190,10 @@ class AuthCodeGrant extends AbstractAuthorizeGrant // THe user approved the client, redirect them back with an auth code if ($userHasApprovedClient === true) { + + // Finalize the requested scopes + $scopes = $this->scopeRepository->finalizeScopes($scopes, $client, $userId); + $authCode = $this->issueAuthCode( $this->authCodeTTL, $client, diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 1b15defd..3c1db5e0 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -30,6 +30,9 @@ class ClientCredentialsGrant extends AbstractGrant $client = $this->validateClient($request); $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client); + // Finalize the requested scopes + $scopes = $this->scopeRepository->finalizeScopes($scopes, $client); + // Issue and persist access token $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $client->getIdentifier(), $scopes); diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index c6a578e8..076cd582 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -189,6 +189,10 @@ class ImplicitGrant extends AbstractAuthorizeGrant // THe user approved the client, redirect them back with an access token if ($userHasApprovedClient === true) { + + // Finalize the requested scopes + $scopes = $this->scopeRepository->finalizeScopes($scopes, $client, $userId); + $accessToken = $this->issueAccessToken( $accessTokenTTL, $client, diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index fb6d07f6..a6a53e4f 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -51,7 +51,10 @@ class PasswordGrant extends AbstractGrant // Validate request $client = $this->validateClient($request); $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client); - $user = $this->validateUser($request, $client, $scopes); + $user = $this->validateUser($request, $client); + + // Finalize the requested scopes + $scopes = $this->scopeRepository->finalizeScopes($scopes, $client, $user->getIdentifier()); // Issue and persist new tokens $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $scopes); @@ -67,13 +70,12 @@ class PasswordGrant extends AbstractGrant /** * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client - * @param ScopeEntityInterface[] $scopes * * @throws \League\OAuth2\Server\Exception\OAuthServerException * * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface */ - protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client, array &$scopes) + protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client) { $username = $this->getRequestParameter('username', $request); if (is_null($username)) { @@ -89,8 +91,7 @@ class PasswordGrant extends AbstractGrant $username, $password, $this->getIdentifier(), - $client, - $scopes + $client ); if (!$user instanceof UserEntityInterface) { $this->getEmitter()->emit(new RequestEvent('user.authentication.failed', $request)); diff --git a/src/Repositories/ScopeRepositoryInterface.php b/src/Repositories/ScopeRepositoryInterface.php index 5ac9aff8..5b44c615 100644 --- a/src/Repositories/ScopeRepositoryInterface.php +++ b/src/Repositories/ScopeRepositoryInterface.php @@ -10,6 +10,9 @@ */ namespace League\OAuth2\Server\Repositories; +use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; + /** * Scope interface. */ @@ -25,4 +28,16 @@ interface ScopeRepositoryInterface extends RepositoryInterface * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface */ public function getScopeEntityByIdentifier($identifier, $grantType, $clientId = null); + + /** + * Given a client and user validate the set of scopes requested are valid and optionally + * append additional scopes or remove requested scopes. + * + * @param ScopeEntityInterface[] $scopes + * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $clientEntity + * @param null|string $userIdentifier + * + * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] + */ + public function finalizeScopes(array $scopes = [], ClientEntityInterface $clientEntity, $userIdentifier = null); } From a49c76268341e836165d299b4c1dfa1c501a309a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 23 Mar 2016 18:36:43 +0000 Subject: [PATCH 337/444] Remove injected array of scopes --- src/Repositories/UserRepositoryInterface.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Repositories/UserRepositoryInterface.php b/src/Repositories/UserRepositoryInterface.php index ad247a9b..b21503a7 100644 --- a/src/Repositories/UserRepositoryInterface.php +++ b/src/Repositories/UserRepositoryInterface.php @@ -3,7 +3,6 @@ namespace League\OAuth2\Server\Repositories; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; interface UserRepositoryInterface extends RepositoryInterface { @@ -14,7 +13,6 @@ interface UserRepositoryInterface extends RepositoryInterface * @param string $password * @param string $grantType The grant type used * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $clientEntity - * @param ScopeEntityInterface[] $scopes * * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface */ @@ -22,7 +20,6 @@ interface UserRepositoryInterface extends RepositoryInterface $username, $password, $grantType, - ClientEntityInterface $clientEntity, - array &$scopes + ClientEntityInterface $clientEntity ); } From cca401e66eadf760009bb2a6c13ce232093478f3 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 23 Mar 2016 14:37:07 -0400 Subject: [PATCH 338/444] Applied fixes from StyleCI --- src/Grant/PasswordGrant.php | 1 - src/Repositories/ScopeRepositoryInterface.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 1d2af5e6..40bf39d5 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -11,7 +11,6 @@ namespace League\OAuth2\Server\Grant; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; diff --git a/src/Repositories/ScopeRepositoryInterface.php b/src/Repositories/ScopeRepositoryInterface.php index 5b44c615..f8731fea 100644 --- a/src/Repositories/ScopeRepositoryInterface.php +++ b/src/Repositories/ScopeRepositoryInterface.php @@ -39,5 +39,5 @@ interface ScopeRepositoryInterface extends RepositoryInterface * * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] */ - public function finalizeScopes(array $scopes = [], ClientEntityInterface $clientEntity, $userIdentifier = null); + public function finalizeScopes(array $scopes, ClientEntityInterface $clientEntity, $userIdentifier = null); } From a18b8c57b2233d3df700a28d0ac64c19f48d17a4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 23 Mar 2016 18:50:14 +0000 Subject: [PATCH 339/444] Fix broken tests --- src/Grant/ClientCredentialsGrant.php | 2 +- src/Grant/ImplicitGrant.php | 3 +-- src/Repositories/ScopeRepositoryInterface.php | 2 +- tests/Grant/AuthCodeGrantTest.php | 8 ++++++++ tests/Grant/ClientCredentialsGrantTest.php | 5 +++++ tests/Grant/ImplicitGrantTest.php | 5 +++++ tests/Grant/PasswordGrantTest.php | 5 +++++ .../Middleware/AuthenticationServerMiddlewareTest.php | 5 ++++- tests/ServerTest.php | 10 ++++++++-- 9 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 3c1db5e0..5b80d02f 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -32,7 +32,7 @@ class ClientCredentialsGrant extends AbstractGrant // Finalize the requested scopes $scopes = $this->scopeRepository->finalizeScopes($scopes, $client); - + // Issue and persist access token $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $client->getIdentifier(), $scopes); diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 076cd582..62aacb06 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -123,8 +123,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant $usernameParameter, $passwordParameter, $this->getIdentifier(), - $client, - $scopes + $client ); if ($userEntity instanceof UserEntityInterface) { diff --git a/src/Repositories/ScopeRepositoryInterface.php b/src/Repositories/ScopeRepositoryInterface.php index 5b44c615..1f933426 100644 --- a/src/Repositories/ScopeRepositoryInterface.php +++ b/src/Repositories/ScopeRepositoryInterface.php @@ -30,7 +30,7 @@ interface ScopeRepositoryInterface extends RepositoryInterface public function getScopeEntityByIdentifier($identifier, $grantType, $clientId = null); /** - * Given a client and user validate the set of scopes requested are valid and optionally + * Given a client (and optional user identifier) validate the set of scopes requested are valid and optionally * append additional scopes or remove requested scopes. * * @param ScopeEntityInterface[] $scopes diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 44bba0fc..1dfb6974 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -87,6 +87,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), @@ -95,6 +98,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setScopeRepository($scopeRepositoryMock); $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); @@ -410,6 +414,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), @@ -418,6 +425,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setScopeRepository($scopeRepositoryMock); $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); diff --git a/tests/Grant/ClientCredentialsGrantTest.php b/tests/Grant/ClientCredentialsGrantTest.php index 7ca1487d..c41528c5 100644 --- a/tests/Grant/ClientCredentialsGrantTest.php +++ b/tests/Grant/ClientCredentialsGrantTest.php @@ -6,6 +6,7 @@ use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; use Zend\Diactoros\ServerRequest; @@ -28,9 +29,13 @@ class ClientCredentialsGrantTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $grant = new ClientCredentialsGrant(); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setScopeRepository($scopeRepositoryMock); $serverRequest = new ServerRequest(); $serverRequest = $serverRequest->withParsedBody( diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index e4e10db0..680b55ac 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -6,6 +6,7 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ImplicitGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\HtmlResponse; use LeagueTests\Stubs\ClientEntity; @@ -72,9 +73,13 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $grant = new ImplicitGrant($userRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setScopeRepository($scopeRepositoryMock); $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php index d7938b94..31043d1a 100644 --- a/tests/Grant/PasswordGrantTest.php +++ b/tests/Grant/PasswordGrantTest.php @@ -8,6 +8,7 @@ use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; @@ -42,9 +43,13 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setScopeRepository($scopeRepositoryMock); $serverRequest = new ServerRequest(); $serverRequest = $serverRequest->withParsedBody( diff --git a/tests/Middleware/AuthenticationServerMiddlewareTest.php b/tests/Middleware/AuthenticationServerMiddlewareTest.php index 8fb8a553..4acd5c89 100644 --- a/tests/Middleware/AuthenticationServerMiddlewareTest.php +++ b/tests/Middleware/AuthenticationServerMiddlewareTest.php @@ -20,10 +20,13 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase $clientRepository = $this->getMock(ClientRepositoryInterface::class); $clientRepository->method('getClientEntity')->willReturn(new ClientEntity()); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $server = new Server( $clientRepository, $this->getMock(AccessTokenRepositoryInterface::class), - $this->getMock(ScopeRepositoryInterface::class), + $scopeRepositoryMock, '', '', new StubResponseType() diff --git a/tests/ServerTest.php b/tests/ServerTest.php index cf52cf8f..f61818cf 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -48,10 +48,13 @@ class ServerTest extends \PHPUnit_Framework_TestCase $clientRepository = $this->getMock(ClientRepositoryInterface::class); $clientRepository->method('getClientEntity')->willReturn(new ClientEntity()); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $server = new Server( $clientRepository, $this->getMock(AccessTokenRepositoryInterface::class), - $this->getMock(ScopeRepositoryInterface::class), + $scopeRepositoryMock, '', '', new StubResponseType() @@ -75,10 +78,13 @@ class ServerTest extends \PHPUnit_Framework_TestCase $clientRepository = $this->getMock(ClientRepositoryInterface::class); $clientRepository->method('getClientEntity')->willReturn($client); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $server = new Server( $clientRepository, $this->getMock(AccessTokenRepositoryInterface::class), - $this->getMock(ScopeRepositoryInterface::class), + $scopeRepositoryMock, 'file://' . __DIR__ . '/Stubs/private.key', 'file://' . __DIR__ . '/Stubs/public.key', new StubResponseType() From 267bd3c5d4f4767e0251474aca501f7293182279 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 23 Mar 2016 14:50:27 -0400 Subject: [PATCH 340/444] Applied fixes from StyleCI --- src/Grant/ClientCredentialsGrant.php | 2 +- src/Grant/PasswordGrant.php | 1 - src/Repositories/ScopeRepositoryInterface.php | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 5b80d02f..3c1db5e0 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -32,7 +32,7 @@ class ClientCredentialsGrant extends AbstractGrant // Finalize the requested scopes $scopes = $this->scopeRepository->finalizeScopes($scopes, $client); - + // Issue and persist access token $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $client->getIdentifier(), $scopes); diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 1d2af5e6..40bf39d5 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -11,7 +11,6 @@ namespace League\OAuth2\Server\Grant; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; diff --git a/src/Repositories/ScopeRepositoryInterface.php b/src/Repositories/ScopeRepositoryInterface.php index 1f933426..95230bb6 100644 --- a/src/Repositories/ScopeRepositoryInterface.php +++ b/src/Repositories/ScopeRepositoryInterface.php @@ -39,5 +39,5 @@ interface ScopeRepositoryInterface extends RepositoryInterface * * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] */ - public function finalizeScopes(array $scopes = [], ClientEntityInterface $clientEntity, $userIdentifier = null); + public function finalizeScopes(array $scopes, ClientEntityInterface $clientEntity, $userIdentifier = null); } From 614fbde56e8fdeacf74253a09e8979bdc4c0ec8a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 24 Mar 2016 10:01:49 +0000 Subject: [PATCH 341/444] Updated composer.lock --- examples/composer.lock | 59 ++++-------------------------------------- 1 file changed, 5 insertions(+), 54 deletions(-) diff --git a/examples/composer.lock b/examples/composer.lock index fd03f27b..a5a93bbd 100644 --- a/examples/composer.lock +++ b/examples/composer.lock @@ -148,15 +148,15 @@ "dist": { "type": "path", "url": "../", - "reference": "d635b3484bdf41b494b6e6107f88ad61f9859af7", + "reference": "0fbe109e2004c71feac2bd14fd85aff97704b2e5", "shasum": null }, "require": { "lcobucci/jwt": "^3.1", - "league/event": "~2.1", + "league/event": "^2.1", "paragonie/random_compat": "^1.1", "php": ">=5.5.9", - "zendframework/zend-diactoros": "~1.1" + "psr/http-message": "^1.0" }, "replace": { "league/oauth2server": "*", @@ -164,7 +164,8 @@ }, "require-dev": { "league/plates": "^3.1", - "phpunit/phpunit": "^4.8" + "phpunit/phpunit": "^4.8", + "zendframework/zend-diactoros": "^1.0" }, "suggest": { "league/plates": "Used for parsing authorization code templates", @@ -521,56 +522,6 @@ "router" ], "time": "2015-12-07 14:11:09" - }, - { - "name": "zendframework/zend-diactoros", - "version": "1.3.5", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-diactoros.git", - "reference": "b1d59735b672865dbeb930805029c24f226e3e77" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/b1d59735b672865dbeb930805029c24f226e3e77", - "reference": "b1d59735b672865dbeb930805029c24f226e3e77", - "shasum": "" - }, - "require": { - "php": "^5.4 || ^7.0", - "psr/http-message": "~1.0" - }, - "provide": { - "psr/http-message-implementation": "~1.0.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.6", - "squizlabs/php_codesniffer": "^2.3.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev", - "dev-develop": "1.4-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\Diactoros\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "description": "PSR HTTP Message implementations", - "homepage": "https://github.com/zendframework/zend-diactoros", - "keywords": [ - "http", - "psr", - "psr-7" - ], - "time": "2016-03-17 18:02:05" } ], "packages-dev": [], From 6383a58755705fd71ea1cdc6f8999de78cdb4909 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 24 Mar 2016 10:04:15 +0000 Subject: [PATCH 342/444] Updated scope validation --- examples/src/Repositories/ScopeRepository.php | 17 ++++++++++++++++- examples/src/Repositories/UserRepository.php | 14 ++------------ src/Grant/AbstractGrant.php | 6 +----- src/Grant/AuthCodeGrant.php | 14 +++++--------- src/Grant/ClientCredentialsGrant.php | 2 +- src/Grant/ImplicitGrant.php | 6 ++---- src/Grant/PasswordGrant.php | 2 +- src/Grant/RefreshTokenGrant.php | 6 +----- src/Repositories/ScopeRepositoryInterface.php | 16 ++++++++++------ 9 files changed, 39 insertions(+), 44 deletions(-) diff --git a/examples/src/Repositories/ScopeRepository.php b/examples/src/Repositories/ScopeRepository.php index 014ca3dd..441c0116 100644 --- a/examples/src/Repositories/ScopeRepository.php +++ b/examples/src/Repositories/ScopeRepository.php @@ -2,6 +2,8 @@ namespace OAuth2ServerExamples\Repositories; +use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use OAuth2ServerExamples\Entities\ScopeEntity; @@ -10,7 +12,7 @@ class ScopeRepository implements ScopeRepositoryInterface /** * {@inheritdoc} */ - public function getScopeEntityByIdentifier($scopeIdentifier, $grantType, $clientId = null) + public function getScopeEntityByIdentifier($scopeIdentifier) { $scopes = [ 'basic' => [ @@ -30,4 +32,17 @@ class ScopeRepository implements ScopeRepositoryInterface return $scope; } + + + /** + * @inheritdoc + */ + public function finalizeScopes( + array $scopes, + $grantType, + ClientEntityInterface $clientEntity, + $userIdentifier = null + ) { + return $scopes; + } } diff --git a/examples/src/Repositories/UserRepository.php b/examples/src/Repositories/UserRepository.php index 403a568d..f69e93cf 100644 --- a/examples/src/Repositories/UserRepository.php +++ b/examples/src/Repositories/UserRepository.php @@ -3,7 +3,6 @@ namespace OAuth2ServerExamples\Repositories; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use OAuth2ServerExamples\Entities\ScopeEntity; use OAuth2ServerExamples\Entities\UserEntity; @@ -11,22 +10,13 @@ use OAuth2ServerExamples\Entities\UserEntity; class UserRepository implements UserRepositoryInterface { /** - * Get a user entity. - * - * @param string $username - * @param string $password - * @param string $grantType The grant type used - * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $clientEntity - * @param ScopeEntityInterface[] $scopes - * - * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface + * @inheritdoc */ public function getUserEntityByUserCredentials( $username, $password, $grantType, - ClientEntityInterface $clientEntity, - array &$scopes + ClientEntityInterface $clientEntity ) { if ($username === 'alex' && $password === 'whisky') { $scope = new ScopeEntity(); diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 51661d1c..14a46e35 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -205,11 +205,7 @@ abstract class AbstractGrant implements GrantTypeInterface $scopes = []; foreach ($scopesList as $scopeItem) { - $scope = $this->scopeRepository->getScopeEntityByIdentifier( - $scopeItem, - $this->getIdentifier(), - $client->getIdentifier() - ); + $scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeItem); if (($scope instanceof ScopeEntityInterface) === false) { throw OAuthServerException::invalidScope($scopeItem, $redirectUri); diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index d035001b..eec6d5f0 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -78,6 +78,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant $redirectUriParameter = $this->getQueryStringParameter('redirect_uri', $request, $client->getRedirectUri()); if ($redirectUriParameter !== $client->getRedirectUri()) { + $this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request)); throw OAuthServerException::invalidClient(); } @@ -124,8 +125,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant $usernameParameter, $passwordParameter, $this->getIdentifier(), - $client, - $scopes + $client ); if ($userEntity instanceof UserEntityInterface) { @@ -134,7 +134,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant $loginError = 'Incorrect username or password'; } } - + // The user hasn't logged in yet so show a login form if ($userId === null) { $html = $this->getTemplateRenderer()->renderLogin([ @@ -192,7 +192,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant if ($userHasApprovedClient === true) { // Finalize the requested scopes - $scopes = $this->scopeRepository->finalizeScopes($scopes, $client, $userId); + $scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $userId); $authCode = $this->issueAuthCode( $this->authCodeTTL, @@ -281,11 +281,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant $scopes = []; foreach ($authCodePayload->scopes as $scopeId) { - $scope = $this->scopeRepository->getScopeEntityByIdentifier( - $scopeId, - $this->getIdentifier(), - $client->getIdentifier() - ); + $scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeId); if (!$scope) { // @codeCoverageIgnoreStart diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 3c1db5e0..41a47f6f 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -31,7 +31,7 @@ class ClientCredentialsGrant extends AbstractGrant $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client); // Finalize the requested scopes - $scopes = $this->scopeRepository->finalizeScopes($scopes, $client); + $scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client); // Issue and persist access token $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $client->getIdentifier(), $scopes); diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 62aacb06..f932730d 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -69,14 +69,12 @@ class ImplicitGrant extends AbstractAuthorizeGrant if ($client instanceof ClientEntityInterface === false) { $this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request)); - throw OAuthServerException::invalidClient(); } $redirectUriParameter = $this->getQueryStringParameter('redirect_uri', $request, $client->getRedirectUri()); if ($redirectUriParameter !== $client->getRedirectUri()) { $this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request)); - throw OAuthServerException::invalidClient(); } @@ -114,7 +112,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant // 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 @@ -190,7 +188,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant if ($userHasApprovedClient === true) { // Finalize the requested scopes - $scopes = $this->scopeRepository->finalizeScopes($scopes, $client, $userId); + $scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $userId); $accessToken = $this->issueAccessToken( $accessTokenTTL, diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 40bf39d5..be3d4707 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -52,7 +52,7 @@ class PasswordGrant extends AbstractGrant $user = $this->validateUser($request, $client); // Finalize the requested scopes - $scopes = $this->scopeRepository->finalizeScopes($scopes, $client, $user->getIdentifier()); + $scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $user->getIdentifier()); // Issue and persist new tokens $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $scopes); diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index b25c1537..10ebcad5 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -47,11 +47,7 @@ class RefreshTokenGrant extends AbstractGrant // If no new scopes are requested then give the access token the original session scopes if (count($scopes) === 0) { $scopes = array_map(function ($scopeId) use ($client) { - $scope = $this->scopeRepository->getScopeEntityByIdentifier( - $scopeId, - $this->getIdentifier(), - $client->getIdentifier() - ); + $scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeId); if (!$scope) { // @codeCoverageIgnoreStart diff --git a/src/Repositories/ScopeRepositoryInterface.php b/src/Repositories/ScopeRepositoryInterface.php index 95230bb6..ccafbbdd 100644 --- a/src/Repositories/ScopeRepositoryInterface.php +++ b/src/Repositories/ScopeRepositoryInterface.php @@ -21,23 +21,27 @@ interface ScopeRepositoryInterface extends RepositoryInterface /** * Return information about a scope. * - * @param string $identifier The scope identifier - * @param string $grantType The grant type used in the request - * @param string|null $clientId The client sending the request + * @param string $identifier The scope identifier * * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface */ - public function getScopeEntityByIdentifier($identifier, $grantType, $clientId = null); + public function getScopeEntityByIdentifier($identifier); /** - * Given a client (and optional user identifier) validate the set of scopes requested are valid and optionally + * Given a client, grant type and optional user identifier validate the set of scopes requested are valid and optionally * append additional scopes or remove requested scopes. * * @param ScopeEntityInterface[] $scopes + * @param string $grantType * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $clientEntity * @param null|string $userIdentifier * * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] */ - public function finalizeScopes(array $scopes, ClientEntityInterface $clientEntity, $userIdentifier = null); + public function finalizeScopes( + array $scopes, + $grantType, + ClientEntityInterface $clientEntity, + $userIdentifier = null + ); } From 115237bc1a16d190ddb5f186ffa3d3a9e877b1e6 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 24 Mar 2016 10:04:48 +0000 Subject: [PATCH 343/444] Added missing return statement --- src/Grant/ImplicitGrant.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index f932730d..eaab499d 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -209,6 +209,8 @@ class ImplicitGrant extends AbstractAuthorizeGrant '#' ) ); + + return $response; } // The user denied the client, redirect them back with an error From 2b76e2bf6ef3dcddb479982b54308859009d27cb Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 24 Mar 2016 10:07:09 +0000 Subject: [PATCH 344/444] Fix for broken test which wasn't actually broken but was --- tests/Grant/ImplicitGrantTest.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 680b55ac..06525b9c 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -9,6 +9,7 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\HtmlResponse; +use League\OAuth2\Server\ResponseTypes\RedirectResponse; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\CryptTraitStub; use LeagueTests\Stubs\StubResponseType; @@ -55,10 +56,6 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $this->assertTrue($grant->canRespondToRequest($request)); } - /** - * @expectedException \League\OAuth2\Server\Exception\OAuthServerException - * @expectedExceptionCode 9 - */ public function testRespondToAuthorizationRequest() { $client = new ClientEntity(); @@ -106,7 +103,9 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase ] ); - $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof RedirectResponse); } /** From 630a92b45fe598ab7c84fdd0c41281f113f26c27 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 24 Mar 2016 06:07:20 -0400 Subject: [PATCH 345/444] Applied fixes from StyleCI --- examples/src/Repositories/ScopeRepository.php | 4 +--- examples/src/Repositories/UserRepository.php | 2 +- src/Grant/AuthCodeGrant.php | 2 +- src/Grant/ImplicitGrant.php | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/examples/src/Repositories/ScopeRepository.php b/examples/src/Repositories/ScopeRepository.php index 441c0116..26aa15cb 100644 --- a/examples/src/Repositories/ScopeRepository.php +++ b/examples/src/Repositories/ScopeRepository.php @@ -3,7 +3,6 @@ namespace OAuth2ServerExamples\Repositories; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use OAuth2ServerExamples\Entities\ScopeEntity; @@ -33,9 +32,8 @@ class ScopeRepository implements ScopeRepositoryInterface return $scope; } - /** - * @inheritdoc + * {@inheritdoc} */ public function finalizeScopes( array $scopes, diff --git a/examples/src/Repositories/UserRepository.php b/examples/src/Repositories/UserRepository.php index f69e93cf..1ee09fc1 100644 --- a/examples/src/Repositories/UserRepository.php +++ b/examples/src/Repositories/UserRepository.php @@ -10,7 +10,7 @@ use OAuth2ServerExamples\Entities\UserEntity; class UserRepository implements UserRepositoryInterface { /** - * @inheritdoc + * {@inheritdoc} */ public function getUserEntityByUserCredentials( $username, diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index eec6d5f0..251c782d 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -134,7 +134,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant $loginError = 'Incorrect username or password'; } } - + // The user hasn't logged in yet so show a login form if ($userId === null) { $html = $this->getTemplateRenderer()->renderLogin([ diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index eaab499d..11950a78 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -112,7 +112,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant // 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 From fe0ed765a5cf46bbec3a29f068165ff007bb3df4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 24 Mar 2016 13:56:31 +0000 Subject: [PATCH 346/444] Added setTemplateRenderer method --- src/Grant/AbstractAuthorizeGrant.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Grant/AbstractAuthorizeGrant.php b/src/Grant/AbstractAuthorizeGrant.php index e409d2b2..aa578335 100644 --- a/src/Grant/AbstractAuthorizeGrant.php +++ b/src/Grant/AbstractAuthorizeGrant.php @@ -22,6 +22,16 @@ abstract class AbstractAuthorizeGrant extends AbstractGrant */ protected $templateRenderer; + /** + * Set the template renderer + * + * @param RendererInterface $templateRenderer + */ + public function setTemplateRenderer(RendererInterface $templateRenderer) + { + $this->templateRenderer = $templateRenderer; + } + /** * Retrieve template renderer. * From d8e1e0e00edd046810221ad595f5f89f217c8fd8 Mon Sep 17 00:00:00 2001 From: Frederik Bosch Date: Thu, 24 Mar 2016 15:01:55 +0100 Subject: [PATCH 347/444] remove unnecessary methods from interfaces --- .../Interfaces/ClientEntityInterface.php | 21 ------------------- .../Interfaces/ScopeEntityInterface.php | 7 ------- 2 files changed, 28 deletions(-) diff --git a/src/Entities/Interfaces/ClientEntityInterface.php b/src/Entities/Interfaces/ClientEntityInterface.php index 4ed17162..2ddb6ee9 100644 --- a/src/Entities/Interfaces/ClientEntityInterface.php +++ b/src/Entities/Interfaces/ClientEntityInterface.php @@ -11,13 +11,6 @@ interface ClientEntityInterface */ public function getIdentifier(); - /** - * Set the client's identifier. - * - * @param $identifier - */ - public function setIdentifier($identifier); - /** * Get the client's name. * @@ -25,20 +18,6 @@ interface ClientEntityInterface */ public function getName(); - /** - * Set the client's name. - * - * @param string $name - */ - public function setName($name); - - /** - * Set the client's redirect uri. - * - * @param string $redirectUri - */ - public function setRedirectUri($redirectUri); - /** * Returns the registered redirect URI. * diff --git a/src/Entities/Interfaces/ScopeEntityInterface.php b/src/Entities/Interfaces/ScopeEntityInterface.php index 44aa13be..099b66e5 100644 --- a/src/Entities/Interfaces/ScopeEntityInterface.php +++ b/src/Entities/Interfaces/ScopeEntityInterface.php @@ -10,11 +10,4 @@ interface ScopeEntityInterface extends \JsonSerializable * @return string */ public function getIdentifier(); - - /** - * Set the scope's identifier. - * - * @param $identifier - */ - public function setIdentifier($identifier); } From b1cf6a8436ac29e490d560987827cf63e7304556 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 24 Mar 2016 14:51:44 +0000 Subject: [PATCH 348/444] Fix for bad hint --- src/Grant/RefreshTokenGrant.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 10ebcad5..566fac91 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -96,7 +96,7 @@ class RefreshTokenGrant extends AbstractGrant { $encryptedRefreshToken = $this->getRequestParameter('refresh_token', $request); if (is_null($encryptedRefreshToken)) { - throw OAuthServerException::invalidRequest('refresh_token', '`%s` parameter is missing'); + throw OAuthServerException::invalidRequest('refresh_token'); } // Validate refresh token From e23570535f6593ec7cb78aa0f8b6ce5e2cf971c5 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 24 Mar 2016 15:27:55 +0000 Subject: [PATCH 349/444] Added API example --- examples/public/api.php | 75 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 examples/public/api.php diff --git a/examples/public/api.php b/examples/public/api.php new file mode 100644 index 00000000..56b9c3fa --- /dev/null +++ b/examples/public/api.php @@ -0,0 +1,75 @@ + [ + 'displayErrorDetails' => true, + ], + Server::class => function () { + // Setup the authorization server + $server = new Server( + new ClientRepository(), + new AccessTokenRepository(), + new ScopeRepository(), + 'file://' . __DIR__ . '/../private.key', + 'file://' . __DIR__ . '/../public.key' + ); + + return $server; + }, +]); + +$app->add( + new \League\OAuth2\Server\Middleware\ResourceServerMiddleware( + $app->getContainer()->get(Server::class) + ) +); + +$app->get('/users', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { + + $users = [ + [ + 'id' => 123, + 'name' => 'Alex', + 'email' => 'alex@thephpleague.com', + ], + [ + 'id' => 124, + 'name' => 'Frank', + 'email' => 'frank@thephpleague.com', + ], + [ + 'id' => 125, + 'name' => 'Phil', + 'email' => 'phil@thephpleague.com', + ], + ]; + + if (in_array('basic', $request->getAttribute('oauth_scopes')) === false) { + for ($i = 0; $i < count($users); $i++) { + unset($users[$i]['name']); + } + } + + if (in_array('email', $request->getAttribute('oauth_scopes')) === false) { + for ($i = 0; $i < count($users); $i++) { + unset($users[$i]['email']); + } + } + + $response->getBody()->write(json_encode($users)); + + return $response->withStatus(200); +}); + +$app->run(); From 1041a39d086dcfc2702e95681a65d51f1f2d56f7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 24 Mar 2016 11:28:05 -0400 Subject: [PATCH 350/444] Applied fixes from StyleCI --- examples/public/api.php | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/public/api.php b/examples/public/api.php index 56b9c3fa..3c446abb 100644 --- a/examples/public/api.php +++ b/examples/public/api.php @@ -7,7 +7,6 @@ use OAuth2ServerExamples\Repositories\ScopeRepository; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Slim\App; -use Zend\Diactoros\Stream; include __DIR__ . '/../vendor/autoload.php'; From fbf4388b0148c9ea7d7039246b0daf0e4fbaaa32 Mon Sep 17 00:00:00 2001 From: Frederik Bosch Date: Thu, 24 Mar 2016 17:22:18 +0100 Subject: [PATCH 351/444] prevent double persist of token when doing refresh grant --- src/Grant/RefreshTokenGrant.php | 2 -- tests/Grant/RefreshTokenGrantTest.php | 8 ++++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 10ebcad5..734ebb07 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -74,8 +74,6 @@ class RefreshTokenGrant extends AbstractGrant // 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); // Inject tokens into response $responseType->setAccessToken($accessToken); diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index 0250855b..719b28c3 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -48,10 +48,14 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity); $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + $accessTokenRepositoryMock + ->expects($this->once()) + ->method('persistNewAccessToken')->willReturnSelf(); $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); - $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + $refreshTokenRepositoryMock + ->expects($this->once()) + ->method('persistNewRefreshToken')->willReturnSelf(); $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); From 5b977b14958810280b82ac8b7abb10a3ba789375 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 24 Mar 2016 19:34:26 +0000 Subject: [PATCH 352/444] Updated changelog from master --- CHANGELOG.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37bad0f4..a3e4ccef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,36 @@ # Changelog +## 4.1.5 (released 2016-01-04) + +* Enable Symfony 3.0 support (#412) + +## 4.1.4 (released 2015-11-13) + +* Fix for determining access token in header (Issue #328) +* Refresh tokens are now returned for MAC responses (Issue #356) +* Added integration list to readme (Issue #341) +* Expose parameter passed to exceptions (Issue #345) +* Removed duplicate routing setup code (Issue #346) +* Docs fix (Issues #347, #360, #380) +* Examples fix (Issues #348, #358) +* Fix typo in docblock (Issue #352) +* Improved timeouts for MAC tokens (Issue #364) +* `hash_hmac()` should output raw binary data, not hexits (Issue #370) +* Improved regex for matching all Base64 characters (Issue #371) +* Fix incorrect signature parameter (Issue #372) +* AuthCodeGrant and RefreshTokenGrant don't require client_secret (Issue #377) +* Added priority argument to event listener (Issue #388) + +## 4.1.3 (released 2015-03-22) + +* Docblock, namespace and inconsistency fixes (Issue #303) +* Docblock type fix (Issue #310) +* Example bug fix (Issue #300) +* Updated league/event to ~2.1 (Issue #311) +* Fixed missing session scope (Issue #319) +* Updated interface docs (Issue #323) +* `.travis.yml` updates + ## 4.1.2 (released 2015-01-01) * Remove side-effects in hash_equals() implementation (Issue #290) @@ -128,7 +159,7 @@ * Included a PDO driver which implements the storage interfaces so the library is more "get up and go" * Further normalised the database structure so all sessions no longer contain infomation related to authorization grant (which may or may not be enabled) * A session can have multiple associated access tokens -* Induvidual grants can have custom expire times for access tokens +* Individual grants can have custom expire times for access tokens * Authorization codes now have a TTL of 10 minutes by default (can be manually set) * Refresh tokens now have a TTL of one week by default (can be manually set) * The client credentials grant will no longer gives out refresh tokens as per the specification From 95335953947bac33f1a725d65d1b81d0401afb2a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 24 Mar 2016 19:37:07 +0000 Subject: [PATCH 353/444] Added 5.0.0-RC1 release notes --- CHANGELOG.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3e4ccef..bb4cb1c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # Changelog +## 5.0.0-RC1 (release 2016-03-24) + +Version 5 is a complete code rewrite. + +* JWT support +* PSR-7 support +* Improved exception errors +* Replace all occurrences of the term "Storage" with "Repository" +* Simplify repositories +* Entities conform to interfaces and use traits +* Auth code grant updated + * Allow support for public clients + * Add support for #439 +* Client credentials grant updated +* Password grant updated + * Allow support for public clients +* Refresh token grant updated +* Implement Implicit grant +* Bearer token output type +* Remove MAC token output type +* Authorization server rewrite +* Resource server class moved to PSR-7 middleware +* Tests +* Much much better documentation + ## 4.1.5 (released 2016-01-04) * Enable Symfony 3.0 support (#412) From b1ce1f872be4243366a794c5da120991843ed1c2 Mon Sep 17 00:00:00 2001 From: Frederik Bosch Date: Fri, 25 Mar 2016 17:11:13 +0100 Subject: [PATCH 354/444] client identifier passed where user identifier is expected --- src/Grant/ClientCredentialsGrant.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 41a47f6f..21673f78 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -34,7 +34,7 @@ class ClientCredentialsGrant extends AbstractGrant $scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client); // Issue and persist access token - $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $client->getIdentifier(), $scopes); + $accessToken = $this->issueAccessToken($accessTokenTTL, $client, null, $scopes); // Inject access token into response type $responseType->setAccessToken($accessToken); From e513b4211705f53d42a8979afedce399d0241928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Mon, 28 Mar 2016 12:10:51 +0200 Subject: [PATCH 355/444] remove access token repository from response types --- src/Grant/AuthCodeGrant.php | 6 ++--- src/Grant/ImplicitGrant.php | 6 ++--- src/ResponseTypes/AbstractResponseType.php | 14 ---------- .../ResponseTypes/BearerResponseTypeTest.php | 26 +++++++++---------- 4 files changed, 18 insertions(+), 34 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 251c782d..93e7eb51 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -145,7 +145,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant ), ]); - $htmlResponse = new HtmlResponse($this->accessTokenRepository); + $htmlResponse = new HtmlResponse(); $htmlResponse->setStatusCode(403); $htmlResponse->setHtml($html); @@ -163,7 +163,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant ), ]); - $htmlResponse = new HtmlResponse($this->accessTokenRepository); + $htmlResponse = new HtmlResponse(); $htmlResponse->setStatusCode(200); $htmlResponse->setHtml($html); $htmlResponse->setHeader('set-cookie', sprintf( @@ -215,7 +215,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant ) ); - $response = new RedirectResponse($this->accessTokenRepository); + $response = new RedirectResponse(); $response->setRedirectUri( $this->makeRedirectUri( $redirectUri, diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 11950a78..e274b186 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -141,7 +141,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant ), ]); - $htmlResponse = new HtmlResponse($this->accessTokenRepository); + $htmlResponse = new HtmlResponse(); $htmlResponse->setStatusCode(403); $htmlResponse->setHtml($html); @@ -159,7 +159,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant ), ]); - $htmlResponse = new HtmlResponse($this->accessTokenRepository); + $htmlResponse = new HtmlResponse(); $htmlResponse->setStatusCode(200); $htmlResponse->setHtml($html); $htmlResponse->setHeader('set-cookie', sprintf( @@ -201,7 +201,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant $redirectPayload['token_type'] = 'bearer'; $redirectPayload['expires_in'] = time() - $accessToken->getExpiryDateTime()->getTimestamp(); - $response = new RedirectResponse($this->accessTokenRepository); + $response = new RedirectResponse(); $response->setRedirectUri( $this->makeRedirectUri( $redirectUri, diff --git a/src/ResponseTypes/AbstractResponseType.php b/src/ResponseTypes/AbstractResponseType.php index e693d85b..c42e1d87 100644 --- a/src/ResponseTypes/AbstractResponseType.php +++ b/src/ResponseTypes/AbstractResponseType.php @@ -13,7 +13,6 @@ namespace League\OAuth2\Server\ResponseTypes; use League\OAuth2\Server\CryptTrait; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; -use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; abstract class AbstractResponseType implements ResponseTypeInterface { @@ -29,19 +28,6 @@ abstract class AbstractResponseType implements ResponseTypeInterface */ protected $refreshToken; - /** - * @var \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface - */ - protected $accessTokenRepository; - - /** - * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository - */ - public function __construct(AccessTokenRepositoryInterface $accessTokenRepository) - { - $this->accessTokenRepository = $accessTokenRepository; - } - /** * {@inheritdoc} */ diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index a8b62f0e..df0639a1 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -18,9 +18,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase { public function testGenerateHttpResponse() { - $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - - $responseType = new BearerTokenResponse($accessTokenRepositoryMock); + $responseType = new BearerTokenResponse(); $responseType->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $responseType->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); @@ -62,10 +60,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase public function testDetermineAccessTokenInHeaderValidToken() { - $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - $accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(false); - - $responseType = new BearerTokenResponse($accessTokenRepositoryMock); + $responseType = new BearerTokenResponse(); $responseType->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $responseType->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); @@ -89,6 +84,9 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $response = $responseType->generateHttpResponse(new Response()); $json = json_decode((string) $response->getBody()); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(false); + $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); $authorizationValidator->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $authorizationValidator->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); @@ -152,10 +150,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase public function testDetermineAccessTokenInHeaderRevokedToken() { - $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - $accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(true); - - $responseType = new BearerTokenResponse($accessTokenRepositoryMock); + $responseType = new BearerTokenResponse(); $responseType->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $responseType->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); @@ -179,6 +174,9 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $response = $responseType->generateHttpResponse(new Response()); $json = json_decode((string) $response->getBody()); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(true); + $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); $authorizationValidator->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $authorizationValidator->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); @@ -198,12 +196,12 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase public function testDetermineAccessTokenInHeaderInvalidToken() { - $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - - $responseType = new BearerTokenResponse($accessTokenRepositoryMock); + $responseType = new BearerTokenResponse(); $responseType->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $responseType->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); $authorizationValidator->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); $authorizationValidator->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); From 197657f2b9dcc5a5591071b5ff7ebd9dfae5e2c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Mon, 28 Mar 2016 16:42:34 +0200 Subject: [PATCH 356/444] handle RSA key passphrase --- .../BearerTokenValidator.php | 2 +- src/CryptKey.php | 62 ++++++++++++++++++ src/CryptTrait.php | 44 ++++++------- src/Entities/AccessTokenEntity.php | 7 +- .../Interfaces/AccessTokenEntityInterface.php | 6 +- src/Grant/GrantTypeInterface.php | 9 +-- src/Grant/ImplicitGrant.php | 2 +- src/ResponseTypes/BearerTokenResponse.php | 2 +- src/Server.php | 49 ++++++++------ tests/CryptTraitTest.php | 5 +- tests/Grant/AbstractGrantTest.php | 5 +- tests/Grant/AuthCodeGrantTest.php | 65 ++++++++++--------- tests/Grant/ImplicitGrantTest.php | 33 +++++----- tests/Grant/RefreshTokenGrantTest.php | 33 +++++----- .../ResourceServerMiddlewareTest.php | 3 +- .../ResponseTypes/BearerResponseTypeTest.php | 37 ++++++----- tests/Stubs/CryptTraitStub.php | 5 +- 17 files changed, 223 insertions(+), 146 deletions(-) create mode 100644 src/CryptKey.php diff --git a/src/AuthorizationValidators/BearerTokenValidator.php b/src/AuthorizationValidators/BearerTokenValidator.php index 5dab2203..3c550e19 100644 --- a/src/AuthorizationValidators/BearerTokenValidator.php +++ b/src/AuthorizationValidators/BearerTokenValidator.php @@ -43,7 +43,7 @@ class BearerTokenValidator implements AuthorizationValidatorInterface try { // Attempt to parse and validate the JWT $token = (new Parser())->parse($jwt); - if ($token->verify(new Sha256(), $this->publicKeyPath) === false) { + if ($token->verify(new Sha256(), $this->publicKey->getKeyPath()) === false) { throw OAuthServerException::accessDenied('Access token could not be verified'); } diff --git a/src/CryptKey.php b/src/CryptKey.php new file mode 100644 index 00000000..4ea05264 --- /dev/null +++ b/src/CryptKey.php @@ -0,0 +1,62 @@ + + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ +namespace League\OAuth2\Server; + +class CryptKey +{ + /** + * @var string + */ + protected $keyPath; + + /** + * @var string + */ + protected $passPhrase; + + /** + * @param string $keyPath + * @param null|string $passPhrase + */ + public function __construct($keyPath, $passPhrase = null) + { + if (strpos($keyPath, 'file://') !== 0) { + $keyPath = 'file://' . $keyPath; + } + + if (!file_exists($keyPath) || !is_readable($keyPath)) { + throw new \LogicException(sprintf('Key path "%s" does not exist or is not readable', $keyPath)); + } + + $this->keyPath = $keyPath; + $this->passPhrase = $passPhrase; + } + + /** + * Retrieve key path. + * + * @return string + */ + public function getKeyPath() + { + return $this->keyPath; + } + + /** + * Retrieve key pass phrase. + * + * @return null|string + */ + public function getPassPhrase() + { + return $this->passPhrase; + } +} diff --git a/src/CryptTrait.php b/src/CryptTrait.php index 3c648b79..1075ea12 100644 --- a/src/CryptTrait.php +++ b/src/CryptTrait.php @@ -13,41 +13,33 @@ namespace League\OAuth2\Server; trait CryptTrait { /** - * @var string + * @var \League\OAuth2\Server\CryptKey */ - protected $privateKeyPath; + protected $privateKey; /** - * @var string + * @var \League\OAuth2\Server\CryptKey */ - protected $publicKeyPath; + protected $publicKey; /** * Set path to private key. * - * @param string $privateKeyPath + * @param \League\OAuth2\Server\CryptKey $privateKey */ - public function setPrivateKeyPath($privateKeyPath) + public function setPrivateKey(CryptKey $privateKey) { - if (strpos($privateKeyPath, 'file://') !== 0) { - $privateKeyPath = 'file://' . $privateKeyPath; - } - - $this->privateKeyPath = $privateKeyPath; + $this->privateKey = $privateKey; } /** * Set path to public key. * - * @param string $publicKeyPath + * @param \League\OAuth2\Server\CryptKey $publicKey */ - public function setPublicKeyPath($publicKeyPath) + public function setPublicKey(CryptKey $publicKey) { - if (strpos($publicKeyPath, 'file://') !== 0) { - $publicKeyPath = 'file://' . $publicKeyPath; - } - - $this->publicKeyPath = $publicKeyPath; + $this->publicKey = $publicKey; } /** @@ -59,10 +51,12 @@ trait CryptTrait */ protected function encrypt($unencryptedData) { - $privateKey = openssl_pkey_get_private($this->privateKeyPath); + $privateKey = openssl_pkey_get_private($this->privateKey->getKeyPath(), $this->privateKey->getPassPhrase()); $privateKeyDetails = @openssl_pkey_get_details($privateKey); if ($privateKeyDetails === null) { - throw new \LogicException(sprintf('Could not get details of private key: %s', $this->privateKeyPath)); + throw new \LogicException( + sprintf('Could not get details of private key: %s', $this->privateKey->getKeyPath()) + ); } $chunkSize = ceil($privateKeyDetails['bits'] / 8) - 11; @@ -78,7 +72,7 @@ trait CryptTrait } $output .= $encrypted; } - openssl_free_key($privateKey); + openssl_pkey_free($privateKey); return base64_encode($output); } @@ -94,10 +88,12 @@ trait CryptTrait */ protected function decrypt($encryptedData) { - $publicKey = openssl_pkey_get_public($this->publicKeyPath); + $publicKey = openssl_pkey_get_public($this->publicKey->getKeyPath()); $publicKeyDetails = @openssl_pkey_get_details($publicKey); if ($publicKeyDetails === null) { - throw new \LogicException(sprintf('Could not get details of public key: %s', $this->publicKeyPath)); + throw new \LogicException( + sprintf('Could not get details of public key: %s', $this->publicKey->getKeyPath()) + ); } $chunkSize = ceil($publicKeyDetails['bits'] / 8); @@ -115,7 +111,7 @@ trait CryptTrait } $output .= $decrypted; } - openssl_free_key($publicKey); + openssl_pkey_free($publicKey); return $output; } diff --git a/src/Entities/AccessTokenEntity.php b/src/Entities/AccessTokenEntity.php index 5b4b34a1..34ae167e 100644 --- a/src/Entities/AccessTokenEntity.php +++ b/src/Entities/AccessTokenEntity.php @@ -5,6 +5,7 @@ namespace League\OAuth2\Server\Entities; use Lcobucci\JWT\Builder; use Lcobucci\JWT\Signer\Key; use Lcobucci\JWT\Signer\Rsa\Sha256; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Traits\EntityTrait; use League\OAuth2\Server\Entities\Traits\TokenEntityTrait; @@ -16,11 +17,11 @@ class AccessTokenEntity implements AccessTokenEntityInterface /** * Generate a JWT from the access token * - * @param string $privateKeyPath + * @param \League\OAuth2\Server\CryptKey $privateKey * * @return string */ - public function convertToJWT($privateKeyPath) + public function convertToJWT(CryptKey $privateKey) { return (new Builder()) ->setAudience($this->getClient()->getIdentifier()) @@ -30,7 +31,7 @@ class AccessTokenEntity implements AccessTokenEntityInterface ->setExpiration($this->getExpiryDateTime()->getTimestamp()) ->setSubject($this->getUserIdentifier()) ->set('scopes', $this->getScopes()) - ->sign(new Sha256(), new Key($privateKeyPath)) + ->sign(new Sha256(), new Key($privateKey->getKeyPath(), $privateKey->getPassPhrase())) ->getToken(); } } diff --git a/src/Entities/Interfaces/AccessTokenEntityInterface.php b/src/Entities/Interfaces/AccessTokenEntityInterface.php index 86ad1107..2b4c38a8 100644 --- a/src/Entities/Interfaces/AccessTokenEntityInterface.php +++ b/src/Entities/Interfaces/AccessTokenEntityInterface.php @@ -2,14 +2,16 @@ namespace League\OAuth2\Server\Entities\Interfaces; +use League\OAuth2\Server\CryptKey; + interface AccessTokenEntityInterface extends TokenInterface { /** * Generate a JWT from the access token * - * @param string $privateKeyPath + * @param \League\OAuth2\Server\CryptKey $privateKey * * @return string */ - public function convertToJWT($privateKeyPath); + public function convertToJWT(CryptKey $privateKey); } diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index cb60bf90..0e4ce62d 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -11,6 +11,7 @@ namespace League\OAuth2\Server\Grant; use League\Event\EmitterAwareInterface; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; @@ -89,14 +90,14 @@ interface GrantTypeInterface extends EmitterAwareInterface /** * Set the path to the private key. * - * @param string $privateKeyPath + * @param \League\OAuth2\Server\CryptKey $privateKey */ - public function setPrivateKeyPath($privateKeyPath); + public function setPrivateKey(CryptKey $privateKey); /** * Set the path to the public key. * - * @param string $publicKeyPath + * @param \League\OAuth2\Server\CryptKey $publicKey */ - public function setPublicKeyPath($publicKeyPath); + public function setPublicKey(CryptKey $publicKey); } diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 11950a78..2fe4a455 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -197,7 +197,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant $scopes ); - $redirectPayload['access_token'] = (string) $accessToken->convertToJWT($this->privateKeyPath); + $redirectPayload['access_token'] = (string) $accessToken->convertToJWT($this->privateKey); $redirectPayload['token_type'] = 'bearer'; $redirectPayload['expires_in'] = time() - $accessToken->getExpiryDateTime()->getTimestamp(); diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index 17675b88..7a77c699 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -22,7 +22,7 @@ class BearerTokenResponse extends AbstractResponseType { $expireDateTime = $this->accessToken->getExpiryDateTime()->getTimestamp(); - $jwtAccessToken = $this->accessToken->convertToJWT($this->privateKeyPath); + $jwtAccessToken = $this->accessToken->convertToJWT($this->privateKey); $responseParams = [ 'token_type' => 'Bearer', diff --git a/src/Server.php b/src/Server.php index e77a344b..e5573026 100644 --- a/src/Server.php +++ b/src/Server.php @@ -32,20 +32,20 @@ class Server implements EmitterAwareInterface protected $grantTypeAccessTokenTTL = []; /** - * @var string + * @var \League\OAuth2\Server\CryptKey */ - protected $privateKeyPath; + protected $privateKey; + + /** + * @var \League\OAuth2\Server\CryptKey + */ + protected $publicKey; /** * @var ResponseTypeInterface */ protected $responseType; - /** - * @var string - */ - private $publicKeyPath; - /** * @var \League\OAuth2\Server\Repositories\ClientRepositoryInterface */ @@ -72,8 +72,8 @@ class Server implements EmitterAwareInterface * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository - * @param string $privateKeyPath - * @param string $publicKeyPath + * @param \League\OAuth2\Server\CryptKey|string $privateKey + * @param \League\OAuth2\Server\CryptKey|string $publicKey * @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType * @param null|\League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface $authorizationValidator */ @@ -81,16 +81,25 @@ class Server implements EmitterAwareInterface ClientRepositoryInterface $clientRepository, AccessTokenRepositoryInterface $accessTokenRepository, ScopeRepositoryInterface $scopeRepository, - $privateKeyPath, - $publicKeyPath, + $privateKey, + $publicKey, ResponseTypeInterface $responseType = null, AuthorizationValidatorInterface $authorizationValidator = null ) { $this->clientRepository = $clientRepository; $this->accessTokenRepository = $accessTokenRepository; $this->scopeRepository = $scopeRepository; - $this->privateKeyPath = $privateKeyPath; - $this->publicKeyPath = $publicKeyPath; + + if (!$privateKey instanceof CryptKey) { + $privateKey = new CryptKey($privateKey); + } + $this->privateKey = $privateKey; + + if (!$publicKey instanceof CryptKey) { + $publicKey = new CryptKey($publicKey); + } + $this->publicKey = $publicKey; + $this->responseType = $responseType; $this->authorizationValidator = $authorizationValidator; } @@ -106,8 +115,8 @@ class Server implements EmitterAwareInterface $grantType->setAccessTokenRepository($this->accessTokenRepository); $grantType->setClientRepository($this->clientRepository); $grantType->setScopeRepository($this->scopeRepository); - $grantType->setPrivateKeyPath($this->privateKeyPath); - $grantType->setPublicKeyPath($this->publicKeyPath); + $grantType->setPrivateKey($this->privateKey); + $grantType->setPublicKey($this->publicKey); $grantType->setEmitter($this->getEmitter()); $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; @@ -118,8 +127,8 @@ class Server implements EmitterAwareInterface /** * Return an access token response. * - * @param \Psr\Http\Message\ServerRequestInterface|null $request - * @param \Psr\Http\Message\ResponseInterface|null $response + * @param \Psr\Http\Message\ServerRequestInterface $request + * @param \Psr\Http\Message\ResponseInterface $response * * @throws \League\OAuth2\Server\Exception\OAuthServerException * @@ -171,8 +180,7 @@ class Server implements EmitterAwareInterface $this->responseType = new BearerTokenResponse($this->accessTokenRepository); } - $this->responseType->setPublicKeyPath($this->publicKeyPath); - $this->responseType->setPrivateKeyPath($this->privateKeyPath); + $this->responseType->setPrivateKey($this->privateKey); return $this->responseType; } @@ -186,8 +194,7 @@ class Server implements EmitterAwareInterface $this->authorizationValidator = new BearerTokenValidator($this->accessTokenRepository); } - $this->authorizationValidator->setPublicKeyPath($this->publicKeyPath); - $this->authorizationValidator->setPrivateKeyPath($this->privateKeyPath); + $this->authorizationValidator->setPublicKey($this->publicKey); return $this->authorizationValidator; } diff --git a/tests/CryptTraitTest.php b/tests/CryptTraitTest.php index fad2fdcf..364d712f 100644 --- a/tests/CryptTraitTest.php +++ b/tests/CryptTraitTest.php @@ -2,6 +2,7 @@ namespace LeagueTests\Utils; +use League\OAuth2\Server\CryptKey; use LeagueTests\Stubs\CryptTraitStub; class CryptTraitTest extends \PHPUnit_Framework_TestCase @@ -31,7 +32,7 @@ class CryptTraitTest extends \PHPUnit_Framework_TestCase */ public function testBadPrivateKey() { - $this->cryptStub->setPrivateKeyPath(__DIR__ . '/Stubs/public.key'); + $this->cryptStub->setPrivateKey(new CryptKey(__DIR__ . '/Stubs/public.key')); $this->cryptStub->doEncrypt(''); } @@ -40,7 +41,7 @@ class CryptTraitTest extends \PHPUnit_Framework_TestCase */ public function testBadPublicKey() { - $this->cryptStub->setPublicKeyPath(__DIR__ . '/Stubs/private.key'); + $this->cryptStub->setPublicKey(new CryptKey(__DIR__ . '/Stubs/private.key')); $this->cryptStub->doDecrypt(''); } } diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 1161ebc4..595e48d6 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -3,6 +3,7 @@ namespace LeagueTests\Grant; use League\Event\Emitter; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; @@ -23,8 +24,8 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase { /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); - $grantMock->setPrivateKeyPath('./private.key'); - $grantMock->setPublicKeyPath('./public.key'); + $grantMock->setPrivateKey(new CryptKey(__DIR__ . '/../Stubs/private.key')); + $grantMock->setPublicKey(new CryptKey(__DIR__ . '/../Stubs/public.key')); $grantMock->setEmitter(new Emitter()); } diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 1dfb6974..6fe74782 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -2,6 +2,7 @@ namespace LeagueTests\Grant; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; @@ -99,8 +100,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -161,8 +162,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -214,8 +215,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -260,8 +261,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -312,8 +313,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -370,8 +371,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -426,8 +427,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -483,8 +484,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -542,8 +543,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -607,8 +608,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setScopeRepository($scopeRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [], @@ -665,8 +666,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [], @@ -711,8 +712,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [], @@ -762,8 +763,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [], @@ -831,8 +832,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [], @@ -897,8 +898,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [], @@ -963,8 +964,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [], diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 06525b9c..100b97aa 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -2,6 +2,7 @@ namespace LeagueTests\Grant; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ImplicitGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -77,8 +78,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -115,8 +116,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase public function testRespondToAuthorizationRequestMissingClientId() { $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -152,8 +153,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -199,8 +200,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -252,8 +253,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -299,8 +300,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -350,8 +351,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ @@ -401,8 +402,8 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( [ diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index 719b28c3..d48a5af2 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -2,6 +2,7 @@ namespace LeagueTests\Grant; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Grant\RefreshTokenGrant; @@ -61,8 +62,8 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $oldRefreshToken = $this->cryptStub->doEncrypt( json_encode( @@ -116,8 +117,8 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $oldRefreshToken = $this->cryptStub->doEncrypt( json_encode( @@ -176,8 +177,8 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $oldRefreshToken = $this->cryptStub->doEncrypt( json_encode( @@ -224,8 +225,8 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $serverRequest = new ServerRequest(); $serverRequest = $serverRequest->withParsedBody( @@ -257,8 +258,8 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $oldRefreshToken = 'foobar'; @@ -297,8 +298,8 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $oldRefreshToken = $this->cryptStub->doEncrypt( json_encode( @@ -344,8 +345,8 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $oldRefreshToken = $this->cryptStub->doEncrypt( json_encode( @@ -392,8 +393,8 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); - $grant->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $oldRefreshToken = $this->cryptStub->doEncrypt( json_encode( diff --git a/tests/Middleware/ResourceServerMiddlewareTest.php b/tests/Middleware/ResourceServerMiddlewareTest.php index 960113db..49c22397 100644 --- a/tests/Middleware/ResourceServerMiddlewareTest.php +++ b/tests/Middleware/ResourceServerMiddlewareTest.php @@ -2,6 +2,7 @@ namespace LeagueTests\Middleware; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Middleware\ResourceServerMiddleware; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -37,7 +38,7 @@ class ResourceServerMiddlewareTest extends \PHPUnit_Framework_TestCase $accessToken->setExpiryDateTime((new \DateTime())->add(new \DateInterval('PT1H'))); $accessToken->setClient($client); - $token = $accessToken->convertToJWT('file://' . __DIR__ . '/../Stubs/private.key'); + $token = $accessToken->convertToJWT(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest(); $request = $request->withHeader('authorization', sprintf('Bearer %s', $token)); diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index a8b62f0e..3fb11168 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -3,6 +3,7 @@ namespace LeagueTests\ResponseTypes; use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; @@ -21,8 +22,8 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $responseType = new BearerTokenResponse($accessTokenRepositoryMock); - $responseType->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $responseType->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $client = new ClientEntity(); $client->setIdentifier('clientName'); @@ -66,8 +67,8 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(false); $responseType = new BearerTokenResponse($accessTokenRepositoryMock); - $responseType->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $responseType->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $client = new ClientEntity(); $client->setIdentifier('clientName'); @@ -90,8 +91,8 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $json = json_decode((string) $response->getBody()); $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); - $authorizationValidator->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $authorizationValidator->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $authorizationValidator->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $request = new ServerRequest(); $request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token)); @@ -110,8 +111,8 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(false); $responseType = new BearerTokenResponse($accessTokenRepositoryMock); - $responseType->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $responseType->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $client = new ClientEntity(); $client->setIdentifier('clientName'); @@ -134,8 +135,8 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $json = json_decode((string) $response->getBody()); $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); - $authorizationValidator->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $authorizationValidator->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $authorizationValidator->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $request = new ServerRequest(); $request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token . 'foo')); @@ -156,8 +157,8 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(true); $responseType = new BearerTokenResponse($accessTokenRepositoryMock); - $responseType->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $responseType->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $client = new ClientEntity(); $client->setIdentifier('clientName'); @@ -180,8 +181,8 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $json = json_decode((string) $response->getBody()); $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); - $authorizationValidator->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $authorizationValidator->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $authorizationValidator->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $request = new ServerRequest(); $request = $request->withHeader('authorization', sprintf('Bearer %s', $json->access_token)); @@ -201,12 +202,12 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $responseType = new BearerTokenResponse($accessTokenRepositoryMock); - $responseType->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $responseType->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); - $authorizationValidator->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $authorizationValidator->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $authorizationValidator->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $request = new ServerRequest(); $request = $request->withHeader('authorization', 'Bearer blah'); diff --git a/tests/Stubs/CryptTraitStub.php b/tests/Stubs/CryptTraitStub.php index 583a851c..2414c199 100644 --- a/tests/Stubs/CryptTraitStub.php +++ b/tests/Stubs/CryptTraitStub.php @@ -2,6 +2,7 @@ namespace LeagueTests\Stubs; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\CryptTrait; class CryptTraitStub @@ -10,8 +11,8 @@ class CryptTraitStub public function __construct() { - $this->setPrivateKeyPath('file://' . __DIR__ . '/private.key'); - $this->setPublicKeyPath('file://' . __DIR__ . '/public.key'); + $this->setPrivateKey(new CryptKey('file://' . __DIR__ . '/private.key')); + $this->setPublicKey(new CryptKey('file://' . __DIR__ . '/public.key')); } public function doEncrypt($unencryptedData) From a38b7f97f9f389bff143cf2adff9cc086610d375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Mon, 28 Mar 2016 17:10:41 +0200 Subject: [PATCH 357/444] include keys in Server tests --- .../AuthenticationServerMiddlewareTest.php | 8 ++++---- .../Middleware/ResourceServerMiddlewareTest.php | 4 ++-- tests/ServerTest.php | 16 ++++++++-------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/Middleware/AuthenticationServerMiddlewareTest.php b/tests/Middleware/AuthenticationServerMiddlewareTest.php index 4acd5c89..bfed2651 100644 --- a/tests/Middleware/AuthenticationServerMiddlewareTest.php +++ b/tests/Middleware/AuthenticationServerMiddlewareTest.php @@ -27,8 +27,8 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase $clientRepository, $this->getMock(AccessTokenRepositoryInterface::class), $scopeRepositoryMock, - '', - '', + 'file://' . __DIR__ . '/../Stubs/private.key', + 'file://' . __DIR__ . '/../Stubs/public.key', new StubResponseType() ); @@ -60,8 +60,8 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase $clientRepository, $this->getMock(AccessTokenRepositoryInterface::class), $this->getMock(ScopeRepositoryInterface::class), - '', - '', + 'file://' . __DIR__ . '/../Stubs/private.key', + 'file://' . __DIR__ . '/../Stubs/public.key', new StubResponseType() ); diff --git a/tests/Middleware/ResourceServerMiddlewareTest.php b/tests/Middleware/ResourceServerMiddlewareTest.php index 49c22397..bb3f7ab7 100644 --- a/tests/Middleware/ResourceServerMiddlewareTest.php +++ b/tests/Middleware/ResourceServerMiddlewareTest.php @@ -65,8 +65,8 @@ class ResourceServerMiddlewareTest extends \PHPUnit_Framework_TestCase $clientRepository, $this->getMock(AccessTokenRepositoryInterface::class), $this->getMock(ScopeRepositoryInterface::class), - '', - '', + 'file://' . __DIR__ . '/../Stubs/private.key', + 'file://' . __DIR__ . '/../Stubs/public.key', new StubResponseType() ); diff --git a/tests/ServerTest.php b/tests/ServerTest.php index f61818cf..d3c693d6 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -28,8 +28,8 @@ class ServerTest extends \PHPUnit_Framework_TestCase $this->getMock(ClientRepositoryInterface::class), $this->getMock(AccessTokenRepositoryInterface::class), $this->getMock(ScopeRepositoryInterface::class), - '', - '', + 'file://' . __DIR__ . '/Stubs/private.key', + 'file://' . __DIR__ . '/Stubs/public.key', new StubResponseType() ); @@ -55,8 +55,8 @@ class ServerTest extends \PHPUnit_Framework_TestCase $clientRepository, $this->getMock(AccessTokenRepositoryInterface::class), $scopeRepositoryMock, - '', - '', + 'file://' . __DIR__ . '/Stubs/private.key', + 'file://' . __DIR__ . '/Stubs/public.key', new StubResponseType() ); @@ -125,8 +125,8 @@ class ServerTest extends \PHPUnit_Framework_TestCase $clientRepository, $this->getMock(AccessTokenRepositoryInterface::class), $this->getMock(ScopeRepositoryInterface::class), - '', - '' + 'file://' . __DIR__ . '/Stubs/private.key', + 'file://' . __DIR__ . '/Stubs/public.key' ); $abstractGrantReflection = new \ReflectionClass($server); @@ -144,8 +144,8 @@ class ServerTest extends \PHPUnit_Framework_TestCase $clientRepository, $this->getMock(AccessTokenRepositoryInterface::class), $this->getMock(ScopeRepositoryInterface::class), - '', - '' + 'file://' . __DIR__ . '/Stubs/private.key', + 'file://' . __DIR__ . '/Stubs/public.key' ); try { From 4d2ccac8ed7b443e14aef38b7a8d72d96cc2a0cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Tue, 29 Mar 2016 09:31:34 +0200 Subject: [PATCH 358/444] remove unused mac token interface --- src/Repositories/MacTokenInterface.php | 36 -------------------------- 1 file changed, 36 deletions(-) delete mode 100644 src/Repositories/MacTokenInterface.php diff --git a/src/Repositories/MacTokenInterface.php b/src/Repositories/MacTokenInterface.php deleted file mode 100644 index 00e35a4c..00000000 --- a/src/Repositories/MacTokenInterface.php +++ /dev/null @@ -1,36 +0,0 @@ - - * @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. - */ -interface MacTokenInterface extends RepositoryInterface -{ - /** - * Create a MAC key linked to an access token. - * - * @param string $macKey - * @param string $accessToken - */ - public function persistMacTokenEntity($macKey, $accessToken); - - /** - * Get a MAC key by access token. - * - * @param string $accessToken - * - * @return string - */ - public function getMacKeyByAccessTokenString($accessToken); -} From 8f69f4f9a9232523f18325cb65287a7f61f22614 Mon Sep 17 00:00:00 2001 From: Adam McCann Date: Thu, 31 Mar 2016 18:50:36 +0100 Subject: [PATCH 359/444] Access denied on token expiry (or value before nbf/not before) - issue #506 --- src/AuthorizationValidators/BearerTokenValidator.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/AuthorizationValidators/BearerTokenValidator.php b/src/AuthorizationValidators/BearerTokenValidator.php index 5dab2203..5a65ab0b 100644 --- a/src/AuthorizationValidators/BearerTokenValidator.php +++ b/src/AuthorizationValidators/BearerTokenValidator.php @@ -3,6 +3,7 @@ namespace League\OAuth2\Server\AuthorizationValidators; use Lcobucci\JWT\Parser; +use Lcobucci\JWT\ValidationData; use Lcobucci\JWT\Signer\Rsa\Sha256; use League\OAuth2\Server\CryptTrait; use League\OAuth2\Server\Exception\OAuthServerException; @@ -47,6 +48,14 @@ class BearerTokenValidator implements AuthorizationValidatorInterface throw OAuthServerException::accessDenied('Access token could not be verified'); } + // validate + $data = new ValidationData(); + $data->setCurrentTime(time()); + + if ($token->validate($data) === false) { + throw OAuthServerException::accessDenied('Access token is invalid'); + } + // Check if token has been revoked if ($this->accessTokenRepository->isAccessTokenRevoked($token->getClaim('jti'))) { throw OAuthServerException::accessDenied('Access token has been revoked'); From de8f6ff53900229c2263dac218bca5cd13ac9139 Mon Sep 17 00:00:00 2001 From: Frederik Bosch Date: Fri, 25 Mar 2016 14:09:26 +0100 Subject: [PATCH 360/444] add getNewAccessToken getNewRefreshToken and getNewAuthCode to repositories --- src/Grant/AbstractGrant.php | 13 ++--- .../AbstractAccessTokenRepository.php | 46 ++++++++++++++++ .../AbstractAuthCodeRepository.php | 53 +++++++++++++++++++ .../AbstractRefreshTokenRepository.php | 53 +++++++++++++++++++ .../AccessTokenRepositoryInterface.php | 12 +++++ .../AuthCodeRepositoryInterface.php | 7 +++ .../RefreshTokenRepositoryInterface.php | 7 +++ tests/Grant/AbstractGrantTest.php | 8 +++ tests/Grant/AuthCodeGrantTest.php | 15 +++++- tests/Grant/ClientCredentialsGrantTest.php | 2 + tests/Grant/ImplicitGrantTest.php | 2 + tests/Grant/PasswordGrantTest.php | 4 ++ tests/Grant/RefreshTokenGrantTest.php | 6 +++ .../AuthenticationServerMiddlewareTest.php | 6 ++- tests/ServerTest.php | 12 ++++- 15 files changed, 233 insertions(+), 13 deletions(-) create mode 100644 src/Repositories/AbstractAccessTokenRepository.php create mode 100644 src/Repositories/AbstractAuthCodeRepository.php create mode 100644 src/Repositories/AbstractRefreshTokenRepository.php diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 14a46e35..7b68804e 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -12,12 +12,9 @@ namespace League\OAuth2\Server\Grant; use League\Event\EmitterAwareTrait; use League\OAuth2\Server\CryptTrait; -use League\OAuth2\Server\Entities\AccessTokenEntity; -use League\OAuth2\Server\Entities\AuthCodeEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; -use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; @@ -291,11 +288,11 @@ abstract class AbstractGrant implements GrantTypeInterface $userIdentifier, array $scopes = [] ) { - $accessToken = new AccessTokenEntity(); - $accessToken->setIdentifier($this->generateUniqueIdentifier()); - $accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL)); + $accessToken = $this->accessTokenRepository->getNewToken($client, $scopes, $userIdentifier); $accessToken->setClient($client); $accessToken->setUserIdentifier($userIdentifier); + $accessToken->setIdentifier($this->generateUniqueIdentifier()); + $accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL)); foreach ($scopes as $scope) { $accessToken->addScope($scope); @@ -324,7 +321,7 @@ abstract class AbstractGrant implements GrantTypeInterface $redirectUri, array $scopes = [] ) { - $authCode = new AuthCodeEntity(); + $authCode = $this->authCodeRepository->getNewAuthCode(); $authCode->setIdentifier($this->generateUniqueIdentifier()); $authCode->setExpiryDateTime((new \DateTime())->add($authCodeTTL)); $authCode->setClient($client); @@ -347,7 +344,7 @@ abstract class AbstractGrant implements GrantTypeInterface */ protected function issueRefreshToken(AccessTokenEntityInterface $accessToken) { - $refreshToken = new RefreshTokenEntity(); + $refreshToken = $this->refreshTokenRepository->getNewRefreshToken(); $refreshToken->setIdentifier($this->generateUniqueIdentifier()); $refreshToken->setExpiryDateTime((new \DateTime())->add($this->refreshTokenTTL)); $refreshToken->setAccessToken($accessToken); diff --git a/src/Repositories/AbstractAccessTokenRepository.php b/src/Repositories/AbstractAccessTokenRepository.php new file mode 100644 index 00000000..321abc65 --- /dev/null +++ b/src/Repositories/AbstractAccessTokenRepository.php @@ -0,0 +1,46 @@ + + * @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\AuthCodeEntity; +use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; + +/** + * Auth code storage abstract class. + */ +abstract class AbstractAuthCodeRepository implements AuthCodeRepositoryInterface +{ + /** + * Creates a new AuthCode + * + * @return \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface + */ + public function getNewAuthCode() + { + return new AuthCodeEntity(); + } + + /** + * Persists a new auth code to permanent storage. + * + * @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $authCodeEntity + */ + abstract public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity); + + /** + * Revoke an auth code. + * + * @param string $codeId + */ + abstract public function revokeAuthCode($codeId); + + /** + * Check if the auth code has been revoked. + * + * @param string $codeId + * + * @return bool Return true if this code has been revoked + */ + abstract public function isAuthCodeRevoked($codeId); +} diff --git a/src/Repositories/AbstractRefreshTokenRepository.php b/src/Repositories/AbstractRefreshTokenRepository.php new file mode 100644 index 00000000..ff786f94 --- /dev/null +++ b/src/Repositories/AbstractRefreshTokenRepository.php @@ -0,0 +1,53 @@ + + * @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; +use League\OAuth2\Server\Entities\RefreshTokenEntity; + +/** + * Refresh token abstract class. + */ +abstract class AbstractRefreshTokenRepository implements RefreshTokenRepositoryInterface +{ + /** + * Creates a new refresh token + * + * @return RefreshTokenEntityInterface + */ + public function getNewRefreshToken() + { + return new RefreshTokenEntity(); + } + + /** + * Create a new refresh token_name. + * + * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshTokenEntity + */ + abstract public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity); + + /** + * Revoke the refresh token. + * + * @param string $tokenId + */ + abstract public function revokeRefreshToken($tokenId); + + /** + * Check if the refresh token has been revoked. + * + * @param string $tokenId + * + * @return bool Return true if this token has been revoked + */ + abstract public function isRefreshTokenRevoked($tokenId); +} diff --git a/src/Repositories/AccessTokenRepositoryInterface.php b/src/Repositories/AccessTokenRepositoryInterface.php index d9e054d8..a6d725a2 100644 --- a/src/Repositories/AccessTokenRepositoryInterface.php +++ b/src/Repositories/AccessTokenRepositoryInterface.php @@ -11,12 +11,24 @@ namespace League\OAuth2\Server\Repositories; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; /** * Access token interface. */ interface AccessTokenRepositoryInterface extends RepositoryInterface { + /** + * Create a new access token + * + * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $clientEntity + * @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] $scopes + * @param mixed $userIdentifier + * + * @return AccessTokenEntityInterface + */ + public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null); + /** * Persists a new access token to permanent storage. * diff --git a/src/Repositories/AuthCodeRepositoryInterface.php b/src/Repositories/AuthCodeRepositoryInterface.php index 16c48742..d1da7d44 100644 --- a/src/Repositories/AuthCodeRepositoryInterface.php +++ b/src/Repositories/AuthCodeRepositoryInterface.php @@ -17,6 +17,13 @@ use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; */ interface AuthCodeRepositoryInterface extends RepositoryInterface { + /** + * Creates a new AuthCode + * + * @return \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface + */ + public function getNewAuthCode(); + /** * Persists a new auth code to permanent storage. * diff --git a/src/Repositories/RefreshTokenRepositoryInterface.php b/src/Repositories/RefreshTokenRepositoryInterface.php index d987ab22..e857e2ff 100644 --- a/src/Repositories/RefreshTokenRepositoryInterface.php +++ b/src/Repositories/RefreshTokenRepositoryInterface.php @@ -17,6 +17,13 @@ use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; */ interface RefreshTokenRepositoryInterface extends RepositoryInterface { + /** + * Creates a new refresh token + * + * @return RefreshTokenEntityInterface + */ + public function getNewRefreshToken(); + /** * Create a new refresh token_name. * diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 1161ebc4..ac5c2a0a 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -4,9 +4,11 @@ namespace LeagueTests\Grant; use League\Event\Emitter; use League\OAuth2\Server\Entities\AccessTokenEntity; +use League\OAuth2\Server\Entities\AuthCodeEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Grant\AbstractGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; @@ -227,6 +229,10 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase public function testIssueRefreshToken() { $refreshTokenRepoMock = $this->getMock(RefreshTokenRepositoryInterface::class); + $refreshTokenRepoMock + ->expects($this->once()) + ->method('getNewRefreshToken') + ->willReturn(new RefreshTokenEntity()); /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); @@ -248,6 +254,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase public function testIssueAccessToken() { $accessTokenRepoMock = $this->getMock(AccessTokenRepositoryInterface::class); + $accessTokenRepoMock->method('getNewToken')->willReturn(new AccessTokenEntity()); /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); @@ -272,6 +279,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase public function testIssueAuthCode() { $authCodeRepoMock = $this->getMock(AuthCodeRepositoryInterface::class); + $authCodeRepoMock->expects($this->once())->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 1dfb6974..f56c64e6 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -2,8 +2,11 @@ namespace LeagueTests\Grant; +use League\OAuth2\Server\Entities\AccessTokenEntity; +use League\OAuth2\Server\Entities\AuthCodeEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -90,8 +93,11 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $authCodeRepoMock = $this->getMock(AuthCodeRepositoryInterface::class); + $authCodeRepoMock->expects($this->once())->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); + $grant = new AuthCodeGrant( - $this->getMock(AuthCodeRepositoryInterface::class), + $authCodeRepoMock, $this->getMock(RefreshTokenRepositoryInterface::class), $userRepositoryMock, new \DateInterval('PT10M') @@ -417,8 +423,11 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $authCodeRepoMock = $this->getMock(AuthCodeRepositoryInterface::class); + $authCodeRepoMock->expects($this->once())->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); + $grant = new AuthCodeGrant( - $this->getMock(AuthCodeRepositoryInterface::class), + $authCodeRepoMock, $this->getMock(RefreshTokenRepositoryInterface::class), $userRepositoryMock, new \DateInterval('PT10M') @@ -592,10 +601,12 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity); $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + $refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity()); $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), diff --git a/tests/Grant/ClientCredentialsGrantTest.php b/tests/Grant/ClientCredentialsGrantTest.php index c41528c5..a6b66dcd 100644 --- a/tests/Grant/ClientCredentialsGrantTest.php +++ b/tests/Grant/ClientCredentialsGrantTest.php @@ -2,6 +2,7 @@ namespace LeagueTests\Grant; +use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -27,6 +28,7 @@ class ClientCredentialsGrantTest extends \PHPUnit_Framework_TestCase $clientRepositoryMock->method('getClientEntity')->willReturn($client); $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 06525b9c..58da9213 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -2,6 +2,7 @@ namespace LeagueTests\Grant; +use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ImplicitGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -68,6 +69,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php index 31043d1a..eb72c905 100644 --- a/tests/Grant/PasswordGrantTest.php +++ b/tests/Grant/PasswordGrantTest.php @@ -2,8 +2,10 @@ namespace LeagueTests\Grant; +use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -34,6 +36,7 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase $clientRepositoryMock->method('getClientEntity')->willReturn($client); $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); @@ -42,6 +45,7 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + $refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity()); $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index 719b28c3..acd77a39 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -2,8 +2,10 @@ namespace LeagueTests\Grant; +use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -48,11 +50,13 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity); $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); $accessTokenRepositoryMock ->expects($this->once()) ->method('persistNewAccessToken')->willReturnSelf(); $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity()); $refreshTokenRepositoryMock ->expects($this->once()) ->method('persistNewRefreshToken')->willReturnSelf(); @@ -102,10 +106,12 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $clientRepositoryMock->method('getClientEntity')->willReturn($client); $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + $refreshTokenRepositoryMock->method('getNewRefreshToken')->willReturn(new RefreshTokenEntity()); $scope = new ScopeEntity(); $scope->setIdentifier('foo'); diff --git a/tests/Middleware/AuthenticationServerMiddlewareTest.php b/tests/Middleware/AuthenticationServerMiddlewareTest.php index 4acd5c89..9b259699 100644 --- a/tests/Middleware/AuthenticationServerMiddlewareTest.php +++ b/tests/Middleware/AuthenticationServerMiddlewareTest.php @@ -2,6 +2,7 @@ namespace LeagueTests\Middleware; +use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Middleware\AuthenticationServerMiddleware; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -23,9 +24,12 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $accessRepositoryMock = $this->getMock(AccessTokenRepositoryInterface::class); + $accessRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); + $server = new Server( $clientRepository, - $this->getMock(AccessTokenRepositoryInterface::class), + $accessRepositoryMock, $scopeRepositoryMock, '', '', diff --git a/tests/ServerTest.php b/tests/ServerTest.php index f61818cf..d8367e85 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -2,6 +2,8 @@ namespace LeagueTests; +use League\OAuth2\Server\Entities\AccessTokenEntity; +use League\OAuth2\Server\Entities\AuthCodeEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\ClientCredentialsGrant; @@ -51,9 +53,12 @@ class ServerTest extends \PHPUnit_Framework_TestCase $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); + $accessTokenRepositoryMock = $this->getMock(AccessTokenRepositoryInterface::class); + $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); + $server = new Server( $clientRepository, - $this->getMock(AccessTokenRepositoryInterface::class), + $accessTokenRepositoryMock, $scopeRepositoryMock, '', '', @@ -93,9 +98,12 @@ class ServerTest extends \PHPUnit_Framework_TestCase $userRepository = $this->getMock(UserRepositoryInterface::class); $userRepository->method('getUserEntityByUserCredentials')->willReturn(new UserEntity()); + $authCodeRepoMock = $this->getMock(AuthCodeRepositoryInterface::class); + $authCodeRepoMock->expects($this->once())->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); + $server->enableGrantType( new AuthCodeGrant( - $this->getMock(AuthCodeRepositoryInterface::class), + $authCodeRepoMock, $this->getMock(RefreshTokenRepositoryInterface::class), $userRepository, new \DateInterval('PT1H') From 8274c56fc295d860342c96521d7ac05b5ec44d4e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 13:36:08 +0100 Subject: [PATCH 361/444] Allow multiple client redirect URIs. Fixes #511 --- .../Interfaces/ClientEntityInterface.php | 6 ++-- src/Grant/AbstractGrant.php | 14 ++++++++-- tests/Grant/AbstractGrantTest.php | 28 +++++++++++++++++++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/Entities/Interfaces/ClientEntityInterface.php b/src/Entities/Interfaces/ClientEntityInterface.php index 4ed17162..7fde09d9 100644 --- a/src/Entities/Interfaces/ClientEntityInterface.php +++ b/src/Entities/Interfaces/ClientEntityInterface.php @@ -40,9 +40,11 @@ interface ClientEntityInterface public function setRedirectUri($redirectUri); /** - * Returns the registered redirect URI. + * Returns the registered redirect URI (as a string). * - * @return string + * Alternatively return an indexed array of redirect URIs. + * + * @return string|string[] */ public function getRedirectUri(); } diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 14a46e35..f68913d8 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -173,8 +173,18 @@ abstract class AbstractGrant implements GrantTypeInterface // 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(); + if ($redirectUri !== null) { + if ( + is_string($client->getRedirectUri()) + && (strcmp($client->getRedirectUri(), $redirectUri) !== 0) + ) { + throw OAuthServerException::invalidClient(); + } elseif ( + is_array($client->getRedirectUri()) + && in_array($redirectUri, $client->getRedirectUri()) === false + ) { + throw OAuthServerException::invalidClient(); + } } return $client; diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 1161ebc4..cdde8764 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -185,6 +185,34 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $validateClientMethod->invoke($grantMock, $serverRequest, true, true); } + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateClientInvalidRedirectUriArray() + { + $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 */ From fc9e912e067d772bb9bc668e7596ec1ab3165ebb Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 13:45:38 +0100 Subject: [PATCH 362/444] Fixed broken test --- tests/ResponseTypes/BearerResponseTypeTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index c60426a2..962cd99b 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -157,8 +157,8 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase public function testDetermineAccessTokenInHeaderRevokedToken() { $responseType = new BearerTokenResponse(); - $responseType->setPrivateKeyPath('file://' . __DIR__ . '/../Stubs/private.key'); - $responseType->setPublicKeyPath('file://' . __DIR__ . '/../Stubs/public.key'); + $responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $client = new ClientEntity(); $client->setIdentifier('clientName'); From a83c56f570d9ab22134834edc445041f64b65593 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 13:53:14 +0100 Subject: [PATCH 363/444] Comment improvement --- src/AuthorizationValidators/BearerTokenValidator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AuthorizationValidators/BearerTokenValidator.php b/src/AuthorizationValidators/BearerTokenValidator.php index ecee1fd2..ac619817 100644 --- a/src/AuthorizationValidators/BearerTokenValidator.php +++ b/src/AuthorizationValidators/BearerTokenValidator.php @@ -48,7 +48,7 @@ class BearerTokenValidator implements AuthorizationValidatorInterface throw OAuthServerException::accessDenied('Access token could not be verified'); } - // validate + // Ensure access token hasn't expired $data = new ValidationData(); $data->setCurrentTime(time()); From 1ccfd9be3273d4a1a6743990a15738086a6d3823 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 08:53:29 -0400 Subject: [PATCH 364/444] Applied fixes from StyleCI --- src/AuthorizationValidators/BearerTokenValidator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AuthorizationValidators/BearerTokenValidator.php b/src/AuthorizationValidators/BearerTokenValidator.php index ac619817..f7ad7267 100644 --- a/src/AuthorizationValidators/BearerTokenValidator.php +++ b/src/AuthorizationValidators/BearerTokenValidator.php @@ -3,8 +3,8 @@ namespace League\OAuth2\Server\AuthorizationValidators; use Lcobucci\JWT\Parser; -use Lcobucci\JWT\ValidationData; use Lcobucci\JWT\Signer\Rsa\Sha256; +use Lcobucci\JWT\ValidationData; use League\OAuth2\Server\CryptTrait; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; From 3c0a7f14abe927aac6ee02a17aa4612bf109e792 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 14:15:10 +0100 Subject: [PATCH 365/444] Fixed broken tests --- tests/Grant/AuthCodeGrantTest.php | 2 ++ tests/Grant/ImplicitGrantTest.php | 1 + tests/Grant/RefreshTokenGrantTest.php | 1 + 3 files changed, 4 insertions(+) diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 7b90504a..78acce56 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -3,6 +3,8 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\CryptKey; +use League\OAuth2\Server\Entities\AccessTokenEntity; +use League\OAuth2\Server\Entities\AuthCodeEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntity; diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 150449cd..09362417 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -3,6 +3,7 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\CryptKey; +use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ImplicitGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index 5a6859d4..2159d0fc 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -3,6 +3,7 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\CryptKey; +use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntity; From be9bd76f3520ed0e29a3efaf4745a0222f503c54 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 15:09:13 +0100 Subject: [PATCH 366/444] Added AccessTokenTrait --- src/Entities/Traits/AccessTokenTrait.php | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/Entities/Traits/AccessTokenTrait.php diff --git a/src/Entities/Traits/AccessTokenTrait.php b/src/Entities/Traits/AccessTokenTrait.php new file mode 100644 index 00000000..17a8f7d4 --- /dev/null +++ b/src/Entities/Traits/AccessTokenTrait.php @@ -0,0 +1,32 @@ +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($privateKey->getKeyPath(), $privateKey->getPassPhrase())) + ->getToken(); + } +} From 5cba35456fb3c548e7eb71466e60bc1d4c34e86b Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 15:09:22 +0100 Subject: [PATCH 367/444] Updated access token repository example --- examples/src/Entities/AccessTokenEntity.php | 13 +++++++ .../Repositories/AccessTokenRepository.php | 37 ++++++++++++------- 2 files changed, 36 insertions(+), 14 deletions(-) create mode 100644 examples/src/Entities/AccessTokenEntity.php diff --git a/examples/src/Entities/AccessTokenEntity.php b/examples/src/Entities/AccessTokenEntity.php new file mode 100644 index 00000000..e1dd1a02 --- /dev/null +++ b/examples/src/Entities/AccessTokenEntity.php @@ -0,0 +1,13 @@ +setClient($clientEntity); + foreach ($scopes as $scope) { + $accessToken->addScope($scope); + } + $accessToken->setUserIdentifier($userIdentifier); + + return $accessToken; } } From 5ca215231314165de6790f0666df183bc936c3bf Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 15:17:11 +0100 Subject: [PATCH 368/444] Updated examples --- examples/src/Entities/AuthCodeEntity.php | 13 +++++++++ examples/src/Entities/RefreshTokenEntity.php | 12 ++++++++ .../src/Repositories/AuthCodeRepository.php | 29 ++++++++++--------- .../Repositories/RefreshTokenRepository.php | 29 ++++++++++--------- src/Entities/Traits/AuthCodeTrait.php | 27 +++++++++++++++++ 5 files changed, 82 insertions(+), 28 deletions(-) create mode 100644 examples/src/Entities/AuthCodeEntity.php create mode 100644 examples/src/Entities/RefreshTokenEntity.php create mode 100644 src/Entities/Traits/AuthCodeTrait.php diff --git a/examples/src/Entities/AuthCodeEntity.php b/examples/src/Entities/AuthCodeEntity.php new file mode 100644 index 00000000..a54217ef --- /dev/null +++ b/examples/src/Entities/AuthCodeEntity.php @@ -0,0 +1,13 @@ +redirectUri; + } + + /** + * @param string $uri + */ + public function setRedirectUri($uri) + { + $this->redirectUri = $uri; + } +} From 6773db66c66ab426e1becd8879f3b4929e322868 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 10:19:40 -0400 Subject: [PATCH 369/444] Applied fixes from StyleCI --- examples/src/Repositories/AccessTokenRepository.php | 8 ++++---- examples/src/Repositories/AuthCodeRepository.php | 8 ++++---- examples/src/Repositories/RefreshTokenRepository.php | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/src/Repositories/AccessTokenRepository.php b/examples/src/Repositories/AccessTokenRepository.php index b61f03a2..526dbd6e 100644 --- a/examples/src/Repositories/AccessTokenRepository.php +++ b/examples/src/Repositories/AccessTokenRepository.php @@ -10,7 +10,7 @@ use OAuth2ServerExamples\Entities\AccessTokenEntity; class AccessTokenRepository implements AccessTokenRepositoryInterface { /** - * @inheritdoc + * {@inheritdoc} */ public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity) { @@ -18,7 +18,7 @@ class AccessTokenRepository implements AccessTokenRepositoryInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function revokeAccessToken($tokenId) { @@ -26,7 +26,7 @@ class AccessTokenRepository implements AccessTokenRepositoryInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function isAccessTokenRevoked($tokenId) { @@ -34,7 +34,7 @@ class AccessTokenRepository implements AccessTokenRepositoryInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null) { diff --git a/examples/src/Repositories/AuthCodeRepository.php b/examples/src/Repositories/AuthCodeRepository.php index 7145329f..4c8c72ff 100644 --- a/examples/src/Repositories/AuthCodeRepository.php +++ b/examples/src/Repositories/AuthCodeRepository.php @@ -9,7 +9,7 @@ use OAuth2ServerExamples\Entities\AuthCodeEntity; class AuthCodeRepository implements AuthCodeRepositoryInterface { /** - * @inheritdoc + * {@inheritdoc} */ public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity) { @@ -17,7 +17,7 @@ class AuthCodeRepository implements AuthCodeRepositoryInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function revokeAuthCode($codeId) { @@ -25,7 +25,7 @@ class AuthCodeRepository implements AuthCodeRepositoryInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function isAuthCodeRevoked($codeId) { @@ -33,7 +33,7 @@ class AuthCodeRepository implements AuthCodeRepositoryInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function getNewAuthCode() { diff --git a/examples/src/Repositories/RefreshTokenRepository.php b/examples/src/Repositories/RefreshTokenRepository.php index e481dfcc..35175bd0 100644 --- a/examples/src/Repositories/RefreshTokenRepository.php +++ b/examples/src/Repositories/RefreshTokenRepository.php @@ -9,7 +9,7 @@ use OAuth2ServerExamples\Entities\RefreshTokenEntity; class RefreshTokenRepository implements RefreshTokenRepositoryInterface { /** - * @inheritdoc + * {@inheritdoc} */ public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntityInterface) { @@ -17,7 +17,7 @@ class RefreshTokenRepository implements RefreshTokenRepositoryInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function revokeRefreshToken($tokenId) { @@ -25,7 +25,7 @@ class RefreshTokenRepository implements RefreshTokenRepositoryInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function isRefreshTokenRevoked($tokenId) { @@ -33,7 +33,7 @@ class RefreshTokenRepository implements RefreshTokenRepositoryInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function getNewRefreshToken() { From 00518dded7fa8840cbd93d8f14ca60ac7a6c994f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 15:21:15 +0100 Subject: [PATCH 370/444] Removed built-in entities, all functinality available using traits --- src/Entities/AccessTokenEntity.php | 37 ----------------------------- src/Entities/AuthCodeEntity.php | 33 ------------------------- src/Entities/RefreshTokenEntity.php | 15 ------------ 3 files changed, 85 deletions(-) delete mode 100644 src/Entities/AccessTokenEntity.php delete mode 100644 src/Entities/AuthCodeEntity.php delete mode 100644 src/Entities/RefreshTokenEntity.php diff --git a/src/Entities/AccessTokenEntity.php b/src/Entities/AccessTokenEntity.php deleted file mode 100644 index 34ae167e..00000000 --- a/src/Entities/AccessTokenEntity.php +++ /dev/null @@ -1,37 +0,0 @@ -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($privateKey->getKeyPath(), $privateKey->getPassPhrase())) - ->getToken(); - } -} diff --git a/src/Entities/AuthCodeEntity.php b/src/Entities/AuthCodeEntity.php deleted file mode 100644 index 87279d30..00000000 --- a/src/Entities/AuthCodeEntity.php +++ /dev/null @@ -1,33 +0,0 @@ -redirectUri; - } - - /** - * @param string $uri - */ - public function setRedirectUri($uri) - { - $this->redirectUri = $uri; - } -} diff --git a/src/Entities/RefreshTokenEntity.php b/src/Entities/RefreshTokenEntity.php deleted file mode 100644 index 97b0348a..00000000 --- a/src/Entities/RefreshTokenEntity.php +++ /dev/null @@ -1,15 +0,0 @@ - Date: Sat, 9 Apr 2016 15:25:32 +0100 Subject: [PATCH 371/444] Moved entity interfaces into parent folder. Fixes #504 --- .../{Interfaces => }/AccessTokenEntityInterface.php | 2 +- src/Entities/{Interfaces => }/AuthCodeEntityInterface.php | 2 +- src/Entities/{Interfaces => }/ClientEntityInterface.php | 2 +- .../{Interfaces => }/RefreshTokenEntityInterface.php | 6 +++--- src/Entities/{Interfaces => }/ScopeEntityInterface.php | 2 +- src/Entities/{Interfaces => }/TokenInterface.php | 6 +++--- src/Entities/{Interfaces => }/UserEntityInterface.php | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) rename src/Entities/{Interfaces => }/AccessTokenEntityInterface.php (85%) rename src/Entities/{Interfaces => }/AuthCodeEntityInterface.php (81%) rename src/Entities/{Interfaces => }/ClientEntityInterface.php (90%) rename src/Entities/{Interfaces => }/RefreshTokenEntityInterface.php (81%) rename src/Entities/{Interfaces => }/ScopeEntityInterface.php (78%) rename src/Entities/{Interfaces => }/TokenInterface.php (87%) rename src/Entities/{Interfaces => }/UserEntityInterface.php (75%) diff --git a/src/Entities/Interfaces/AccessTokenEntityInterface.php b/src/Entities/AccessTokenEntityInterface.php similarity index 85% rename from src/Entities/Interfaces/AccessTokenEntityInterface.php rename to src/Entities/AccessTokenEntityInterface.php index 2b4c38a8..82ce640c 100644 --- a/src/Entities/Interfaces/AccessTokenEntityInterface.php +++ b/src/Entities/AccessTokenEntityInterface.php @@ -1,6 +1,6 @@ Date: Sat, 9 Apr 2016 15:25:45 +0100 Subject: [PATCH 372/444] Updated references to interfaces --- examples/src/Entities/AccessTokenEntity.php | 2 +- examples/src/Entities/AuthCodeEntity.php | 2 +- examples/src/Entities/ClientEntity.php | 2 +- examples/src/Entities/RefreshTokenEntity.php | 2 +- examples/src/Entities/ScopeEntity.php | 2 +- examples/src/Entities/UserEntity.php | 2 +- .../Repositories/AccessTokenRepository.php | 4 +-- .../src/Repositories/AuthCodeRepository.php | 2 +- .../Repositories/RefreshTokenRepository.php | 2 +- examples/src/Repositories/ScopeRepository.php | 2 +- examples/src/Repositories/UserRepository.php | 2 +- src/Entities/Traits/RefreshTokenTrait.php | 2 +- src/Entities/Traits/TokenEntityTrait.php | 8 +++--- src/Grant/AbstractGrant.php | 28 +++++++++---------- src/Grant/AuthCodeGrant.php | 4 +-- src/Grant/ImplicitGrant.php | 4 +-- src/Grant/PasswordGrant.php | 8 +++--- .../AbstractAccessTokenRepository.php | 12 ++++---- .../AbstractAuthCodeRepository.php | 6 ++-- .../AbstractRefreshTokenRepository.php | 4 +-- .../AccessTokenRepositoryInterface.php | 10 +++---- .../AuthCodeRepositoryInterface.php | 6 ++-- .../ClientRepositoryInterface.php | 2 +- .../RefreshTokenRepositoryInterface.php | 4 +-- src/Repositories/ScopeRepositoryInterface.php | 10 +++---- src/Repositories/UserRepositoryInterface.php | 6 ++-- src/ResponseTypes/AbstractResponseType.php | 8 +++--- src/ResponseTypes/BearerTokenResponse.php | 2 +- src/ResponseTypes/ResponseTypeInterface.php | 8 +++--- tests/Grant/AbstractGrantTest.php | 6 ++-- tests/Grant/AuthCodeGrantTest.php | 4 +-- tests/Grant/ClientCredentialsGrantTest.php | 2 +- tests/Grant/PasswordGrantTest.php | 4 +-- tests/Grant/RefreshTokenGrantTest.php | 4 +-- tests/Stubs/ClientEntity.php | 2 +- tests/Stubs/ScopeEntity.php | 2 +- tests/Stubs/StubResponseType.php | 8 +++--- tests/Stubs/UserEntity.php | 2 +- 38 files changed, 95 insertions(+), 95 deletions(-) diff --git a/examples/src/Entities/AccessTokenEntity.php b/examples/src/Entities/AccessTokenEntity.php index e1dd1a02..802bafe0 100644 --- a/examples/src/Entities/AccessTokenEntity.php +++ b/examples/src/Entities/AccessTokenEntity.php @@ -2,7 +2,7 @@ namespace OAuth2ServerExamples\Entities; -use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Traits\AccessTokenTrait; use League\OAuth2\Server\Entities\Traits\EntityTrait; use League\OAuth2\Server\Entities\Traits\TokenEntityTrait; diff --git a/examples/src/Entities/AuthCodeEntity.php b/examples/src/Entities/AuthCodeEntity.php index a54217ef..65590532 100644 --- a/examples/src/Entities/AuthCodeEntity.php +++ b/examples/src/Entities/AuthCodeEntity.php @@ -2,7 +2,7 @@ namespace OAuth2ServerExamples\Entities; -use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; +use League\OAuth2\Server\Entities\AuthCodeEntityInterface; use League\OAuth2\Server\Entities\Traits\AuthCodeTrait; use League\OAuth2\Server\Entities\Traits\EntityTrait; use League\OAuth2\Server\Entities\Traits\TokenEntityTrait; diff --git a/examples/src/Entities/ClientEntity.php b/examples/src/Entities/ClientEntity.php index 822a3f64..cb3c51d0 100644 --- a/examples/src/Entities/ClientEntity.php +++ b/examples/src/Entities/ClientEntity.php @@ -2,7 +2,7 @@ namespace OAuth2ServerExamples\Entities; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Entities\Traits\EntityTrait; class ClientEntity implements ClientEntityInterface diff --git a/examples/src/Entities/RefreshTokenEntity.php b/examples/src/Entities/RefreshTokenEntity.php index 13ea68eb..ab4561eb 100644 --- a/examples/src/Entities/RefreshTokenEntity.php +++ b/examples/src/Entities/RefreshTokenEntity.php @@ -2,7 +2,7 @@ namespace OAuth2ServerExamples\Entities; -use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\Traits\EntityTrait; use League\OAuth2\Server\Entities\Traits\RefreshTokenTrait; diff --git a/examples/src/Entities/ScopeEntity.php b/examples/src/Entities/ScopeEntity.php index 23d12a44..ba6da73b 100644 --- a/examples/src/Entities/ScopeEntity.php +++ b/examples/src/Entities/ScopeEntity.php @@ -2,7 +2,7 @@ namespace OAuth2ServerExamples\Entities; -use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; +use League\OAuth2\Server\Entities\ScopeEntityInterface; use League\OAuth2\Server\Entities\Traits\EntityTrait; class ScopeEntity implements ScopeEntityInterface diff --git a/examples/src/Entities/UserEntity.php b/examples/src/Entities/UserEntity.php index 9efe6611..d56bdaab 100644 --- a/examples/src/Entities/UserEntity.php +++ b/examples/src/Entities/UserEntity.php @@ -2,7 +2,7 @@ namespace OAuth2ServerExamples\Entities; -use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; +use League\OAuth2\Server\Entities\UserEntityInterface; class UserEntity implements UserEntityInterface { diff --git a/examples/src/Repositories/AccessTokenRepository.php b/examples/src/Repositories/AccessTokenRepository.php index b61f03a2..768f2453 100644 --- a/examples/src/Repositories/AccessTokenRepository.php +++ b/examples/src/Repositories/AccessTokenRepository.php @@ -2,8 +2,8 @@ namespace OAuth2ServerExamples\Repositories; -use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Entities\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use OAuth2ServerExamples\Entities\AccessTokenEntity; diff --git a/examples/src/Repositories/AuthCodeRepository.php b/examples/src/Repositories/AuthCodeRepository.php index 7145329f..0bf5419b 100644 --- a/examples/src/Repositories/AuthCodeRepository.php +++ b/examples/src/Repositories/AuthCodeRepository.php @@ -2,7 +2,7 @@ namespace OAuth2ServerExamples\Repositories; -use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; +use League\OAuth2\Server\Entities\AuthCodeEntityInterface; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use OAuth2ServerExamples\Entities\AuthCodeEntity; diff --git a/examples/src/Repositories/RefreshTokenRepository.php b/examples/src/Repositories/RefreshTokenRepository.php index e481dfcc..3e868fd5 100644 --- a/examples/src/Repositories/RefreshTokenRepository.php +++ b/examples/src/Repositories/RefreshTokenRepository.php @@ -2,7 +2,7 @@ namespace OAuth2ServerExamples\Repositories; -use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use OAuth2ServerExamples\Entities\RefreshTokenEntity; diff --git a/examples/src/Repositories/ScopeRepository.php b/examples/src/Repositories/ScopeRepository.php index 26aa15cb..228c629b 100644 --- a/examples/src/Repositories/ScopeRepository.php +++ b/examples/src/Repositories/ScopeRepository.php @@ -2,7 +2,7 @@ namespace OAuth2ServerExamples\Repositories; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use OAuth2ServerExamples\Entities\ScopeEntity; diff --git a/examples/src/Repositories/UserRepository.php b/examples/src/Repositories/UserRepository.php index 1ee09fc1..9726be25 100644 --- a/examples/src/Repositories/UserRepository.php +++ b/examples/src/Repositories/UserRepository.php @@ -2,7 +2,7 @@ namespace OAuth2ServerExamples\Repositories; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use OAuth2ServerExamples\Entities\ScopeEntity; use OAuth2ServerExamples\Entities\UserEntity; diff --git a/src/Entities/Traits/RefreshTokenTrait.php b/src/Entities/Traits/RefreshTokenTrait.php index f9b60960..96d429fe 100644 --- a/src/Entities/Traits/RefreshTokenTrait.php +++ b/src/Entities/Traits/RefreshTokenTrait.php @@ -3,7 +3,7 @@ namespace League\OAuth2\Server\Entities\Traits; use DateTime; -use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\AccessTokenEntityInterface; trait RefreshTokenTrait { diff --git a/src/Entities/Traits/TokenEntityTrait.php b/src/Entities/Traits/TokenEntityTrait.php index e7b9d29f..3c91542f 100644 --- a/src/Entities/Traits/TokenEntityTrait.php +++ b/src/Entities/Traits/TokenEntityTrait.php @@ -3,8 +3,8 @@ namespace League\OAuth2\Server\Entities\Traits; use DateTime; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; +use League\OAuth2\Server\Entities\ClientEntityInterface; +use League\OAuth2\Server\Entities\ScopeEntityInterface; trait TokenEntityTrait { @@ -31,7 +31,7 @@ trait TokenEntityTrait /** * Associate a scope with the token. * - * @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface $scope + * @param \League\OAuth2\Server\Entities\ScopeEntityInterface $scope */ public function addScope(ScopeEntityInterface $scope) { @@ -101,7 +101,7 @@ trait TokenEntityTrait /** * Set the client that the token was issued to. * - * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client + * @param \League\OAuth2\Server\Entities\ClientEntityInterface $client */ public function setClient(ClientEntityInterface $client) { diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index ca459945..0a1cf824 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -12,9 +12,9 @@ namespace League\OAuth2\Server\Grant; use League\Event\EmitterAwareTrait; use League\OAuth2\Server\CryptTrait; -use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; +use League\OAuth2\Server\Entities\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\ClientEntityInterface; +use League\OAuth2\Server\Entities\ScopeEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; @@ -137,7 +137,7 @@ abstract class AbstractGrant implements GrantTypeInterface * * @throws \League\OAuth2\Server\Exception\OAuthServerException * - * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface + * @return \League\OAuth2\Server\Entities\ClientEntityInterface */ protected function validateClient(ServerRequestInterface $request) { @@ -191,12 +191,12 @@ abstract class AbstractGrant implements GrantTypeInterface * Validate scopes in the request. * * @param string $scopes - * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client + * @param \League\OAuth2\Server\Entities\ClientEntityInterface $client * @param string $redirectUri * * @throws \League\OAuth2\Server\Exception\OAuthServerException * - * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] + * @return \League\OAuth2\Server\Entities\ScopeEntityInterface[] */ public function validateScopes( $scopes, @@ -286,11 +286,11 @@ abstract class AbstractGrant implements GrantTypeInterface * Issue an access token. * * @param \DateInterval $accessTokenTTL - * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client + * @param \League\OAuth2\Server\Entities\ClientEntityInterface $client * @param string $userIdentifier - * @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] $scopes + * @param \League\OAuth2\Server\Entities\ScopeEntityInterface[] $scopes * - * @return \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface + * @return \League\OAuth2\Server\Entities\AccessTokenEntityInterface */ protected function issueAccessToken( \DateInterval $accessTokenTTL, @@ -317,12 +317,12 @@ abstract class AbstractGrant implements GrantTypeInterface * Issue an auth code. * * @param \DateInterval $authCodeTTL - * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client + * @param \League\OAuth2\Server\Entities\ClientEntityInterface $client * @param string $userIdentifier * @param string $redirectUri - * @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] $scopes + * @param \League\OAuth2\Server\Entities\ScopeEntityInterface[] $scopes * - * @return \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface + * @return \League\OAuth2\Server\Entities\AuthCodeEntityInterface */ protected function issueAuthCode( \DateInterval $authCodeTTL, @@ -348,9 +348,9 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken + * @param \League\OAuth2\Server\Entities\AccessTokenEntityInterface $accessToken * - * @return \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface + * @return \League\OAuth2\Server\Entities\RefreshTokenEntityInterface */ protected function issueRefreshToken(AccessTokenEntityInterface $accessToken) { diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 93e7eb51..210dc9a1 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -3,8 +3,8 @@ namespace League\OAuth2\Server\Grant; use DateInterval; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; +use League\OAuth2\Server\Entities\ClientEntityInterface; +use League\OAuth2\Server\Entities\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 6f7b1301..fefc7189 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -2,8 +2,8 @@ namespace League\OAuth2\Server\Grant; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; +use League\OAuth2\Server\Entities\ClientEntityInterface; +use League\OAuth2\Server\Entities\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\RequestEvent; diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index be3d4707..2e3dddd0 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -10,8 +10,8 @@ */ namespace League\OAuth2\Server\Grant; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; +use League\OAuth2\Server\Entities\ClientEntityInterface; +use League\OAuth2\Server\Entities\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; @@ -67,11 +67,11 @@ class PasswordGrant extends AbstractGrant /** * @param \Psr\Http\Message\ServerRequestInterface $request - * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client + * @param \League\OAuth2\Server\Entities\ClientEntityInterface $client * * @throws \League\OAuth2\Server\Exception\OAuthServerException * - * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface + * @return \League\OAuth2\Server\Entities\UserEntityInterface */ protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client) { diff --git a/src/Repositories/AbstractAccessTokenRepository.php b/src/Repositories/AbstractAccessTokenRepository.php index 321abc65..8c5c5948 100644 --- a/src/Repositories/AbstractAccessTokenRepository.php +++ b/src/Repositories/AbstractAccessTokenRepository.php @@ -2,19 +2,19 @@ namespace League\OAuth2\Server\Repositories; use League\OAuth2\Server\Entities\AccessTokenEntity; -use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Entities\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\ClientEntityInterface; abstract class AbstractAccessTokenRepository implements AccessTokenRepositoryInterface { /** * Create a new access token * - * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $clientEntity - * @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] $scopes + * @param \League\OAuth2\Server\Entities\ClientEntityInterface $clientEntity + * @param \League\OAuth2\Server\Entities\ScopeEntityInterface[] $scopes * @param mixed $userIdentifier * - * @return \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface + * @return \League\OAuth2\Server\Entities\AccessTokenEntityInterface */ public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null) { @@ -24,7 +24,7 @@ abstract class AbstractAccessTokenRepository implements AccessTokenRepositoryInt /** * Persists a new access token to permanent storage. * - * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessTokenEntity + * @param \League\OAuth2\Server\Entities\AccessTokenEntityInterface $accessTokenEntity */ abstract public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity); diff --git a/src/Repositories/AbstractAuthCodeRepository.php b/src/Repositories/AbstractAuthCodeRepository.php index b6d3ed6f..6bd43e49 100644 --- a/src/Repositories/AbstractAuthCodeRepository.php +++ b/src/Repositories/AbstractAuthCodeRepository.php @@ -11,7 +11,7 @@ namespace League\OAuth2\Server\Repositories; use League\OAuth2\Server\Entities\AuthCodeEntity; -use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; +use League\OAuth2\Server\Entities\AuthCodeEntityInterface; /** * Auth code storage abstract class. @@ -21,7 +21,7 @@ abstract class AbstractAuthCodeRepository implements AuthCodeRepositoryInterface /** * Creates a new AuthCode * - * @return \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface + * @return \League\OAuth2\Server\Entities\AuthCodeEntityInterface */ public function getNewAuthCode() { @@ -31,7 +31,7 @@ abstract class AbstractAuthCodeRepository implements AuthCodeRepositoryInterface /** * Persists a new auth code to permanent storage. * - * @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $authCodeEntity + * @param \League\OAuth2\Server\Entities\AuthCodeEntityInterface $authCodeEntity */ abstract public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity); diff --git a/src/Repositories/AbstractRefreshTokenRepository.php b/src/Repositories/AbstractRefreshTokenRepository.php index ff786f94..04748b2d 100644 --- a/src/Repositories/AbstractRefreshTokenRepository.php +++ b/src/Repositories/AbstractRefreshTokenRepository.php @@ -10,7 +10,7 @@ */ namespace League\OAuth2\Server\Repositories; -use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntity; /** @@ -31,7 +31,7 @@ abstract class AbstractRefreshTokenRepository implements RefreshTokenRepositoryI /** * Create a new refresh token_name. * - * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshTokenEntity + * @param \League\OAuth2\Server\Entities\RefreshTokenEntityInterface $refreshTokenEntity */ abstract public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity); diff --git a/src/Repositories/AccessTokenRepositoryInterface.php b/src/Repositories/AccessTokenRepositoryInterface.php index a6d725a2..426d71f8 100644 --- a/src/Repositories/AccessTokenRepositoryInterface.php +++ b/src/Repositories/AccessTokenRepositoryInterface.php @@ -10,8 +10,8 @@ */ namespace League\OAuth2\Server\Repositories; -use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Entities\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\ClientEntityInterface; /** * Access token interface. @@ -21,8 +21,8 @@ interface AccessTokenRepositoryInterface extends RepositoryInterface /** * Create a new access token * - * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $clientEntity - * @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] $scopes + * @param \League\OAuth2\Server\Entities\ClientEntityInterface $clientEntity + * @param \League\OAuth2\Server\Entities\ScopeEntityInterface[] $scopes * @param mixed $userIdentifier * * @return AccessTokenEntityInterface @@ -32,7 +32,7 @@ interface AccessTokenRepositoryInterface extends RepositoryInterface /** * Persists a new access token to permanent storage. * - * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessTokenEntity + * @param \League\OAuth2\Server\Entities\AccessTokenEntityInterface $accessTokenEntity */ public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity); diff --git a/src/Repositories/AuthCodeRepositoryInterface.php b/src/Repositories/AuthCodeRepositoryInterface.php index d1da7d44..052fb849 100644 --- a/src/Repositories/AuthCodeRepositoryInterface.php +++ b/src/Repositories/AuthCodeRepositoryInterface.php @@ -10,7 +10,7 @@ */ namespace League\OAuth2\Server\Repositories; -use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; +use League\OAuth2\Server\Entities\AuthCodeEntityInterface; /** * Auth code storage interface. @@ -20,14 +20,14 @@ interface AuthCodeRepositoryInterface extends RepositoryInterface /** * Creates a new AuthCode * - * @return \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface + * @return \League\OAuth2\Server\Entities\AuthCodeEntityInterface */ public function getNewAuthCode(); /** * Persists a new auth code to permanent storage. * - * @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $authCodeEntity + * @param \League\OAuth2\Server\Entities\AuthCodeEntityInterface $authCodeEntity */ public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity); diff --git a/src/Repositories/ClientRepositoryInterface.php b/src/Repositories/ClientRepositoryInterface.php index a742b366..ce6c2b0e 100644 --- a/src/Repositories/ClientRepositoryInterface.php +++ b/src/Repositories/ClientRepositoryInterface.php @@ -22,7 +22,7 @@ interface ClientRepositoryInterface extends RepositoryInterface * @param string $grantType The grant type used * @param null|string $clientSecret The client's secret (if sent) * - * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface + * @return \League\OAuth2\Server\Entities\ClientEntityInterface */ public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null); } diff --git a/src/Repositories/RefreshTokenRepositoryInterface.php b/src/Repositories/RefreshTokenRepositoryInterface.php index e857e2ff..d7e496c4 100644 --- a/src/Repositories/RefreshTokenRepositoryInterface.php +++ b/src/Repositories/RefreshTokenRepositoryInterface.php @@ -10,7 +10,7 @@ */ namespace League\OAuth2\Server\Repositories; -use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; /** * Refresh token interface. @@ -27,7 +27,7 @@ interface RefreshTokenRepositoryInterface extends RepositoryInterface /** * Create a new refresh token_name. * - * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshTokenEntity + * @param \League\OAuth2\Server\Entities\RefreshTokenEntityInterface $refreshTokenEntity */ public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity); diff --git a/src/Repositories/ScopeRepositoryInterface.php b/src/Repositories/ScopeRepositoryInterface.php index ccafbbdd..524f1702 100644 --- a/src/Repositories/ScopeRepositoryInterface.php +++ b/src/Repositories/ScopeRepositoryInterface.php @@ -10,8 +10,8 @@ */ namespace League\OAuth2\Server\Repositories; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; +use League\OAuth2\Server\Entities\ClientEntityInterface; +use League\OAuth2\Server\Entities\ScopeEntityInterface; /** * Scope interface. @@ -23,7 +23,7 @@ interface ScopeRepositoryInterface extends RepositoryInterface * * @param string $identifier The scope identifier * - * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface + * @return \League\OAuth2\Server\Entities\ScopeEntityInterface */ public function getScopeEntityByIdentifier($identifier); @@ -33,10 +33,10 @@ interface ScopeRepositoryInterface extends RepositoryInterface * * @param ScopeEntityInterface[] $scopes * @param string $grantType - * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $clientEntity + * @param \League\OAuth2\Server\Entities\ClientEntityInterface $clientEntity * @param null|string $userIdentifier * - * @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] + * @return \League\OAuth2\Server\Entities\ScopeEntityInterface[] */ public function finalizeScopes( array $scopes, diff --git a/src/Repositories/UserRepositoryInterface.php b/src/Repositories/UserRepositoryInterface.php index b21503a7..f00436e8 100644 --- a/src/Repositories/UserRepositoryInterface.php +++ b/src/Repositories/UserRepositoryInterface.php @@ -2,7 +2,7 @@ namespace League\OAuth2\Server\Repositories; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Entities\ClientEntityInterface; interface UserRepositoryInterface extends RepositoryInterface { @@ -12,9 +12,9 @@ interface UserRepositoryInterface extends RepositoryInterface * @param string $username * @param string $password * @param string $grantType The grant type used - * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $clientEntity + * @param \League\OAuth2\Server\Entities\ClientEntityInterface $clientEntity * - * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface + * @return \League\OAuth2\Server\Entities\UserEntityInterface */ public function getUserEntityByUserCredentials( $username, diff --git a/src/ResponseTypes/AbstractResponseType.php b/src/ResponseTypes/AbstractResponseType.php index c42e1d87..02ce842b 100644 --- a/src/ResponseTypes/AbstractResponseType.php +++ b/src/ResponseTypes/AbstractResponseType.php @@ -11,20 +11,20 @@ namespace League\OAuth2\Server\ResponseTypes; use League\OAuth2\Server\CryptTrait; -use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; abstract class AbstractResponseType implements ResponseTypeInterface { use CryptTrait; /** - * @var \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface + * @var \League\OAuth2\Server\Entities\AccessTokenEntityInterface */ protected $accessToken; /** - * @var \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface + * @var \League\OAuth2\Server\Entities\RefreshTokenEntityInterface */ protected $refreshToken; diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index 7a77c699..63598265 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -10,7 +10,7 @@ */ namespace League\OAuth2\Server\ResponseTypes; -use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; use Psr\Http\Message\ResponseInterface; class BearerTokenResponse extends AbstractResponseType diff --git a/src/ResponseTypes/ResponseTypeInterface.php b/src/ResponseTypes/ResponseTypeInterface.php index 100e8cda..a26466a7 100644 --- a/src/ResponseTypes/ResponseTypeInterface.php +++ b/src/ResponseTypes/ResponseTypeInterface.php @@ -10,19 +10,19 @@ */ namespace League\OAuth2\Server\ResponseTypes; -use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; use Psr\Http\Message\ResponseInterface; interface ResponseTypeInterface { /** - * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken + * @param \League\OAuth2\Server\Entities\AccessTokenEntityInterface $accessToken */ public function setAccessToken(AccessTokenEntityInterface $accessToken); /** - * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshToken + * @param \League\OAuth2\Server\Entities\RefreshTokenEntityInterface $refreshToken */ public function setRefreshToken(RefreshTokenEntityInterface $refreshToken); diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 7dda918d..0fb3fab4 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -6,9 +6,9 @@ use League\Event\Emitter; use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\AuthCodeEntity; -use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\AuthCodeEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Grant\AbstractGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 78acce56..7782f030 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -5,8 +5,8 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\AuthCodeEntity; -use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; diff --git a/tests/Grant/ClientCredentialsGrantTest.php b/tests/Grant/ClientCredentialsGrantTest.php index a6b66dcd..7ce66307 100644 --- a/tests/Grant/ClientCredentialsGrantTest.php +++ b/tests/Grant/ClientCredentialsGrantTest.php @@ -3,7 +3,7 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\Entities\AccessTokenEntity; -use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php index eb72c905..0368569e 100644 --- a/tests/Grant/PasswordGrantTest.php +++ b/tests/Grant/PasswordGrantTest.php @@ -3,8 +3,8 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\Entities\AccessTokenEntity; -use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index 2159d0fc..6832f8c7 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -4,8 +4,8 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Entities\AccessTokenEntity; -use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; diff --git a/tests/Stubs/ClientEntity.php b/tests/Stubs/ClientEntity.php index 4956b62b..af75200f 100644 --- a/tests/Stubs/ClientEntity.php +++ b/tests/Stubs/ClientEntity.php @@ -2,7 +2,7 @@ namespace LeagueTests\Stubs; -use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Entities\Traits\EntityTrait; class ClientEntity implements ClientEntityInterface diff --git a/tests/Stubs/ScopeEntity.php b/tests/Stubs/ScopeEntity.php index ad448769..4e4a6bec 100644 --- a/tests/Stubs/ScopeEntity.php +++ b/tests/Stubs/ScopeEntity.php @@ -2,7 +2,7 @@ namespace LeagueTests\Stubs; -use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; +use League\OAuth2\Server\Entities\ScopeEntityInterface; use League\OAuth2\Server\Entities\Traits\EntityTrait; class ScopeEntity implements ScopeEntityInterface diff --git a/tests/Stubs/StubResponseType.php b/tests/Stubs/StubResponseType.php index 04e09d62..ac8679d2 100644 --- a/tests/Stubs/StubResponseType.php +++ b/tests/Stubs/StubResponseType.php @@ -2,8 +2,8 @@ namespace LeagueTests\Stubs; -use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\ResponseTypes\AbstractResponseType; use Psr\Http\Message\ResponseInterface; @@ -27,7 +27,7 @@ class StubResponseType extends AbstractResponseType } /** - * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken + * @param \League\OAuth2\Server\Entities\AccessTokenEntityInterface $accessToken */ public function setAccessToken(AccessTokenEntityInterface $accessToken) { @@ -35,7 +35,7 @@ class StubResponseType extends AbstractResponseType } /** - * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshToken + * @param \League\OAuth2\Server\Entities\RefreshTokenEntityInterface $refreshToken */ public function setRefreshToken(RefreshTokenEntityInterface $refreshToken) { diff --git a/tests/Stubs/UserEntity.php b/tests/Stubs/UserEntity.php index 5d102c77..1936861d 100644 --- a/tests/Stubs/UserEntity.php +++ b/tests/Stubs/UserEntity.php @@ -2,7 +2,7 @@ namespace LeagueTests\Stubs; -use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; +use League\OAuth2\Server\Entities\UserEntityInterface; class UserEntity implements UserEntityInterface { From b59106dc64131c3773afce173a7cae73a7063a73 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 15:27:44 +0100 Subject: [PATCH 373/444] Added ClientTrait --- examples/src/Entities/ClientEntity.php | 77 +------------------------- src/Entities/Traits/ClientTrait.php | 32 +++++++++++ 2 files changed, 34 insertions(+), 75 deletions(-) create mode 100644 src/Entities/Traits/ClientTrait.php diff --git a/examples/src/Entities/ClientEntity.php b/examples/src/Entities/ClientEntity.php index cb3c51d0..36262646 100644 --- a/examples/src/Entities/ClientEntity.php +++ b/examples/src/Entities/ClientEntity.php @@ -3,83 +3,10 @@ namespace OAuth2ServerExamples\Entities; use League\OAuth2\Server\Entities\ClientEntityInterface; +use League\OAuth2\Server\Entities\Traits\ClientTrait; use League\OAuth2\Server\Entities\Traits\EntityTrait; class ClientEntity implements ClientEntityInterface { - use EntityTrait; - - private $name; - - private $secret; - - private $redirectUri; - - /** - * Get the client's name. - * - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * Set the client's name. - * - * @param string $name - */ - public function setName($name) - { - $this->name = $name; - } - - /** - * @param string $secret - */ - public function setSecret($secret) - { - $this->secret = $secret; - } - - /** - * Get the hashed client secret - * - * @return string - */ - public function getSecret() - { - return $this->secret; - } - - /** - * Set the client's redirect uri. - * - * @param string $redirectUri - */ - public function setRedirectUri($redirectUri) - { - $this->redirectUri = $redirectUri; - } - - /** - * Returns the registered redirect URI. - * - * @return string - */ - public function getRedirectUri() - { - return $this->redirectUri; - } - - /** - * Returns true if the client is capable of keeping it's secrets secret. - * - * @return bool - */ - public function canKeepASecret() - { - return $this->secret !== null; - } + use EntityTrait, ClientTrait; } diff --git a/src/Entities/Traits/ClientTrait.php b/src/Entities/Traits/ClientTrait.php new file mode 100644 index 00000000..bf5fb97d --- /dev/null +++ b/src/Entities/Traits/ClientTrait.php @@ -0,0 +1,32 @@ +name; + } + + /** + * Returns the registered redirect URI (as a string). + * + * Alternatively return an indexed array of redirect URIs. + * + * @return string|string[] + */ + public function getRedirectUri() + { + return $this->redirectUri; + } +} From 47656cd9b5d1b01a22c8ca91ce3626ffe22760e7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 15:44:38 +0100 Subject: [PATCH 374/444] Fix broken tests --- tests/Grant/AbstractGrantTest.php | 16 ++-- tests/Grant/AuthCodeGrantTest.php | 7 +- tests/Grant/ClientCredentialsGrantTest.php | 3 +- tests/Grant/ImplicitGrantTest.php | 4 +- tests/Grant/PasswordGrantTest.php | 8 +- tests/Grant/RefreshTokenGrantTest.php | 12 +-- .../AuthenticationServerMiddlewareTest.php | 2 +- .../ResourceServerMiddlewareTest.php | 2 +- .../ResponseTypes/BearerResponseTypeTest.php | 4 +- tests/ServerTest.php | 4 +- tests/Stubs/AccessTokenEntity.php | 13 ++++ tests/Stubs/AuthCodeEntity.php | 13 ++++ tests/Stubs/ClientEntity.php | 77 +------------------ tests/Stubs/RefreshTokenEntity.php | 12 +++ tests/Stubs/UserEntity.php | 7 +- 15 files changed, 70 insertions(+), 114 deletions(-) create mode 100644 tests/Stubs/AccessTokenEntity.php create mode 100644 tests/Stubs/AuthCodeEntity.php create mode 100644 tests/Stubs/RefreshTokenEntity.php diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 0fb3fab4..559a5269 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -4,12 +4,9 @@ namespace LeagueTests\Grant; use League\Event\Emitter; use League\OAuth2\Server\CryptKey; -use League\OAuth2\Server\Entities\AccessTokenEntity; -use League\OAuth2\Server\Entities\AuthCodeEntity; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\AuthCodeEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; -use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Grant\AbstractGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; @@ -17,6 +14,9 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use LeagueTests\Stubs\ClientEntity; +use LeagueTests\Stubs\AuthCodeEntity; +use LeagueTests\Stubs\AccessTokenEntity; +use LeagueTests\Stubs\RefreshTokenEntity; use LeagueTests\Stubs\ScopeEntity; use Zend\Diactoros\ServerRequest; @@ -60,8 +60,6 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase 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); @@ -178,8 +176,8 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $serverRequest = new ServerRequest(); $serverRequest = $serverRequest->withParsedBody([ - 'client_id' => 'foo', - 'redirect_uri' => 'http://bar/foo', + 'client_id' => 'foo', + 'redirect_uri' => 'http://bar/foo', ]); $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); @@ -206,8 +204,8 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $serverRequest = new ServerRequest(); $serverRequest = $serverRequest->withParsedBody([ - 'client_id' => 'foo', - 'redirect_uri' => 'http://bar/foo', + 'client_id' => 'foo', + 'redirect_uri' => 'http://bar/foo', ]); $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 7782f030..b49ecd18 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -3,11 +3,11 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\CryptKey; -use League\OAuth2\Server\Entities\AccessTokenEntity; -use League\OAuth2\Server\Entities\AuthCodeEntity; +use LeagueTests\Stubs\AccessTokenEntity; +use LeagueTests\Stubs\AuthCodeEntity; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; -use League\OAuth2\Server\Entities\RefreshTokenEntity; +use LeagueTests\Stubs\RefreshTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -705,7 +705,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 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); diff --git a/tests/Grant/ClientCredentialsGrantTest.php b/tests/Grant/ClientCredentialsGrantTest.php index 7ce66307..dc883a0e 100644 --- a/tests/Grant/ClientCredentialsGrantTest.php +++ b/tests/Grant/ClientCredentialsGrantTest.php @@ -2,7 +2,7 @@ namespace LeagueTests\Grant; -use League\OAuth2\Server\Entities\AccessTokenEntity; +use LeagueTests\Stubs\AccessTokenEntity; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -23,7 +23,6 @@ class ClientCredentialsGrantTest extends \PHPUnit_Framework_TestCase public function testRespondToRequest() { $client = new ClientEntity(); - $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 09362417..5636de0e 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -3,7 +3,7 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\CryptKey; -use League\OAuth2\Server\Entities\AccessTokenEntity; +use LeagueTests\Stubs\AccessTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ImplicitGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -221,7 +221,7 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase [ 'response_type' => 'token', 'client_id' => 'foo', - 'redirect_uri' => 'sdfsdf', + 'redirect_uri' => 'sdfsdf', ], [ 'username' => 'alex', diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php index 0368569e..f8827720 100644 --- a/tests/Grant/PasswordGrantTest.php +++ b/tests/Grant/PasswordGrantTest.php @@ -2,10 +2,10 @@ namespace LeagueTests\Grant; -use League\OAuth2\Server\Entities\AccessTokenEntity; +use LeagueTests\Stubs\AccessTokenEntity; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; -use League\OAuth2\Server\Entities\RefreshTokenEntity; +use LeagueTests\Stubs\RefreshTokenEntity; use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -31,7 +31,6 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase public function testRespondToRequest() { $client = new ClientEntity(); - $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); @@ -78,7 +77,6 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase public function testRespondToRequestMissingUsername() { $client = new ClientEntity(); - $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); @@ -110,7 +108,6 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase public function testRespondToRequestMissingPassword() { $client = new ClientEntity(); - $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); @@ -143,7 +140,6 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase public function testRespondToRequestBadCredentials() { $client = new ClientEntity(); - $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index 6832f8c7..b19dce9c 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -3,10 +3,10 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\CryptKey; -use League\OAuth2\Server\Entities\AccessTokenEntity; +use LeagueTests\Stubs\AccessTokenEntity; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; -use League\OAuth2\Server\Entities\RefreshTokenEntity; +use LeagueTests\Stubs\RefreshTokenEntity; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -42,7 +42,6 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase { $client = new ClientEntity(); $client->setIdentifier('foo'); - $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); @@ -102,7 +101,6 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase { $client = new ClientEntity(); $client->setIdentifier('foo'); - $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); @@ -164,7 +162,6 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase { $client = new ClientEntity(); $client->setIdentifier('foo'); - $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); @@ -221,7 +218,6 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase { $client = new ClientEntity(); $client->setIdentifier('foo'); - $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); @@ -254,7 +250,6 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase { $client = new ClientEntity(); $client->setIdentifier('foo'); - $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); @@ -290,7 +285,6 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase { $client = new ClientEntity(); $client->setIdentifier('foo'); - $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); @@ -341,7 +335,6 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase { $client = new ClientEntity(); $client->setIdentifier('foo'); - $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); @@ -388,7 +381,6 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase { $client = new ClientEntity(); $client->setIdentifier('foo'); - $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); diff --git a/tests/Middleware/AuthenticationServerMiddlewareTest.php b/tests/Middleware/AuthenticationServerMiddlewareTest.php index ee3b7007..cbc3cf62 100644 --- a/tests/Middleware/AuthenticationServerMiddlewareTest.php +++ b/tests/Middleware/AuthenticationServerMiddlewareTest.php @@ -2,7 +2,7 @@ namespace LeagueTests\Middleware; -use League\OAuth2\Server\Entities\AccessTokenEntity; +use LeagueTests\Stubs\AccessTokenEntity; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Middleware\AuthenticationServerMiddleware; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; diff --git a/tests/Middleware/ResourceServerMiddlewareTest.php b/tests/Middleware/ResourceServerMiddlewareTest.php index bb3f7ab7..a3517d1d 100644 --- a/tests/Middleware/ResourceServerMiddlewareTest.php +++ b/tests/Middleware/ResourceServerMiddlewareTest.php @@ -3,7 +3,7 @@ namespace LeagueTests\Middleware; use League\OAuth2\Server\CryptKey; -use League\OAuth2\Server\Entities\AccessTokenEntity; +use LeagueTests\Stubs\AccessTokenEntity; use League\OAuth2\Server\Middleware\ResourceServerMiddleware; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index 962cd99b..d6e75fdf 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -4,8 +4,8 @@ namespace LeagueTests\ResponseTypes; use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator; use League\OAuth2\Server\CryptKey; -use League\OAuth2\Server\Entities\AccessTokenEntity; -use League\OAuth2\Server\Entities\RefreshTokenEntity; +use\LeagueTests\Stubs\AccessTokenEntity; +use LeagueTests\Stubs\RefreshTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; diff --git a/tests/ServerTest.php b/tests/ServerTest.php index dd5477d1..ec261b6f 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -2,8 +2,8 @@ namespace LeagueTests; -use League\OAuth2\Server\Entities\AccessTokenEntity; -use League\OAuth2\Server\Entities\AuthCodeEntity; +use LeagueTests\Stubs\AccessTokenEntity; +use LeagueTests\Stubs\AuthCodeEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\ClientCredentialsGrant; diff --git a/tests/Stubs/AccessTokenEntity.php b/tests/Stubs/AccessTokenEntity.php new file mode 100644 index 00000000..77a4d223 --- /dev/null +++ b/tests/Stubs/AccessTokenEntity.php @@ -0,0 +1,13 @@ +name; + $this->redirectUri = $uri; } - /** - * {@inheritdoc} - */ public function setName($name) { $this->name = $name; } - /** - * {@inheritdoc} - */ - public function canKeepASecret() - { - return $this->secret !== null; - } - - /** - * {@inheritdoc} - */ - public function setSecret($secret) - { - $this->secret = password_hash($secret, PASSWORD_DEFAULT); - } - - /** - * {@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; - } - - /** - * Get the hashed client secret - * - * @return string - */ - public function getSecret() - { - return $this->secret; - } } diff --git a/tests/Stubs/RefreshTokenEntity.php b/tests/Stubs/RefreshTokenEntity.php new file mode 100644 index 00000000..f145b706 --- /dev/null +++ b/tests/Stubs/RefreshTokenEntity.php @@ -0,0 +1,12 @@ +setIdentifier(123); } } From d8d49f742e8d8b63b88a2083f6c0d9a37f9b42ea Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 15:46:30 +0100 Subject: [PATCH 375/444] Removed unnecessary abstract classes --- .../AbstractAccessTokenRepository.php | 46 ---------------- .../AbstractAuthCodeRepository.php | 53 ------------------- .../AbstractRefreshTokenRepository.php | 53 ------------------- 3 files changed, 152 deletions(-) delete mode 100644 src/Repositories/AbstractAccessTokenRepository.php delete mode 100644 src/Repositories/AbstractAuthCodeRepository.php delete mode 100644 src/Repositories/AbstractRefreshTokenRepository.php diff --git a/src/Repositories/AbstractAccessTokenRepository.php b/src/Repositories/AbstractAccessTokenRepository.php deleted file mode 100644 index 8c5c5948..00000000 --- a/src/Repositories/AbstractAccessTokenRepository.php +++ /dev/null @@ -1,46 +0,0 @@ - - * @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\AuthCodeEntity; -use League\OAuth2\Server\Entities\AuthCodeEntityInterface; - -/** - * Auth code storage abstract class. - */ -abstract class AbstractAuthCodeRepository implements AuthCodeRepositoryInterface -{ - /** - * Creates a new AuthCode - * - * @return \League\OAuth2\Server\Entities\AuthCodeEntityInterface - */ - public function getNewAuthCode() - { - return new AuthCodeEntity(); - } - - /** - * Persists a new auth code to permanent storage. - * - * @param \League\OAuth2\Server\Entities\AuthCodeEntityInterface $authCodeEntity - */ - abstract public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity); - - /** - * Revoke an auth code. - * - * @param string $codeId - */ - abstract public function revokeAuthCode($codeId); - - /** - * Check if the auth code has been revoked. - * - * @param string $codeId - * - * @return bool Return true if this code has been revoked - */ - abstract public function isAuthCodeRevoked($codeId); -} diff --git a/src/Repositories/AbstractRefreshTokenRepository.php b/src/Repositories/AbstractRefreshTokenRepository.php deleted file mode 100644 index 04748b2d..00000000 --- a/src/Repositories/AbstractRefreshTokenRepository.php +++ /dev/null @@ -1,53 +0,0 @@ - - * @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\RefreshTokenEntityInterface; -use League\OAuth2\Server\Entities\RefreshTokenEntity; - -/** - * Refresh token abstract class. - */ -abstract class AbstractRefreshTokenRepository implements RefreshTokenRepositoryInterface -{ - /** - * Creates a new refresh token - * - * @return RefreshTokenEntityInterface - */ - public function getNewRefreshToken() - { - return new RefreshTokenEntity(); - } - - /** - * Create a new refresh token_name. - * - * @param \League\OAuth2\Server\Entities\RefreshTokenEntityInterface $refreshTokenEntity - */ - abstract public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity); - - /** - * Revoke the refresh token. - * - * @param string $tokenId - */ - abstract public function revokeRefreshToken($tokenId); - - /** - * Check if the refresh token has been revoked. - * - * @param string $tokenId - * - * @return bool Return true if this token has been revoked - */ - abstract public function isRefreshTokenRevoked($tokenId); -} From 2c2ef800d41c06c0718cdfba3e917841053b8eb6 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 10:46:40 -0400 Subject: [PATCH 376/444] Applied fixes from StyleCI --- src/Grant/AbstractGrant.php | 14 +++++++------- src/Grant/PasswordGrant.php | 2 +- .../AccessTokenRepositoryInterface.php | 2 +- src/Repositories/ScopeRepositoryInterface.php | 6 +++--- src/Repositories/UserRepositoryInterface.php | 6 +++--- tests/Grant/AbstractGrantTest.php | 4 ++-- tests/Grant/AuthCodeGrantTest.php | 6 +++--- tests/Grant/ClientCredentialsGrantTest.php | 2 +- tests/Grant/ImplicitGrantTest.php | 2 +- tests/Grant/PasswordGrantTest.php | 4 ++-- tests/Grant/RefreshTokenGrantTest.php | 4 ++-- .../AuthenticationServerMiddlewareTest.php | 2 +- tests/Middleware/ResourceServerMiddlewareTest.php | 2 +- tests/ResponseTypes/BearerResponseTypeTest.php | 6 +++--- tests/ServerTest.php | 4 ++-- tests/Stubs/ClientEntity.php | 1 - 16 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 0a1cf824..c9cf177e 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -190,9 +190,9 @@ abstract class AbstractGrant implements GrantTypeInterface /** * Validate scopes in the request. * - * @param string $scopes + * @param string $scopes * @param \League\OAuth2\Server\Entities\ClientEntityInterface $client - * @param string $redirectUri + * @param string $redirectUri * * @throws \League\OAuth2\Server\Exception\OAuthServerException * @@ -285,9 +285,9 @@ abstract class AbstractGrant implements GrantTypeInterface /** * Issue an access token. * - * @param \DateInterval $accessTokenTTL + * @param \DateInterval $accessTokenTTL * @param \League\OAuth2\Server\Entities\ClientEntityInterface $client - * @param string $userIdentifier + * @param string $userIdentifier * @param \League\OAuth2\Server\Entities\ScopeEntityInterface[] $scopes * * @return \League\OAuth2\Server\Entities\AccessTokenEntityInterface @@ -316,10 +316,10 @@ abstract class AbstractGrant implements GrantTypeInterface /** * Issue an auth code. * - * @param \DateInterval $authCodeTTL + * @param \DateInterval $authCodeTTL * @param \League\OAuth2\Server\Entities\ClientEntityInterface $client - * @param string $userIdentifier - * @param string $redirectUri + * @param string $userIdentifier + * @param string $redirectUri * @param \League\OAuth2\Server\Entities\ScopeEntityInterface[] $scopes * * @return \League\OAuth2\Server\Entities\AuthCodeEntityInterface diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 2e3dddd0..d41d7f79 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -66,7 +66,7 @@ class PasswordGrant extends AbstractGrant } /** - * @param \Psr\Http\Message\ServerRequestInterface $request + * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\Entities\ClientEntityInterface $client * * @throws \League\OAuth2\Server\Exception\OAuthServerException diff --git a/src/Repositories/AccessTokenRepositoryInterface.php b/src/Repositories/AccessTokenRepositoryInterface.php index 426d71f8..a8655253 100644 --- a/src/Repositories/AccessTokenRepositoryInterface.php +++ b/src/Repositories/AccessTokenRepositoryInterface.php @@ -23,7 +23,7 @@ interface AccessTokenRepositoryInterface extends RepositoryInterface * * @param \League\OAuth2\Server\Entities\ClientEntityInterface $clientEntity * @param \League\OAuth2\Server\Entities\ScopeEntityInterface[] $scopes - * @param mixed $userIdentifier + * @param mixed $userIdentifier * * @return AccessTokenEntityInterface */ diff --git a/src/Repositories/ScopeRepositoryInterface.php b/src/Repositories/ScopeRepositoryInterface.php index 524f1702..a1363c2b 100644 --- a/src/Repositories/ScopeRepositoryInterface.php +++ b/src/Repositories/ScopeRepositoryInterface.php @@ -31,10 +31,10 @@ interface ScopeRepositoryInterface extends RepositoryInterface * Given a client, grant type and optional user identifier validate the set of scopes requested are valid and optionally * append additional scopes or remove requested scopes. * - * @param ScopeEntityInterface[] $scopes - * @param string $grantType + * @param ScopeEntityInterface[] $scopes + * @param string $grantType * @param \League\OAuth2\Server\Entities\ClientEntityInterface $clientEntity - * @param null|string $userIdentifier + * @param null|string $userIdentifier * * @return \League\OAuth2\Server\Entities\ScopeEntityInterface[] */ diff --git a/src/Repositories/UserRepositoryInterface.php b/src/Repositories/UserRepositoryInterface.php index f00436e8..f6745c1d 100644 --- a/src/Repositories/UserRepositoryInterface.php +++ b/src/Repositories/UserRepositoryInterface.php @@ -9,9 +9,9 @@ interface UserRepositoryInterface extends RepositoryInterface /** * Get a user entity. * - * @param string $username - * @param string $password - * @param string $grantType The grant type used + * @param string $username + * @param string $password + * @param string $grantType The grant type used * @param \League\OAuth2\Server\Entities\ClientEntityInterface $clientEntity * * @return \League\OAuth2\Server\Entities\UserEntityInterface diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 559a5269..78957b75 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -13,9 +13,9 @@ 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 LeagueTests\Stubs\ClientEntity; -use LeagueTests\Stubs\AuthCodeEntity; use LeagueTests\Stubs\AccessTokenEntity; +use LeagueTests\Stubs\AuthCodeEntity; +use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\RefreshTokenEntity; use LeagueTests\Stubs\ScopeEntity; use Zend\Diactoros\ServerRequest; diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index b49ecd18..3d1064bf 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -3,11 +3,8 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\CryptKey; -use LeagueTests\Stubs\AccessTokenEntity; -use LeagueTests\Stubs\AuthCodeEntity; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; -use LeagueTests\Stubs\RefreshTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -18,8 +15,11 @@ use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\HtmlResponse; use League\OAuth2\Server\ResponseTypes\RedirectResponse; +use LeagueTests\Stubs\AccessTokenEntity; +use LeagueTests\Stubs\AuthCodeEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\CryptTraitStub; +use LeagueTests\Stubs\RefreshTokenEntity; use LeagueTests\Stubs\ScopeEntity; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; diff --git a/tests/Grant/ClientCredentialsGrantTest.php b/tests/Grant/ClientCredentialsGrantTest.php index dc883a0e..c334228e 100644 --- a/tests/Grant/ClientCredentialsGrantTest.php +++ b/tests/Grant/ClientCredentialsGrantTest.php @@ -2,12 +2,12 @@ namespace LeagueTests\Grant; -use LeagueTests\Stubs\AccessTokenEntity; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; use Zend\Diactoros\ServerRequest; diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 5636de0e..f8d42930 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -3,7 +3,6 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\CryptKey; -use LeagueTests\Stubs\AccessTokenEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ImplicitGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -12,6 +11,7 @@ use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\HtmlResponse; use League\OAuth2\Server\ResponseTypes\RedirectResponse; +use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\CryptTraitStub; use LeagueTests\Stubs\StubResponseType; diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php index f8827720..d8b310af 100644 --- a/tests/Grant/PasswordGrantTest.php +++ b/tests/Grant/PasswordGrantTest.php @@ -2,17 +2,17 @@ namespace LeagueTests\Grant; -use LeagueTests\Stubs\AccessTokenEntity; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; -use LeagueTests\Stubs\RefreshTokenEntity; use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; +use LeagueTests\Stubs\RefreshTokenEntity; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; use Zend\Diactoros\ServerRequest; diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index b19dce9c..d8eb0182 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -3,17 +3,17 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\CryptKey; -use LeagueTests\Stubs\AccessTokenEntity; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; -use LeagueTests\Stubs\RefreshTokenEntity; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\CryptTraitStub; +use LeagueTests\Stubs\RefreshTokenEntity; use LeagueTests\Stubs\ScopeEntity; use LeagueTests\Stubs\StubResponseType; use Zend\Diactoros\ServerRequest; diff --git a/tests/Middleware/AuthenticationServerMiddlewareTest.php b/tests/Middleware/AuthenticationServerMiddlewareTest.php index cbc3cf62..d5f82594 100644 --- a/tests/Middleware/AuthenticationServerMiddlewareTest.php +++ b/tests/Middleware/AuthenticationServerMiddlewareTest.php @@ -2,13 +2,13 @@ namespace LeagueTests\Middleware; -use LeagueTests\Stubs\AccessTokenEntity; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Middleware\AuthenticationServerMiddleware; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Server; +use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; use Zend\Diactoros\Response; diff --git a/tests/Middleware/ResourceServerMiddlewareTest.php b/tests/Middleware/ResourceServerMiddlewareTest.php index a3517d1d..5656d3d1 100644 --- a/tests/Middleware/ResourceServerMiddlewareTest.php +++ b/tests/Middleware/ResourceServerMiddlewareTest.php @@ -3,12 +3,12 @@ namespace LeagueTests\Middleware; use League\OAuth2\Server\CryptKey; -use LeagueTests\Stubs\AccessTokenEntity; use League\OAuth2\Server\Middleware\ResourceServerMiddleware; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Server; +use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; use Zend\Diactoros\Response; diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index d6e75fdf..003b517c 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -2,14 +2,14 @@ namespace LeagueTests\ResponseTypes; +use \Stubs\AccessTokenEntity; use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator; -use League\OAuth2\Server\CryptKey; -use\LeagueTests\Stubs\AccessTokenEntity; -use LeagueTests\Stubs\RefreshTokenEntity; +useLeagueTestsLeague\OAuth2\Server\CryptKey; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use LeagueTests\Stubs\ClientEntity; +use LeagueTests\Stubs\RefreshTokenEntity; use LeagueTests\Stubs\ScopeEntity; use Psr\Http\Message\ResponseInterface; use Zend\Diactoros\Response; diff --git a/tests/ServerTest.php b/tests/ServerTest.php index ec261b6f..68dae3b1 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -2,8 +2,6 @@ namespace LeagueTests; -use LeagueTests\Stubs\AccessTokenEntity; -use LeagueTests\Stubs\AuthCodeEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\ClientCredentialsGrant; @@ -15,6 +13,8 @@ use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use League\OAuth2\Server\Server; +use LeagueTests\Stubs\AccessTokenEntity; +use LeagueTests\Stubs\AuthCodeEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; diff --git a/tests/Stubs/ClientEntity.php b/tests/Stubs/ClientEntity.php index 04fcae75..0c6a4f9b 100644 --- a/tests/Stubs/ClientEntity.php +++ b/tests/Stubs/ClientEntity.php @@ -19,5 +19,4 @@ class ClientEntity implements ClientEntityInterface { $this->name = $name; } - } From 0ca2511d1e62bf2f6752d232451ea18c72a3c57a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 10:46:46 -0400 Subject: [PATCH 377/444] Applied fixes from StyleCI --- tests/ResponseTypes/BearerResponseTypeTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index 003b517c..d52c7169 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -2,16 +2,17 @@ namespace LeagueTests\ResponseTypes; -use \Stubs\AccessTokenEntity; use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator; -useLeagueTestsLeague\OAuth2\Server\CryptKey; use League\OAuth2\Server\Exception\OAuthServerException; + +useLeagueTestsLeague\OAuth2\Server\CryptKey; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\RefreshTokenEntity; use LeagueTests\Stubs\ScopeEntity; use Psr\Http\Message\ResponseInterface; +use Stubs\AccessTokenEntity; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; From 4689802c309b45189f6523f98344cef167a40388 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 16:20:30 +0100 Subject: [PATCH 378/444] Renamed server `respondToRequest` to `respondToAccessTokenRequest` --- examples/public/client_credentials.php | 2 +- examples/public/password.php | 2 +- examples/public/refresh_token.php | 2 +- src/Server.php | 2 +- tests/ServerTest.php | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index 1792eb69..c1ca45f0 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -50,7 +50,7 @@ $app->post('/access_token', function (ServerRequestInterface $request, ResponseI $server = $app->getContainer()->get(Server::class); try { - return $server->respondToRequest($request, $response); + return $server->respondToAccessTokenRequest($request, $response); } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); } catch (\Exception $exception) { diff --git a/examples/public/password.php b/examples/public/password.php index c04c0e91..d8145050 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -54,7 +54,7 @@ $app->post('/access_token', function (ServerRequestInterface $request, ResponseI $server = $app->getContainer()->get(Server::class); try { - return $server->respondToRequest($request, $response); + return $server->respondToAccessTokenRequest($request, $response); } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); } catch (\Exception $exception) { diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index 64553311..c8c0a396 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -52,7 +52,7 @@ $app->post('/access_token', function (ServerRequestInterface $request, ResponseI $server = $app->getContainer()->get(Server::class); try { - return $server->respondToRequest($request, $response); + return $server->respondToAccessTokenRequest($request, $response); } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); } catch (\Exception $exception) { diff --git a/src/Server.php b/src/Server.php index e5573026..3513d642 100644 --- a/src/Server.php +++ b/src/Server.php @@ -134,7 +134,7 @@ class Server implements EmitterAwareInterface * * @return \Psr\Http\Message\ResponseInterface */ - public function respondToRequest(ServerRequestInterface $request, ResponseInterface $response) + public function respondToAccessTokenRequest(ServerRequestInterface $request, ResponseInterface $response) { $tokenResponse = null; while ($tokenResponse === null && $grantType = array_shift($this->enabledGrantTypes)) { diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 68dae3b1..82d07059 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -38,7 +38,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M')); try { - $server->respondToRequest(ServerRequestFactory::fromGlobals(), new Response); + $server->respondToAccessTokenRequest(ServerRequestFactory::fromGlobals(), new Response); } catch (OAuthServerException $e) { $this->assertEquals('unsupported_grant_type', $e->getErrorType()); $this->assertEquals(400, $e->getHttpStatusCode()); @@ -70,7 +70,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase $_POST['grant_type'] = 'client_credentials'; $_POST['client_id'] = 'foo'; $_POST['client_secret'] = 'bar'; - $response = $server->respondToRequest(ServerRequestFactory::fromGlobals(), new Response); + $response = $server->respondToAccessTokenRequest(ServerRequestFactory::fromGlobals(), new Response); $this->assertEquals(200, $response->getStatusCode()); } @@ -119,7 +119,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase $_POST['action'] = 'approve'; $_POST['username'] = 'user'; $_POST['password'] = 'pass'; - $response = $server->respondToRequest(ServerRequestFactory::fromGlobals(), new Response); + $response = $server->respondToAccessTokenRequest(ServerRequestFactory::fromGlobals(), new Response); $this->assertTrue($response instanceof ResponseInterface); $this->assertEquals(302, $response->getStatusCode()); $this->assertTrue(strstr($response->getHeaderLine('location'), 'code=') !== false); From 76ea6b5a6c8a4e83b7b42ac04ec25d04e17c1c9f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 16:22:00 +0100 Subject: [PATCH 379/444] Renamed grant type `canRespondToRequest` to `canRespondToAccessTokenRequest` --- src/Grant/AbstractGrant.php | 2 +- src/Grant/GrantTypeInterface.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index c9cf177e..b7fcda88 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -392,7 +392,7 @@ abstract class AbstractGrant implements GrantTypeInterface /** * {@inheritdoc} */ - public function canRespondToRequest(ServerRequestInterface $request) + public function canRespondToAccessTokenRequest(ServerRequestInterface $request) { $requestParameters = (array) $request->getParsedBody(); diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 0e4ce62d..dd35c6ce 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -64,7 +64,7 @@ interface GrantTypeInterface extends EmitterAwareInterface * * @return bool */ - public function canRespondToRequest(ServerRequestInterface $request); + public function canRespondToAccessTokenRequest(ServerRequestInterface $request); /** * Set the client repository. From 44937f36009407b740596d142b269bf65ca31b24 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 9 Apr 2016 16:22:22 +0100 Subject: [PATCH 380/444] Updated method calls --- src/Middleware/AuthenticationServerMiddleware.php | 2 +- src/Server.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Middleware/AuthenticationServerMiddleware.php b/src/Middleware/AuthenticationServerMiddleware.php index 2d5ffe41..83f3f1c5 100644 --- a/src/Middleware/AuthenticationServerMiddleware.php +++ b/src/Middleware/AuthenticationServerMiddleware.php @@ -34,7 +34,7 @@ class AuthenticationServerMiddleware public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next) { try { - $response = $this->server->respondToRequest($request, $response); + $response = $this->server->respondToAccessTokenRequest($request, $response); } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); // @codeCoverageIgnoreStart diff --git a/src/Server.php b/src/Server.php index 3513d642..ba18ce91 100644 --- a/src/Server.php +++ b/src/Server.php @@ -139,7 +139,7 @@ class Server implements EmitterAwareInterface $tokenResponse = null; while ($tokenResponse === null && $grantType = array_shift($this->enabledGrantTypes)) { /** @var \League\OAuth2\Server\Grant\GrantTypeInterface $grantType */ - if ($grantType->canRespondToRequest($request)) { + if ($grantType->canRespondToAccessTokenRequest($request)) { $tokenResponse = $grantType->respondToRequest( $request, $this->getResponseType(), From b7064befe4f02b6e5b82d2860cc93d619a46457e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 10:07:08 +0100 Subject: [PATCH 381/444] Checkin --- src/Grant/AbstractGrant.php | 27 ++ src/Grant/AuthCodeGrant.php | 328 +++++++++------------- src/Grant/GrantTypeInterface.php | 37 ++- src/Grant/ImplicitGrant.php | 2 +- src/RequestTypes/AuthorizationRequest.php | 165 +++++++++++ src/Server.php | 22 ++ 6 files changed, 378 insertions(+), 203 deletions(-) create mode 100644 src/RequestTypes/AuthorizationRequest.php diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index b7fcda88..739fb1c5 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -23,6 +23,7 @@ use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\RequestEvent; +use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use Psr\Http\Message\ServerRequestInterface; /** @@ -175,11 +176,13 @@ abstract class AbstractGrant implements GrantTypeInterface is_string($client->getRedirectUri()) && (strcmp($client->getRedirectUri(), $redirectUri) !== 0) ) { + $this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request)); throw OAuthServerException::invalidClient(); } elseif ( is_array($client->getRedirectUri()) && in_array($redirectUri, $client->getRedirectUri()) === false ) { + $this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request)); throw OAuthServerException::invalidClient(); } } @@ -401,4 +404,28 @@ abstract class AbstractGrant implements GrantTypeInterface && $requestParameters['grant_type'] === $this->getIdentifier() ); } + + /** + * @inheritdoc + */ + public function canRespondToAuthorizationRequest(ServerRequestInterface $request) + { + return false; + } + + /** + * @inheritdoc + */ + public function validateAuthorizationRequest(ServerRequestInterface $request) + { + throw new \LogicException('This grant cannot validate an authorization request'); + } + + /** + * @inheritdoc + */ + public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest) + { + throw new \LogicException('This grant cannot complete an authorization request'); + } } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 210dc9a1..5178ed5a 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -10,6 +10,7 @@ use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\RequestEvent; +use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\HtmlResponse; use League\OAuth2\Server\ResponseTypes\RedirectResponse; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; @@ -45,191 +46,6 @@ class AuthCodeGrant extends AbstractAuthorizeGrant $this->templateRenderer = $templateRenderer; } - /** - * Respond to an authorization request. - * - * @param \Psr\Http\Message\ServerRequestInterface $request - * - * @throws \League\OAuth2\Server\Exception\OAuthServerException - * - * @return \Psr\Http\Message\ResponseInterface - */ - protected function respondToAuthorizationRequest( - ServerRequestInterface $request - ) { - $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 RequestEvent('client.authentication.failed', $request)); - throw OAuthServerException::invalidClient(); - } - - $redirectUriParameter = $this->getQueryStringParameter('redirect_uri', $request, $client->getRedirectUri()); - if ($redirectUriParameter !== $client->getRedirectUri()) { - $this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request)); - throw OAuthServerException::invalidClient(); - } - - $scopes = $this->validateScopes( - $this->getQueryStringParameter('scope', $request), - $client, - $client->getRedirectUri() - ); - - $postbackUri = 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($this->decrypt($oauthCookie)); - 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, - $this->getIdentifier(), - $client - ); - - 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) { - $html = $this->getTemplateRenderer()->renderLogin([ - 'error' => $loginError, - 'postback_uri' => $this->makeRedirectUri( - $postbackUri, - $request->getQueryParams() - ), - ]); - - $htmlResponse = new HtmlResponse(); - $htmlResponse->setStatusCode(403); - $htmlResponse->setHtml($html); - - return $htmlResponse; - } - - // The user hasn't approved the client yet so show an authorize form - if ($userId !== null && $userHasApprovedClient === null) { - $html = $this->getTemplateRenderer()->renderAuthorize([ - 'client' => $client, - 'scopes' => $scopes, - 'postback_uri' => $this->makeRedirectUri( - $postbackUri, - $request->getQueryParams() - ), - ]); - - $htmlResponse = new HtmlResponse(); - $htmlResponse->setStatusCode(200); - $htmlResponse->setHtml($html); - $htmlResponse->setHeader('set-cookie', sprintf( - 'oauth_authorize_request=%s; Expires=%s', - urlencode($this->encrypt( - json_encode([ - 'user_id' => $userId, - ]) - )), - (new \DateTime())->add(new \DateInterval('PT5M'))->format('D, d M Y H:i:s e') - )); - - return $htmlResponse; - } - - // The user has either approved or denied the client, so redirect them back - $redirectUri = $client->getRedirectUri(); - $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) { - - // Finalize the requested scopes - $scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $userId); - - $authCode = $this->issueAuthCode( - $this->authCodeTTL, - $client, - $userId, - $redirectUri, - $scopes - ); - - $redirectPayload['code'] = $this->encrypt( - json_encode( - [ - 'client_id' => $authCode->getClient()->getIdentifier(), - 'redirect_uri' => $authCode->getRedirectUri(), - 'auth_code_id' => $authCode->getIdentifier(), - 'scopes' => $authCode->getScopes(), - 'user_id' => $authCode->getUserIdentifier(), - 'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'), - ] - ) - ); - - $response = new RedirectResponse(); - $response->setRedirectUri( - $this->makeRedirectUri( - $redirectUri, - $redirectPayload - ) - ); - - return $response; - } - - // The user denied the client, redirect them back with an error - throw OAuthServerException::accessDenied('The user denied the request', (string) $redirectUri); - } - /** * Respond to an access token request. * @@ -324,20 +140,6 @@ class AuthCodeGrant extends AbstractAuthorizeGrant return $this->respondToAccessTokenRequest($request, $responseType, $accessTokenTTL); } - /** - * {@inheritdoc} - */ - public function canRespondToRequest(ServerRequestInterface $request) - { - return - ( - array_key_exists('response_type', $request->getQueryParams()) - && $request->getQueryParams()['response_type'] === 'code' - && isset($request->getQueryParams()['client_id']) - ) - || parent::canRespondToRequest($request); - } - /** * Return the grant identifier that can be used in matching up requests. * @@ -347,4 +149,132 @@ class AuthCodeGrant extends AbstractAuthorizeGrant { return 'authorization_code'; } + + /** + * @inheritdoc + */ + public function canRespondToAuthorizationRequest(ServerRequestInterface $request) + { + return ( + array_key_exists('response_type', $request->getQueryParams()) + && $request->getQueryParams()['response_type'] === 'code' + && isset($request->getQueryParams()['client_id']) + ); + } + + /** + * @inheritdoc + */ + public function validateAuthorizationRequest(ServerRequestInterface $request) + { + $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 RequestEvent('client.authentication.failed', $request)); + throw OAuthServerException::invalidClient(); + } + + $redirectUri = $this->getQueryStringParameter('redirect_uri', $request); + if ($redirectUri !== null) { + if ( + is_string($client->getRedirectUri()) + && (strcmp($client->getRedirectUri(), $redirectUri) !== 0) + ) { + $this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request)); + throw OAuthServerException::invalidClient(); + } elseif ( + is_array($client->getRedirectUri()) + && in_array($redirectUri, $client->getRedirectUri()) === false + ) { + $this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request)); + throw OAuthServerException::invalidClient(); + } + } + + $scopes = $this->validateScopes( + $this->getQueryStringParameter('scope', $request), + $client, + $client->getRedirectUri() + ); + + $stateParameter = $this->getQueryStringParameter('state', $request); + + $authorizationRequest = new AuthorizationRequest(); + $authorizationRequest->setGrantTypeId($this->getIdentifier()); + $authorizationRequest->setClient($client); + $authorizationRequest->setRedirectUri($redirectUri); + $authorizationRequest->setState($stateParameter); + $authorizationRequest->setScopes($scopes); + + return $authorizationRequest; + } + + /** + * @inheritdoc + */ + public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest) + { + if ($authorizationRequest->getUser() instanceof UserEntityInterface === false) { + throw new \LogicException('An instance of UserEntityInterface should be set on the AuthorizationRequest'); + } + + // The user approved the client, redirect them back with an auth code + if ($authorizationRequest->isAuthorizationApproved() === true) { + + $authCode = $this->issueAuthCode( + $this->authCodeTTL, + $authorizationRequest->getClient(), + $authorizationRequest->getUser()->getIdentifier(), + $authorizationRequest->getRedirectUri(), + $authorizationRequest->getScopes() + ); + + $redirectPayload['code'] = $this->encrypt( + json_encode( + [ + 'client_id' => $authCode->getClient()->getIdentifier(), + 'redirect_uri' => $authCode->getRedirectUri(), + 'auth_code_id' => $authCode->getIdentifier(), + 'scopes' => $authCode->getScopes(), + 'user_id' => $authCode->getUserIdentifier(), + 'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'), + ] + ) + ); + + $finalRedirectUri = ($authorizationRequest->getRedirectUri() === null) + ? is_array($authorizationRequest->getClient()->getRedirectUri()) + ? $authorizationRequest->getClient()->getRedirectUri()[0] + : $authorizationRequest->getClient()->getRedirectUri() + : $authorizationRequest->getRedirectUri(); + + $response = new RedirectResponse(); + $response->setRedirectUri( + $this->makeRedirectUri( + $finalRedirectUri, + $redirectPayload + ) + ); + + return $response; + } + + // The user denied the client, redirect them back with an error + throw OAuthServerException::accessDenied( + 'The user denied the request', + (string) $authorizationRequest->getRedirectUri() + ); + } } diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index dd35c6ce..fc26d925 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -15,6 +15,7 @@ use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ServerRequestInterface; @@ -52,14 +53,44 @@ interface GrantTypeInterface extends EmitterAwareInterface \DateInterval $accessTokenTTL ); + /** + * The grant type should return true if it is able to response to an authorization request + * + * @param \Psr\Http\Message\ServerRequestInterface $request + * + * @return bool + */ + public function canRespondToAuthorizationRequest(ServerRequestInterface $request); + + /** + * If the grant can respond to an authorization request this method should be called to validate the parameters of + * the request. + * + * If the validation is successful an AuthorizationRequest object will be returned. This object can be safely + * serialized in a user's session, and can be used during user authentication and authorization. + * + * @param \Psr\Http\Message\ServerRequestInterface $request + * + * @return AuthorizationRequest + */ + public function validateAuthorizationRequest(ServerRequestInterface $request); + + /** + * Once a user has authenticated and authorized the client the grant can complete the authorization request. + * The AuthorizationRequest object's $userId property must be set to the authenticated user and the + * $authorizationApproved property must reflect their desire to authorize or deny the client. + * + * @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authorizationRequest + * + * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface + */ + public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest); + /** * The grant type should return true if it is able to respond to this request. * * For example most grant types will check that the $_POST['grant_type'] property matches it's identifier property. * - * Some grants, such as the authorization code grant can respond to multiple requests - * - i.e. a client requesting an authorization code and requesting an access token - * * @param \Psr\Http\Message\ServerRequestInterface $request * * @return bool diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index fefc7189..497542d5 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -29,7 +29,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant /** * {@inheritdoc} */ - public function canRespondToRequest(ServerRequestInterface $request) + public function canRespondToAccessTokenRequest(ServerRequestInterface $request) { return (array_key_exists('response_type', $request->getQueryParams()) && $request->getQueryParams()['response_type'] === 'token'); diff --git a/src/RequestTypes/AuthorizationRequest.php b/src/RequestTypes/AuthorizationRequest.php new file mode 100644 index 00000000..06a06672 --- /dev/null +++ b/src/RequestTypes/AuthorizationRequest.php @@ -0,0 +1,165 @@ +grantTypeId; + } + + /** + * @param string $grantTypeId + */ + public function setGrantTypeId($grantTypeId) + { + $this->grantTypeId = $grantTypeId; + } + + /** + * @return ClientEntityInterface + */ + public function getClient() + { + return $this->client; + } + + /** + * @param ClientEntityInterface $client + */ + public function setClient(ClientEntityInterface $client) + { + $this->client = $client; + } + + /** + * @return UserEntityInterface + */ + public function getUser() + { + return $this->user; + } + + /** + * @param UserEntityInterface $user + */ + public function setUser(UserEntityInterface $user) + { + $this->user = $user; + } + + /** + * @return \League\OAuth2\Server\Entities\ScopeEntityInterface[] + */ + public function getScopes() + { + return $this->scopes; + } + + /** + * @param \League\OAuth2\Server\Entities\ScopeEntityInterface[] $scopes + */ + public function setScopes($scopes) + { + $this->scopes = $scopes; + } + + /** + * @return boolean + */ + public function isAuthorizationApproved() + { + return $this->authorizationApproved; + } + + /** + * @param boolean $authorizationApproved + */ + public function setAuthorizationApproved($authorizationApproved) + { + $this->authorizationApproved = $authorizationApproved; + } + + /** + * @return string + */ + public function getRedirectUri() + { + return $this->redirectUri; + } + + /** + * @param string $redirectUri + */ + public function setRedirectUri($redirectUri) + { + $this->redirectUri = $redirectUri; + } + + /** + * @return string + */ + public function getState() + { + return $this->state; + } + + /** + * @param string $state + */ + public function setState($state) + { + $this->state = $state; + } + +} diff --git a/src/Server.php b/src/Server.php index ba18ce91..1dfc1312 100644 --- a/src/Server.php +++ b/src/Server.php @@ -124,6 +124,28 @@ class Server implements EmitterAwareInterface $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL; } + /** + * @param \Psr\Http\Message\ServerRequestInterface $request + * + * @throws \League\OAuth2\Server\Exception\OAuthServerException + */ + public function respondToAuthorizationRequest(ServerRequestInterface $request) + { + $authRequest = null; + while ($authRequest === null && $grantType = array_shift($this->enabledGrantTypes)) { + /** @var \League\OAuth2\Server\Grant\GrantTypeInterface $grantType */ + if ($grantType->canRespondToAccessTokenRequest($request)) { + $authRequest = $grantType->respondToRequest( + $request, + $this->getResponseType(), + $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] + ); + } + } + + throw OAuthServerException::unsupportedGrantType(); + } + /** * Return an access token response. * From 5410a42bb66f5a61969c3ec1a8e7ab30d225875c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 10:28:12 +0100 Subject: [PATCH 382/444] Fix to broken methods --- src/Grant/ClientCredentialsGrant.php | 2 +- src/Grant/GrantTypeInterface.php | 2 +- src/Grant/PasswordGrant.php | 2 +- src/Grant/RefreshTokenGrant.php | 2 +- tests/Grant/AbstractGrantTest.php | 2 +- tests/Grant/ClientCredentialsGrantTest.php | 2 +- tests/Grant/PasswordGrantTest.php | 8 ++++---- tests/Grant/RefreshTokenGrantTest.php | 16 ++++++++-------- tests/ResponseTypes/BearerResponseTypeTest.php | 4 ++-- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 21673f78..49493372 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -21,7 +21,7 @@ class ClientCredentialsGrant extends AbstractGrant /** * {@inheritdoc} */ - public function respondToRequest( + public function respondToAccessTokenRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, \DateInterval $accessTokenTTL diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index fc26d925..c0ffdd9c 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -47,7 +47,7 @@ interface GrantTypeInterface extends EmitterAwareInterface * * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface */ - public function respondToRequest( + public function respondToAccessTokenRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, \DateInterval $accessTokenTTL diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index d41d7f79..29262306 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -41,7 +41,7 @@ class PasswordGrant extends AbstractGrant /** * {@inheritdoc} */ - public function respondToRequest( + public function respondToAccessTokenRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, \DateInterval $accessTokenTTL diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index be0bb79a..43249647 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -34,7 +34,7 @@ class RefreshTokenGrant extends AbstractGrant /** * {@inheritdoc} */ - public function respondToRequest( + public function respondToAccessTokenRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, \DateInterval $accessTokenTTL diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 78957b75..27fe44d5 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -250,7 +250,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase 'grant_type' => 'foobar', ]); - $this->assertTrue($grantMock->canRespondToRequest($serverRequest)); + $this->assertTrue($grantMock->canRespondToAccessTokenRequest($serverRequest)); } public function testIssueRefreshToken() diff --git a/tests/Grant/ClientCredentialsGrantTest.php b/tests/Grant/ClientCredentialsGrantTest.php index c334228e..a1665831 100644 --- a/tests/Grant/ClientCredentialsGrantTest.php +++ b/tests/Grant/ClientCredentialsGrantTest.php @@ -47,7 +47,7 @@ class ClientCredentialsGrantTest extends \PHPUnit_Framework_TestCase ); $responseType = new StubResponseType(); - $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + $grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M')); $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); } diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php index d8b310af..20f2ce2b 100644 --- a/tests/Grant/PasswordGrantTest.php +++ b/tests/Grant/PasswordGrantTest.php @@ -65,7 +65,7 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase ); $responseType = new StubResponseType(); - $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + $grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M')); $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); $this->assertTrue($responseType->getRefreshToken() instanceof RefreshTokenEntityInterface); @@ -99,7 +99,7 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase ); $responseType = new StubResponseType(); - $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + $grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M')); } /** @@ -131,7 +131,7 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase ); $responseType = new StubResponseType(); - $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + $grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M')); } /** @@ -165,6 +165,6 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase ); $responseType = new StubResponseType(); - $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + $grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M')); } } diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index d8eb0182..af3d477f 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -91,7 +91,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase ); $responseType = new StubResponseType(); - $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + $grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M')); $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); $this->assertTrue($responseType->getRefreshToken() instanceof RefreshTokenEntityInterface); @@ -148,7 +148,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase ); $responseType = new StubResponseType(); - $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + $grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M')); $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); $this->assertTrue($responseType->getRefreshToken() instanceof RefreshTokenEntityInterface); @@ -207,7 +207,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase ); $responseType = new StubResponseType(); - $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + $grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M')); } /** @@ -239,7 +239,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase ); $responseType = new StubResponseType(); - $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + $grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M')); } /** @@ -274,7 +274,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase ); $responseType = new StubResponseType(); - $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + $grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M')); } /** @@ -324,7 +324,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase ); $responseType = new StubResponseType(); - $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + $grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M')); } /** @@ -370,7 +370,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase ); $responseType = new StubResponseType(); - $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + $grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M')); } /** @@ -417,6 +417,6 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase ); $responseType = new StubResponseType(); - $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + $grant->respondToAccessTokenRequest($serverRequest, $responseType, new \DateInterval('PT5M')); } } diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index d52c7169..1014aa73 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -5,14 +5,14 @@ namespace LeagueTests\ResponseTypes; use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator; use League\OAuth2\Server\Exception\OAuthServerException; -useLeagueTestsLeague\OAuth2\Server\CryptKey; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\RefreshTokenEntity; use LeagueTests\Stubs\ScopeEntity; use Psr\Http\Message\ResponseInterface; -use Stubs\AccessTokenEntity; +use LeagueTests\Stubs\AccessTokenEntity; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; From 8f5e0ce9f70ef87285c29da9f3b4ac2284d577a2 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 11:45:59 +0100 Subject: [PATCH 383/444] Update example composer --- examples/composer.json | 2 +- examples/composer.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/composer.json b/examples/composer.json index f0bf2564..c601e3d1 100644 --- a/examples/composer.json +++ b/examples/composer.json @@ -7,7 +7,7 @@ ], "require": { "slim/slim": "3.0.*", - "league/oauth2-server": "dev-V5-WIP", + "league/oauth2-server": "dev-V5-authorization-request-flow", "league/plates": "^3.1" }, "autoload": { diff --git a/examples/composer.lock b/examples/composer.lock index a5a93bbd..38924cca 100644 --- a/examples/composer.lock +++ b/examples/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "143453cc35e7f499b130b6460222dc5a", - "content-hash": "1ea46581fb6db25f323a37a45ef74f95", + "hash": "ec2df46ff78a00052e1a241ce5988d81", + "content-hash": "46a1c1e42c62d3e3645279fc54ae95b7", "packages": [ { "name": "container-interop/container-interop", @@ -36,16 +36,16 @@ }, { "name": "lcobucci/jwt", - "version": "3.1.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/lcobucci/jwt.git", - "reference": "31499db4e692b343cec7ff345932899f98fde1cf" + "reference": "afea8e682e911a21574fd8519321b32522fa25b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/jwt/zipball/31499db4e692b343cec7ff345932899f98fde1cf", - "reference": "31499db4e692b343cec7ff345932899f98fde1cf", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/afea8e682e911a21574fd8519321b32522fa25b5", + "reference": "afea8e682e911a21574fd8519321b32522fa25b5", "shasum": "" }, "require": { @@ -90,7 +90,7 @@ "JWS", "jwt" ], - "time": "2015-11-15 01:42:47" + "time": "2016-03-24 22:46:13" }, { "name": "league/event", @@ -144,11 +144,11 @@ }, { "name": "league/oauth2-server", - "version": "dev-V5-WIP", + "version": "dev-V5-authorization-request-flow", "dist": { "type": "path", "url": "../", - "reference": "0fbe109e2004c71feac2bd14fd85aff97704b2e5", + "reference": "5410a42bb66f5a61969c3ec1a8e7ab30d225875c", "shasum": null }, "require": { From 3f6e91575d004957301d872fe1be609aacc283e0 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 11:47:09 +0100 Subject: [PATCH 384/444] Updated auth code example --- examples/public/auth_code.php | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index 824b72d6..1e517e13 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -2,7 +2,9 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; +use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\Server; +use OAuth2ServerExamples\Entities\UserEntity; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\AuthCodeRepository; use OAuth2ServerExamples\Repositories\ClientRepository; @@ -56,18 +58,29 @@ $app = new App([ }, ]); -$app->any('/authorize', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { +$app->get('/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); + // Validate the HTTP request and return an AuthorizationRequest object. + // The auth request object can be serialized into a user's session + $authRequest = $server->validateAuthorizationRequest($request); + + // Once the user has logged in set the user on the AuthorizationRequest + $authRequest->setUser(new UserEntity()); + + // Once the user has approved or denied the client update the status + // (true = approved, false = denied) + $authRequest->setAuthorizationApproved(true); + + // Return the HTTP redirect response + return $server->completeAuthorizationRequest($authRequest, $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); } }); @@ -77,7 +90,7 @@ $app->post('/access_token', function (ServerRequestInterface $request, ResponseI $server = $app->getContainer()->get(Server::class); try { - return $server->respondToRequest($request, $response); + return $server->respondToAccessTokenRequest($request, $response); } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); } catch (\Exception $exception) { From 651709b70fa070428d08c3d00c23052b641d4109 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 11:47:15 +0100 Subject: [PATCH 385/444] Added helper methods --- examples/src/Entities/ClientEntity.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/examples/src/Entities/ClientEntity.php b/examples/src/Entities/ClientEntity.php index 36262646..6a495cdb 100644 --- a/examples/src/Entities/ClientEntity.php +++ b/examples/src/Entities/ClientEntity.php @@ -9,4 +9,14 @@ use League\OAuth2\Server\Entities\Traits\EntityTrait; class ClientEntity implements ClientEntityInterface { use EntityTrait, ClientTrait; + + public function setName($name) + { + $this->name = $name; + } + + public function setRedirectUri($uri) + { + $this->redirectUri = $uri; + } } From 6f71a2d178f2a3095e94892679decdb08775a910 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 11:47:28 +0100 Subject: [PATCH 386/444] Remove unnecessary call --- examples/src/Repositories/ClientRepository.php | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/src/Repositories/ClientRepository.php b/examples/src/Repositories/ClientRepository.php index 4727871b..7cd78ca1 100644 --- a/examples/src/Repositories/ClientRepository.php +++ b/examples/src/Repositories/ClientRepository.php @@ -29,7 +29,6 @@ class ClientRepository implements ClientRepositoryInterface $client->setIdentifier($clientIdentifier); $client->setName($clients[$clientIdentifier]['name']); $client->setRedirectUri($clients[$clientIdentifier]['redirect_uri']); - $client->setSecret($clients[$clientIdentifier]['secret']); return $client; } From fdb1d70874c7196e45e39a6b7c1c983a813e10cb Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 11:47:41 +0100 Subject: [PATCH 387/444] Updated header key --- src/ResponseTypes/RedirectResponse.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ResponseTypes/RedirectResponse.php b/src/ResponseTypes/RedirectResponse.php index d37e58e6..575a49e7 100644 --- a/src/ResponseTypes/RedirectResponse.php +++ b/src/ResponseTypes/RedirectResponse.php @@ -26,6 +26,6 @@ class RedirectResponse extends AbstractResponseType */ public function generateHttpResponse(ResponseInterface $response) { - return $response->withStatus(302)->withHeader('location', $this->redirectUri); + return $response->withStatus(302)->withHeader('Location', $this->redirectUri); } } From 4bc835c007ff3264b5e6a251566a6b3a71248675 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 11:48:21 +0100 Subject: [PATCH 388/444] Updated AuthCodeGrant with new methods to validate and complete an authorization request --- src/Grant/AuthCodeGrant.php | 49 ++++++++++++------------------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 5178ed5a..6f580168 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -11,7 +11,6 @@ use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\RequestEvent; use League\OAuth2\Server\RequestTypes\AuthorizationRequest; -use League\OAuth2\Server\ResponseTypes\HtmlResponse; use League\OAuth2\Server\ResponseTypes\RedirectResponse; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\TemplateRenderer\RendererInterface; @@ -57,17 +56,11 @@ class AuthCodeGrant extends AbstractAuthorizeGrant * * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface */ - protected function respondToAccessTokenRequest( + public 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); @@ -91,6 +84,12 @@ class AuthCodeGrant extends AbstractAuthorizeGrant throw OAuthServerException::invalidRequest('code', 'Authorization code was not issued to this client'); } + // The redirect URI is required in this request + $redirectUri = $this->getRequestParameter('redirect_uri', $request, null); + if (empty($authCodePayload->redirect_uri) === false && $redirectUri === null) { + throw OAuthServerException::invalidRequest('redirect_uri'); + } + if ($authCodePayload->redirect_uri !== $redirectUri) { throw OAuthServerException::invalidRequest('redirect_uri', 'Invalid redirect URI'); } @@ -99,7 +98,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant foreach ($authCodePayload->scopes as $scopeId) { $scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeId); - if (!$scope) { + if ($scope === false) { // @codeCoverageIgnoreStart throw OAuthServerException::invalidScope($scopeId); // @codeCoverageIgnoreEnd @@ -122,24 +121,6 @@ class AuthCodeGrant extends AbstractAuthorizeGrant return $responseType; } - /** - * {@inheritdoc} - */ - public function respondToRequest( - ServerRequestInterface $request, - ResponseTypeInterface $responseType, - \DateInterval $accessTokenTTL - ) { - if ( - array_key_exists('response_type', $request->getQueryParams()) - && $request->getQueryParams()['response_type'] === 'code' - ) { - return $this->respondToAuthorizationRequest($request); - } - - return $this->respondToAccessTokenRequest($request, $responseType, $accessTokenTTL); - } - /** * Return the grant identifier that can be used in matching up requests. * @@ -230,6 +211,12 @@ class AuthCodeGrant extends AbstractAuthorizeGrant throw new \LogicException('An instance of UserEntityInterface should be set on the AuthorizationRequest'); } + $finalRedirectUri = ($authorizationRequest->getRedirectUri() === null) + ? is_array($authorizationRequest->getClient()->getRedirectUri()) + ? $authorizationRequest->getClient()->getRedirectUri()[0] + : $authorizationRequest->getClient()->getRedirectUri() + : $authorizationRequest->getRedirectUri(); + // The user approved the client, redirect them back with an auth code if ($authorizationRequest->isAuthorizationApproved() === true) { @@ -254,12 +241,6 @@ class AuthCodeGrant extends AbstractAuthorizeGrant ) ); - $finalRedirectUri = ($authorizationRequest->getRedirectUri() === null) - ? is_array($authorizationRequest->getClient()->getRedirectUri()) - ? $authorizationRequest->getClient()->getRedirectUri()[0] - : $authorizationRequest->getClient()->getRedirectUri() - : $authorizationRequest->getRedirectUri(); - $response = new RedirectResponse(); $response->setRedirectUri( $this->makeRedirectUri( @@ -274,7 +255,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant // The user denied the client, redirect them back with an error throw OAuthServerException::accessDenied( 'The user denied the request', - (string) $authorizationRequest->getRedirectUri() + $finalRedirectUri ); } } From d4fb00628e1dc9c19e1c03d5318b12f19086e3c6 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 11:48:32 +0100 Subject: [PATCH 389/444] Updated server methods --- src/Server.php | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/Server.php b/src/Server.php index 1dfc1312..f6c388c7 100644 --- a/src/Server.php +++ b/src/Server.php @@ -12,6 +12,7 @@ use League\OAuth2\Server\Grant\GrantTypeInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ResponseInterface; @@ -125,27 +126,44 @@ class Server implements EmitterAwareInterface } /** + * Validate an authorization request + * * @param \Psr\Http\Message\ServerRequestInterface $request * + * @return \League\OAuth2\Server\RequestTypes\AuthorizationRequest|null * @throws \League\OAuth2\Server\Exception\OAuthServerException */ - public function respondToAuthorizationRequest(ServerRequestInterface $request) + public function validateAuthorizationRequest(ServerRequestInterface $request) { $authRequest = null; - while ($authRequest === null && $grantType = array_shift($this->enabledGrantTypes)) { + $enabledGrantTypes = $this->enabledGrantTypes; + while ($authRequest === null && $grantType = array_shift($enabledGrantTypes)) { /** @var \League\OAuth2\Server\Grant\GrantTypeInterface $grantType */ - if ($grantType->canRespondToAccessTokenRequest($request)) { - $authRequest = $grantType->respondToRequest( - $request, - $this->getResponseType(), - $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] - ); + if ($grantType->canRespondToAuthorizationRequest($request)) { + $authRequest = $grantType->validateAuthorizationRequest($request); + + return $authRequest; } } - + throw OAuthServerException::unsupportedGrantType(); } + /** + * Complete an authorization request + * + * @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest + * @param \Psr\Http\Message\ResponseInterface $response + * + * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface + */ + public function completeAuthorizationRequest(AuthorizationRequest $authRequest, ResponseInterface $response) + { + return $this->enabledGrantTypes[$authRequest->getGrantTypeId()] + ->completeAuthorizationRequest($authRequest) + ->generateHttpResponse($response); + } + /** * Return an access token response. * @@ -162,7 +180,7 @@ class Server implements EmitterAwareInterface while ($tokenResponse === null && $grantType = array_shift($this->enabledGrantTypes)) { /** @var \League\OAuth2\Server\Grant\GrantTypeInterface $grantType */ if ($grantType->canRespondToAccessTokenRequest($request)) { - $tokenResponse = $grantType->respondToRequest( + $tokenResponse = $grantType->respondToAccessTokenRequest( $request, $this->getResponseType(), $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] From 5d3516c7b488d5ba498d62e55cd50978ee7959c7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 06:48:46 -0400 Subject: [PATCH 390/444] Applied fixes from StyleCI --- examples/public/auth_code.php | 1 + src/Grant/AbstractGrant.php | 6 +++--- src/Grant/AuthCodeGrant.php | 7 +++---- src/RequestTypes/AuthorizationRequest.php | 12 +++++++++--- src/Server.php | 3 ++- tests/ResponseTypes/BearerResponseTypeTest.php | 5 ++--- 6 files changed, 20 insertions(+), 14 deletions(-) diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index 1e517e13..12f7cc49 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -81,6 +81,7 @@ $app->get('/authorize', function (ServerRequestInterface $request, ResponseInter } catch (\Exception $exception) { $body = new Stream('php://temp', 'r+'); $body->write($exception->getMessage()); + return $response->withStatus(500)->withBody($body); } }); diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 739fb1c5..e2caed89 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -406,7 +406,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function canRespondToAuthorizationRequest(ServerRequestInterface $request) { @@ -414,7 +414,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function validateAuthorizationRequest(ServerRequestInterface $request) { @@ -422,7 +422,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest) { diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 6f580168..a4cf5dd1 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -132,7 +132,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function canRespondToAuthorizationRequest(ServerRequestInterface $request) { @@ -144,7 +144,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function validateAuthorizationRequest(ServerRequestInterface $request) { @@ -203,7 +203,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest) { @@ -219,7 +219,6 @@ class AuthCodeGrant extends AbstractAuthorizeGrant // The user approved the client, redirect them back with an auth code if ($authorizationRequest->isAuthorizationApproved() === true) { - $authCode = $this->issueAuthCode( $this->authCodeTTL, $authorizationRequest->getClient(), diff --git a/src/RequestTypes/AuthorizationRequest.php b/src/RequestTypes/AuthorizationRequest.php index 06a06672..031c58b2 100644 --- a/src/RequestTypes/AuthorizationRequest.php +++ b/src/RequestTypes/AuthorizationRequest.php @@ -10,42 +10,49 @@ class AuthorizationRequest { /** * The grant type identifier + * * @var string */ protected $grantTypeId; /** * The client identifier + * * @var ClientEntityInterface */ protected $client; /** * The user identifier + * * @var UserEntityInterface */ protected $user; /** * An array of scope identifiers + * * @var ScopeEntityInterface[] */ protected $scopes = []; /** * Has the user authorized the authorization request + * * @var bool */ protected $authorizationApproved = false; /** * The redirect URI used in the request + * * @var string */ protected $redirectUri; /** * The state parameter on the authorization request + * * @var string */ protected $state; @@ -115,7 +122,7 @@ class AuthorizationRequest } /** - * @return boolean + * @return bool */ public function isAuthorizationApproved() { @@ -123,7 +130,7 @@ class AuthorizationRequest } /** - * @param boolean $authorizationApproved + * @param bool $authorizationApproved */ public function setAuthorizationApproved($authorizationApproved) { @@ -161,5 +168,4 @@ class AuthorizationRequest { $this->state = $state; } - } diff --git a/src/Server.php b/src/Server.php index f6c388c7..48448b5e 100644 --- a/src/Server.php +++ b/src/Server.php @@ -130,8 +130,9 @@ class Server implements EmitterAwareInterface * * @param \Psr\Http\Message\ServerRequestInterface $request * - * @return \League\OAuth2\Server\RequestTypes\AuthorizationRequest|null * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \League\OAuth2\Server\RequestTypes\AuthorizationRequest|null */ public function validateAuthorizationRequest(ServerRequestInterface $request) { diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index 1014aa73..6c84e148 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -3,16 +3,15 @@ namespace LeagueTests\ResponseTypes; use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator; -use League\OAuth2\Server\Exception\OAuthServerException; - use League\OAuth2\Server\CryptKey; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; +use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\RefreshTokenEntity; use LeagueTests\Stubs\ScopeEntity; use Psr\Http\Message\ResponseInterface; -use LeagueTests\Stubs\AccessTokenEntity; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; From c75d0e0f0ed3e24529efc9e90cc6c42e30ac9800 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 11:52:18 +0100 Subject: [PATCH 391/444] Removed templating code --- src/Grant/AbstractAuthorizeGrant.php | 35 ---------- src/TemplateRenderer/AbstractRenderer.php | 70 ------------------- .../DefaultTemplates/authorize_client.php | 35 ---------- .../DefaultTemplates/login_user.php | 35 ---------- src/TemplateRenderer/MustacheRenderer.php | 41 ----------- src/TemplateRenderer/PlatesRenderer.php | 47 ------------- src/TemplateRenderer/RendererInterface.php | 24 ------- src/TemplateRenderer/SmartyRenderer.php | 49 ------------- src/TemplateRenderer/TwigRenderer.php | 41 ----------- 9 files changed, 377 deletions(-) delete mode 100644 src/TemplateRenderer/AbstractRenderer.php delete mode 100644 src/TemplateRenderer/DefaultTemplates/authorize_client.php delete mode 100644 src/TemplateRenderer/DefaultTemplates/login_user.php delete mode 100644 src/TemplateRenderer/MustacheRenderer.php delete mode 100644 src/TemplateRenderer/PlatesRenderer.php delete mode 100644 src/TemplateRenderer/RendererInterface.php delete mode 100644 src/TemplateRenderer/SmartyRenderer.php delete mode 100644 src/TemplateRenderer/TwigRenderer.php diff --git a/src/Grant/AbstractAuthorizeGrant.php b/src/Grant/AbstractAuthorizeGrant.php index aa578335..4d086711 100644 --- a/src/Grant/AbstractAuthorizeGrant.php +++ b/src/Grant/AbstractAuthorizeGrant.php @@ -11,45 +11,10 @@ namespace League\OAuth2\Server\Grant; -use League\OAuth2\Server\TemplateRenderer\PlatesRenderer; -use League\OAuth2\Server\TemplateRenderer\RendererInterface; use League\Plates\Engine; abstract class AbstractAuthorizeGrant extends AbstractGrant { - /** - * @var \League\OAuth2\Server\TemplateRenderer\RendererInterface - */ - protected $templateRenderer; - - /** - * Set the template renderer - * - * @param RendererInterface $templateRenderer - */ - public function setTemplateRenderer(RendererInterface $templateRenderer) - { - $this->templateRenderer = $templateRenderer; - } - - /** - * Retrieve template renderer. - * - * @return \League\OAuth2\Server\TemplateRenderer\RendererInterface - */ - protected function getTemplateRenderer() - { - if (!$this->templateRenderer instanceof RendererInterface) { - $this->templateRenderer = new PlatesRenderer( - new Engine(__DIR__ . '/../TemplateRenderer/DefaultTemplates'), - 'login_user', - 'authorize_client' - ); - } - - return $this->templateRenderer; - } - /** * @param string $uri * @param array $params diff --git a/src/TemplateRenderer/AbstractRenderer.php b/src/TemplateRenderer/AbstractRenderer.php deleted file mode 100644 index 0dc3e1ae..00000000 --- a/src/TemplateRenderer/AbstractRenderer.php +++ /dev/null @@ -1,70 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * - * @link https://github.com/thephpleague/oauth2-server - */ -namespace League\OAuth2\Server\TemplateRenderer; - -abstract class AbstractRenderer implements RendererInterface -{ - /** - * @var string - */ - protected $loginTemplate; - - /** - * @var string - */ - protected $authorizeTemplate; - - /** - * PlatesRenderer constructor. - * - * @param string $loginTemplate - * @param string $authorizeTemplate - */ - public function __construct($loginTemplate, $authorizeTemplate) - { - $this->loginTemplate = $loginTemplate; - $this->authorizeTemplate = $authorizeTemplate; - } - - /** - * Render login template. - * - * @param array $data - * - * @return string - */ - public function renderLogin(array $data = []) - { - return $this->render($this->loginTemplate, $data); - } - - /** - * Render authorize template. - * - * @param array $data - * - * @return string - */ - public function renderAuthorize(array $data = []) - { - return $this->render($this->authorizeTemplate, $data); - } - - /** - * Render template. - * - * @param string $template - * @param array $data - * - * @return string - */ - abstract protected function render($template, array $data = []); -} diff --git a/src/TemplateRenderer/DefaultTemplates/authorize_client.php b/src/TemplateRenderer/DefaultTemplates/authorize_client.php deleted file mode 100644 index 81587174..00000000 --- a/src/TemplateRenderer/DefaultTemplates/authorize_client.php +++ /dev/null @@ -1,35 +0,0 @@ - - - - - Authorize <?=$this->e($client->getName())?> - - - - -

- Authorize e($client->getName())?> -

- -

- Do you want to authorize e($client->getName())?> to access the following data? -

- -
    - -
  • getIdentifier()?>
  • - -
- -
- - -
- -
- - -
- - - \ No newline at end of file diff --git a/src/TemplateRenderer/DefaultTemplates/login_user.php b/src/TemplateRenderer/DefaultTemplates/login_user.php deleted file mode 100644 index 75b6b529..00000000 --- a/src/TemplateRenderer/DefaultTemplates/login_user.php +++ /dev/null @@ -1,35 +0,0 @@ - - - - - Login - - - - -

Login

- - -
- e($error)?> -
- - -
- - - - -
- - - - -
- - - -
- - - \ No newline at end of file diff --git a/src/TemplateRenderer/MustacheRenderer.php b/src/TemplateRenderer/MustacheRenderer.php deleted file mode 100644 index fbc0abe9..00000000 --- a/src/TemplateRenderer/MustacheRenderer.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * - * @link https://github.com/thephpleague/oauth2-server - */ -namespace League\OAuth2\Server\TemplateRenderer; - -class MustacheRenderer extends AbstractRenderer -{ - /** - * @var \Mustache_Engine - */ - private $engine; - - /** - * PlatesRenderer constructor. - * - * @param \Mustache_Engine $engine - * @param string $loginTemplate - * @param string $authorizeTemplate - */ - public function __construct(\Mustache_Engine $engine, $loginTemplate, $authorizeTemplate) - { - parent::__construct($loginTemplate, $authorizeTemplate); - - $this->engine = $engine; - } - - /** - * {@inheritdoc} - */ - public function render($template, array $data = []) - { - return $this->engine->render($template, $data); - } -} diff --git a/src/TemplateRenderer/PlatesRenderer.php b/src/TemplateRenderer/PlatesRenderer.php deleted file mode 100644 index 6cd4a77b..00000000 --- a/src/TemplateRenderer/PlatesRenderer.php +++ /dev/null @@ -1,47 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * - * @link https://github.com/thephpleague/oauth2-server - */ -namespace League\OAuth2\Server\TemplateRenderer; - -use League\Plates\Engine; - -class PlatesRenderer extends AbstractRenderer -{ - /** - * @var \League\Plates\Engine - */ - private $engine; - - /** - * PlatesRenderer constructor. - * - * @param \League\Plates\Engine $engine - * @param string $loginTemplate - * @param string $authorizeTemplate - */ - public function __construct(Engine $engine, $loginTemplate, $authorizeTemplate) - { - parent::__construct($loginTemplate, $authorizeTemplate); - - $this->engine = $engine; - } - - /** - * {@inheritdoc} - */ - protected function render($template, array $data = []) - { - if ($this->engine->getFileExtension()) { - $template = preg_replace(sprintf('/\.%s$/', $this->engine->getFileExtension()), '', $template); - } - - return $this->engine->render($template, $data); - } -} diff --git a/src/TemplateRenderer/RendererInterface.php b/src/TemplateRenderer/RendererInterface.php deleted file mode 100644 index 74d9b48f..00000000 --- a/src/TemplateRenderer/RendererInterface.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * - * @link https://github.com/thephpleague/oauth2-server - */ -namespace League\OAuth2\Server\TemplateRenderer; - -class SmartyRenderer extends AbstractRenderer -{ - /** - * Smarty class. - * - * @var \Smarty - */ - private $smarty; - - /** - * PlatesRenderer constructor. - * - * @param \Smarty $smarty - * @param string $loginTemplate - * @param string $authorizeTemplate - */ - public function __construct(\Smarty $smarty, $loginTemplate, $authorizeTemplate) - { - parent::__construct($loginTemplate, $authorizeTemplate); - - $this->smarty = $smarty; - } - - /** - * {@inheritdoc} - */ - protected function render($template, array $data = []) - { - $this->smarty->assign($data); - - $output = $this->smarty->fetch($template); - - $this->smarty->clear_assign(array_keys($data)); - - return $output; - } -} diff --git a/src/TemplateRenderer/TwigRenderer.php b/src/TemplateRenderer/TwigRenderer.php deleted file mode 100644 index e4e0c13d..00000000 --- a/src/TemplateRenderer/TwigRenderer.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @copyright Copyright (c) Alex Bilbie - * @license http://mit-license.org/ - * - * @link https://github.com/thephpleague/oauth2-server - */ -namespace League\OAuth2\Server\TemplateRenderer; - -class TwigRenderer extends AbstractRenderer -{ - /** - * @var \Twig_Environment - */ - private $environment; - - /** - * PlatesRenderer constructor. - * - * @param \Twig_Environment $environment - * @param string $loginTemplate - * @param string $authorizeTemplate - */ - public function __construct(\Twig_Environment $environment, $loginTemplate, $authorizeTemplate) - { - parent::__construct($loginTemplate, $authorizeTemplate); - - $this->environment = $environment; - } - - /** - * {@inheritdoc} - */ - protected function render($template, array $data = []) - { - return $this->environment->loadTemplate($template)->render($data); - } -} From 7c35985c1e826dff15527425fd6dfa8a6b7efbda Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 06:52:27 -0400 Subject: [PATCH 392/444] Applied fixes from StyleCI --- examples/public/auth_code.php | 1 + src/Grant/AbstractAuthorizeGrant.php | 2 -- src/Grant/AbstractGrant.php | 6 +++--- src/Grant/AuthCodeGrant.php | 7 +++---- src/RequestTypes/AuthorizationRequest.php | 12 +++++++++--- src/Server.php | 3 ++- tests/ResponseTypes/BearerResponseTypeTest.php | 5 ++--- 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index 1e517e13..12f7cc49 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -81,6 +81,7 @@ $app->get('/authorize', function (ServerRequestInterface $request, ResponseInter } catch (\Exception $exception) { $body = new Stream('php://temp', 'r+'); $body->write($exception->getMessage()); + return $response->withStatus(500)->withBody($body); } }); diff --git a/src/Grant/AbstractAuthorizeGrant.php b/src/Grant/AbstractAuthorizeGrant.php index 4d086711..7f05100c 100644 --- a/src/Grant/AbstractAuthorizeGrant.php +++ b/src/Grant/AbstractAuthorizeGrant.php @@ -11,8 +11,6 @@ namespace League\OAuth2\Server\Grant; -use League\Plates\Engine; - abstract class AbstractAuthorizeGrant extends AbstractGrant { /** diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 739fb1c5..e2caed89 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -406,7 +406,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function canRespondToAuthorizationRequest(ServerRequestInterface $request) { @@ -414,7 +414,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function validateAuthorizationRequest(ServerRequestInterface $request) { @@ -422,7 +422,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest) { diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 6f580168..a4cf5dd1 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -132,7 +132,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function canRespondToAuthorizationRequest(ServerRequestInterface $request) { @@ -144,7 +144,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function validateAuthorizationRequest(ServerRequestInterface $request) { @@ -203,7 +203,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest) { @@ -219,7 +219,6 @@ class AuthCodeGrant extends AbstractAuthorizeGrant // The user approved the client, redirect them back with an auth code if ($authorizationRequest->isAuthorizationApproved() === true) { - $authCode = $this->issueAuthCode( $this->authCodeTTL, $authorizationRequest->getClient(), diff --git a/src/RequestTypes/AuthorizationRequest.php b/src/RequestTypes/AuthorizationRequest.php index 06a06672..031c58b2 100644 --- a/src/RequestTypes/AuthorizationRequest.php +++ b/src/RequestTypes/AuthorizationRequest.php @@ -10,42 +10,49 @@ class AuthorizationRequest { /** * The grant type identifier + * * @var string */ protected $grantTypeId; /** * The client identifier + * * @var ClientEntityInterface */ protected $client; /** * The user identifier + * * @var UserEntityInterface */ protected $user; /** * An array of scope identifiers + * * @var ScopeEntityInterface[] */ protected $scopes = []; /** * Has the user authorized the authorization request + * * @var bool */ protected $authorizationApproved = false; /** * The redirect URI used in the request + * * @var string */ protected $redirectUri; /** * The state parameter on the authorization request + * * @var string */ protected $state; @@ -115,7 +122,7 @@ class AuthorizationRequest } /** - * @return boolean + * @return bool */ public function isAuthorizationApproved() { @@ -123,7 +130,7 @@ class AuthorizationRequest } /** - * @param boolean $authorizationApproved + * @param bool $authorizationApproved */ public function setAuthorizationApproved($authorizationApproved) { @@ -161,5 +168,4 @@ class AuthorizationRequest { $this->state = $state; } - } diff --git a/src/Server.php b/src/Server.php index f6c388c7..48448b5e 100644 --- a/src/Server.php +++ b/src/Server.php @@ -130,8 +130,9 @@ class Server implements EmitterAwareInterface * * @param \Psr\Http\Message\ServerRequestInterface $request * - * @return \League\OAuth2\Server\RequestTypes\AuthorizationRequest|null * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \League\OAuth2\Server\RequestTypes\AuthorizationRequest|null */ public function validateAuthorizationRequest(ServerRequestInterface $request) { diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index 1014aa73..6c84e148 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -3,16 +3,15 @@ namespace LeagueTests\ResponseTypes; use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator; -use League\OAuth2\Server\Exception\OAuthServerException; - use League\OAuth2\Server\CryptKey; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; +use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\RefreshTokenEntity; use LeagueTests\Stubs\ScopeEntity; use Psr\Http\Message\ResponseInterface; -use LeagueTests\Stubs\AccessTokenEntity; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; From 79aa1988d802815e417891d68e58f8c9be99afc5 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 11:55:17 +0100 Subject: [PATCH 393/444] Removed HtmlResponse --- src/ResponseTypes/HtmlResponse.php | 66 ------------------------------ 1 file changed, 66 deletions(-) delete mode 100644 src/ResponseTypes/HtmlResponse.php diff --git a/src/ResponseTypes/HtmlResponse.php b/src/ResponseTypes/HtmlResponse.php deleted file mode 100644 index 11a92b9c..00000000 --- a/src/ResponseTypes/HtmlResponse.php +++ /dev/null @@ -1,66 +0,0 @@ -html = $html; - } - - /** - * @param int $statusCode - */ - public function setStatusCode($statusCode = 200) - { - $this->statusCode = $statusCode; - } - - /** - * @param ResponseInterface $response - * - * @return ResponseInterface - */ - public function generateHttpResponse(ResponseInterface $response) - { - $response->getBody()->write($this->html); - - foreach ($this->headers as $key => $value) { - $response = $response->withHeader($key, $value); - } - - return $response - ->withStatus($this->statusCode) - ->withHeader('content-type', 'text/html'); - } - - /** - * @param string $key - * @param string $value - */ - public function setHeader($key, $value) - { - $this->headers[$key] = $value; - } -} From b8c5056c31be3f056e928b27f859819a55e35b5e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 06:55:24 -0400 Subject: [PATCH 394/444] Applied fixes from StyleCI --- examples/public/auth_code.php | 1 + src/Grant/AbstractAuthorizeGrant.php | 2 -- src/Grant/AbstractGrant.php | 6 +++--- src/Grant/AuthCodeGrant.php | 7 +++---- src/RequestTypes/AuthorizationRequest.php | 12 +++++++++--- src/Server.php | 3 ++- tests/ResponseTypes/BearerResponseTypeTest.php | 5 ++--- 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index 1e517e13..12f7cc49 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -81,6 +81,7 @@ $app->get('/authorize', function (ServerRequestInterface $request, ResponseInter } catch (\Exception $exception) { $body = new Stream('php://temp', 'r+'); $body->write($exception->getMessage()); + return $response->withStatus(500)->withBody($body); } }); diff --git a/src/Grant/AbstractAuthorizeGrant.php b/src/Grant/AbstractAuthorizeGrant.php index 4d086711..7f05100c 100644 --- a/src/Grant/AbstractAuthorizeGrant.php +++ b/src/Grant/AbstractAuthorizeGrant.php @@ -11,8 +11,6 @@ namespace League\OAuth2\Server\Grant; -use League\Plates\Engine; - abstract class AbstractAuthorizeGrant extends AbstractGrant { /** diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 739fb1c5..e2caed89 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -406,7 +406,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function canRespondToAuthorizationRequest(ServerRequestInterface $request) { @@ -414,7 +414,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function validateAuthorizationRequest(ServerRequestInterface $request) { @@ -422,7 +422,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest) { diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 6f580168..a4cf5dd1 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -132,7 +132,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function canRespondToAuthorizationRequest(ServerRequestInterface $request) { @@ -144,7 +144,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function validateAuthorizationRequest(ServerRequestInterface $request) { @@ -203,7 +203,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest) { @@ -219,7 +219,6 @@ class AuthCodeGrant extends AbstractAuthorizeGrant // The user approved the client, redirect them back with an auth code if ($authorizationRequest->isAuthorizationApproved() === true) { - $authCode = $this->issueAuthCode( $this->authCodeTTL, $authorizationRequest->getClient(), diff --git a/src/RequestTypes/AuthorizationRequest.php b/src/RequestTypes/AuthorizationRequest.php index 06a06672..031c58b2 100644 --- a/src/RequestTypes/AuthorizationRequest.php +++ b/src/RequestTypes/AuthorizationRequest.php @@ -10,42 +10,49 @@ class AuthorizationRequest { /** * The grant type identifier + * * @var string */ protected $grantTypeId; /** * The client identifier + * * @var ClientEntityInterface */ protected $client; /** * The user identifier + * * @var UserEntityInterface */ protected $user; /** * An array of scope identifiers + * * @var ScopeEntityInterface[] */ protected $scopes = []; /** * Has the user authorized the authorization request + * * @var bool */ protected $authorizationApproved = false; /** * The redirect URI used in the request + * * @var string */ protected $redirectUri; /** * The state parameter on the authorization request + * * @var string */ protected $state; @@ -115,7 +122,7 @@ class AuthorizationRequest } /** - * @return boolean + * @return bool */ public function isAuthorizationApproved() { @@ -123,7 +130,7 @@ class AuthorizationRequest } /** - * @param boolean $authorizationApproved + * @param bool $authorizationApproved */ public function setAuthorizationApproved($authorizationApproved) { @@ -161,5 +168,4 @@ class AuthorizationRequest { $this->state = $state; } - } diff --git a/src/Server.php b/src/Server.php index f6c388c7..48448b5e 100644 --- a/src/Server.php +++ b/src/Server.php @@ -130,8 +130,9 @@ class Server implements EmitterAwareInterface * * @param \Psr\Http\Message\ServerRequestInterface $request * - * @return \League\OAuth2\Server\RequestTypes\AuthorizationRequest|null * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \League\OAuth2\Server\RequestTypes\AuthorizationRequest|null */ public function validateAuthorizationRequest(ServerRequestInterface $request) { diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index 1014aa73..6c84e148 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -3,16 +3,15 @@ namespace LeagueTests\ResponseTypes; use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator; -use League\OAuth2\Server\Exception\OAuthServerException; - use League\OAuth2\Server\CryptKey; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; +use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\RefreshTokenEntity; use LeagueTests\Stubs\ScopeEntity; use Psr\Http\Message\ResponseInterface; -use LeagueTests\Stubs\AccessTokenEntity; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; From 287c3715866340da3b5362185407c17a71b6844d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 06:56:21 -0400 Subject: [PATCH 395/444] Applied fixes from StyleCI --- src/Grant/AbstractAuthorizeGrant.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Grant/AbstractAuthorizeGrant.php b/src/Grant/AbstractAuthorizeGrant.php index 4d086711..7f05100c 100644 --- a/src/Grant/AbstractAuthorizeGrant.php +++ b/src/Grant/AbstractAuthorizeGrant.php @@ -11,8 +11,6 @@ namespace League\OAuth2\Server\Grant; -use League\Plates\Engine; - abstract class AbstractAuthorizeGrant extends AbstractGrant { /** From 8225b4e6971b23f076f33c5716e804f1b56c172d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 13:26:01 +0100 Subject: [PATCH 396/444] OpenSSL extension is required by lcobucci/jwt --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index e392d1e6..d022b934 100644 --- a/composer.json +++ b/composer.json @@ -5,6 +5,7 @@ "license": "MIT", "require": { "php": ">=5.5.9", + "ext-openssl": "*", "league/event": "^2.1", "lcobucci/jwt": "^3.1", "paragonie/random_compat": "^1.1", From 8f50e58ba9b20361854bba041f8eaa76f9c5c478 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 13:26:31 +0100 Subject: [PATCH 397/444] Remove templating packages --- composer.json | 7 ------- 1 file changed, 7 deletions(-) diff --git a/composer.json b/composer.json index d022b934..aaf66f2d 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,6 @@ }, "require-dev": { "phpunit/phpunit": "^4.8", - "league/plates": "^3.1", "zendframework/zend-diactoros": "^1.0" }, "repositories": [ @@ -64,11 +63,5 @@ "branch-alias": { "dev-V5-WIP": "5.0-dev" } - }, - "suggest": { - "league/plates": "Used for parsing authorization code templates", - "twig/twig": "Used for parsing authorization code templates", - "smarty/smarty": "Used for parsing authorization code templates", - "mustache/mustache": "Used for parsing authorization code templates" } } From 4c0c10ae9877bb8249889c9de4cc8fb956b1a3d7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 13:49:25 +0100 Subject: [PATCH 398/444] HTTPS link --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index aaf66f2d..5a11fd07 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "league/oauth2-server", "description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.", - "homepage": "http://oauth2.thephpleague.com/", + "homepage": "https://oauth2.thephpleague.com/", "license": "MIT", "require": { "php": ">=5.5.9", From a0c4900ee7b95a8de2453154be083cfe5ca2a159 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 13:53:16 +0100 Subject: [PATCH 399/444] Client is not required here because of finalizeScopes method --- src/Grant/AbstractGrant.php | 2 -- src/Grant/AuthCodeGrant.php | 1 - src/Grant/ClientCredentialsGrant.php | 2 +- src/Grant/ImplicitGrant.php | 1 - src/Grant/PasswordGrant.php | 2 +- src/Grant/RefreshTokenGrant.php | 2 +- tests/Grant/AbstractGrantTest.php | 4 ++-- 7 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index e2caed89..fd7b1e48 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -194,7 +194,6 @@ abstract class AbstractGrant implements GrantTypeInterface * Validate scopes in the request. * * @param string $scopes - * @param \League\OAuth2\Server\Entities\ClientEntityInterface $client * @param string $redirectUri * * @throws \League\OAuth2\Server\Exception\OAuthServerException @@ -203,7 +202,6 @@ abstract class AbstractGrant implements GrantTypeInterface */ public function validateScopes( $scopes, - ClientEntityInterface $client, $redirectUri = null ) { $scopesList = array_filter( diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index a4cf5dd1..c8b496a4 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -186,7 +186,6 @@ class AuthCodeGrant extends AbstractAuthorizeGrant $scopes = $this->validateScopes( $this->getQueryStringParameter('scope', $request), - $client, $client->getRedirectUri() ); diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index 49493372..c8ff2d52 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -28,7 +28,7 @@ class ClientCredentialsGrant extends AbstractGrant ) { // Validate request $client = $this->validateClient($request); - $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client); + $scopes = $this->validateScopes($this->getRequestParameter('scope', $request)); // Finalize the requested scopes $scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client); diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 497542d5..92e5b84b 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -80,7 +80,6 @@ class ImplicitGrant extends AbstractAuthorizeGrant $scopes = $this->validateScopes( $this->getQueryStringParameter('scope', $request), - $client, $client->getRedirectUri() ); diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 29262306..6d98115d 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -48,7 +48,7 @@ class PasswordGrant extends AbstractGrant ) { // Validate request $client = $this->validateClient($request); - $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client); + $scopes = $this->validateScopes($this->getRequestParameter('scope', $request)); $user = $this->validateUser($request, $client); // Finalize the requested scopes diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 43249647..168e9908 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -42,7 +42,7 @@ class RefreshTokenGrant extends AbstractGrant // Validate request $client = $this->validateClient($request); $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier()); - $scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client); + $scopes = $this->validateScopes($this->getRequestParameter('scope', $request)); // If no new scopes are requested then give the access token the original session scopes if (count($scopes) === 0) { diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 27fe44d5..1321654d 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -374,7 +374,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); $grantMock->setScopeRepository($scopeRepositoryMock); - $this->assertEquals([$scope], $grantMock->validateScopes('basic ', new ClientEntity())); + $this->assertEquals([$scope], $grantMock->validateScopes('basic ')); } /** @@ -389,7 +389,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); $grantMock->setScopeRepository($scopeRepositoryMock); - $grantMock->validateScopes('basic ', new ClientEntity()); + $grantMock->validateScopes('basic '); } public function testGenerateUniqueIdentifier() From a68f07f734a2712a4806c4f9b1e05783bf2b84a0 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 08:53:54 -0400 Subject: [PATCH 400/444] Applied fixes from StyleCI --- src/Grant/AbstractGrant.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index fd7b1e48..ac5591f5 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -193,8 +193,8 @@ abstract class AbstractGrant implements GrantTypeInterface /** * Validate scopes in the request. * - * @param string $scopes - * @param string $redirectUri + * @param string $scopes + * @param string $redirectUri * * @throws \League\OAuth2\Server\Exception\OAuthServerException * From 096a4a28831ad1a0fdeb8827c46af9bed07b2a12 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 14:22:26 +0100 Subject: [PATCH 401/444] Remove unused params --- src/Grant/AuthCodeGrant.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index c8b496a4..6f3a5611 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -13,7 +13,6 @@ use League\OAuth2\Server\RequestEvent; use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\RedirectResponse; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; -use League\OAuth2\Server\TemplateRenderer\RendererInterface; use Psr\Http\Message\ServerRequestInterface; class AuthCodeGrant extends AbstractAuthorizeGrant @@ -28,21 +27,18 @@ class AuthCodeGrant extends AbstractAuthorizeGrant * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository * @param \DateInterval $authCodeTTL - * @param \League\OAuth2\Server\TemplateRenderer\RendererInterface|null $templateRenderer */ public function __construct( AuthCodeRepositoryInterface $authCodeRepository, RefreshTokenRepositoryInterface $refreshTokenRepository, UserRepositoryInterface $userRepository, - \DateInterval $authCodeTTL, - RendererInterface $templateRenderer = null + \DateInterval $authCodeTTL ) { $this->setAuthCodeRepository($authCodeRepository); $this->setRefreshTokenRepository($refreshTokenRepository); $this->setUserRepository($userRepository); $this->authCodeTTL = $authCodeTTL; $this->refreshTokenTTL = new \DateInterval('P1M'); - $this->templateRenderer = $templateRenderer; } /** From 273ea0ba683c01fea4a6dfe04dd1072551501cf0 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 14:22:52 +0100 Subject: [PATCH 402/444] Updated implicit grant to use the new auth request flow --- src/Grant/ImplicitGrant.php | 209 +++++++++++++++--------------------- 1 file changed, 88 insertions(+), 121 deletions(-) diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 92e5b84b..66100e7d 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -7,23 +7,27 @@ use League\OAuth2\Server\Entities\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\RequestEvent; -use League\OAuth2\Server\ResponseTypes\HtmlResponse; +use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\RedirectResponse; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; -use League\OAuth2\Server\TemplateRenderer\RendererInterface; use Psr\Http\Message\ServerRequestInterface; class ImplicitGrant extends AbstractAuthorizeGrant { /** - * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository - * @param \League\OAuth2\Server\TemplateRenderer\RendererInterface|null $templateRenderer + * @var \DateInterval */ - public function __construct(UserRepositoryInterface $userRepository, RendererInterface $templateRenderer = null) + private $accessTokenTTL; + + /** + * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository + * @param \DateInterval $accessTokenTTL + */ + public function __construct(UserRepositoryInterface $userRepository, \DateInterval $accessTokenTTL) { $this->setUserRepository($userRepository); $this->refreshTokenTTL = new \DateInterval('P1M'); - $this->templateRenderer = $templateRenderer; + $this->accessTokenTTL = $accessTokenTTL; } /** @@ -31,8 +35,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant */ public function canRespondToAccessTokenRequest(ServerRequestInterface $request) { - return (array_key_exists('response_type', $request->getQueryParams()) - && $request->getQueryParams()['response_type'] === 'token'); + return false; } /** @@ -46,13 +49,39 @@ class ImplicitGrant extends AbstractAuthorizeGrant } /** - * {@inheritdoc} + * Respond to an incoming request. + * + * @param \Psr\Http\Message\ServerRequestInterface $request + * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType + * @param \DateInterval $accessTokenTTL + * + * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface */ - public function respondToRequest( + public function respondToAccessTokenRequest( ServerRequestInterface $request, ResponseTypeInterface $responseType, \DateInterval $accessTokenTTL ) { + throw new \LogicException('This grant does not used this method'); + } + + /** + * {@inheritdoc} + */ + public function canRespondToAuthorizationRequest(ServerRequestInterface $request) + { + return ( + array_key_exists('response_type', $request->getQueryParams()) + && $request->getQueryParams()['response_type'] === 'token' + && isset($request->getQueryParams()['client_id']) + ); + } + + /** + * {@inheritdoc} + */ + public function validateAuthorizationRequest(ServerRequestInterface $request) + { $clientId = $this->getQueryStringParameter( 'client_id', $request, @@ -72,10 +101,21 @@ class ImplicitGrant extends AbstractAuthorizeGrant throw OAuthServerException::invalidClient(); } - $redirectUriParameter = $this->getQueryStringParameter('redirect_uri', $request, $client->getRedirectUri()); - if ($redirectUriParameter !== $client->getRedirectUri()) { - $this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request)); - throw OAuthServerException::invalidClient(); + $redirectUri = $this->getQueryStringParameter('redirect_uri', $request); + if ($redirectUri !== null) { + if ( + is_string($client->getRedirectUri()) + && (strcmp($client->getRedirectUri(), $redirectUri) !== 0) + ) { + $this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request)); + throw OAuthServerException::invalidClient(); + } elseif ( + is_array($client->getRedirectUri()) + && in_array($redirectUri, $client->getRedirectUri()) === false + ) { + $this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request)); + throw OAuthServerException::invalidClient(); + } } $scopes = $this->validateScopes( @@ -83,117 +123,41 @@ class ImplicitGrant extends AbstractAuthorizeGrant $client->getRedirectUri() ); - $postbackUri = 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($this->decrypt($oauthCookie)); - 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, - $this->getIdentifier(), - $client - ); - - 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) { - $html = $this->getTemplateRenderer()->renderLogin([ - 'error' => $loginError, - 'postback_uri' => $this->makeRedirectUri( - $postbackUri, - $request->getQueryParams() - ), - ]); - - $htmlResponse = new HtmlResponse(); - $htmlResponse->setStatusCode(403); - $htmlResponse->setHtml($html); - - return $htmlResponse; - } - - // The user hasn't approved the client yet so show an authorize form - if ($userId !== null && $userHasApprovedClient === null) { - $html = $this->getTemplateRenderer()->renderAuthorize([ - 'client' => $client, - 'scopes' => $scopes, - 'postback_uri' => $this->makeRedirectUri( - $postbackUri, - $request->getQueryParams() - ), - ]); - - $htmlResponse = new HtmlResponse(); - $htmlResponse->setStatusCode(200); - $htmlResponse->setHtml($html); - $htmlResponse->setHeader('set-cookie', sprintf( - 'oauth_authorize_request=%s; Expires=%s', - urlencode($this->encrypt( - json_encode([ - 'user_id' => $userId, - ]) - )), - (new \DateTime())->add(new \DateInterval('PT5M'))->format('D, d M Y H:i:s e') - )); - - return $htmlResponse; - } - - // The user has either approved or denied the client, so redirect them back - $redirectUri = $client->getRedirectUri(); - $redirectPayload = []; - $stateParameter = $this->getQueryStringParameter('state', $request); - if ($stateParameter !== null) { - $redirectPayload['state'] = $stateParameter; + + $authorizationRequest = new AuthorizationRequest(); + $authorizationRequest->setGrantTypeId($this->getIdentifier()); + $authorizationRequest->setClient($client); + $authorizationRequest->setRedirectUri($redirectUri); + $authorizationRequest->setState($stateParameter); + $authorizationRequest->setScopes($scopes); + + return $authorizationRequest; + } + + /** + * {@inheritdoc} + */ + public function completeAuthorizationRequest(AuthorizationRequest $authorizationRequest) + { + if ($authorizationRequest->getUser() instanceof UserEntityInterface === false) { + throw new \LogicException('An instance of UserEntityInterface should be set on the AuthorizationRequest'); } - // THe user approved the client, redirect them back with an access token - if ($userHasApprovedClient === true) { + $finalRedirectUri = ($authorizationRequest->getRedirectUri() === null) + ? is_array($authorizationRequest->getClient()->getRedirectUri()) + ? $authorizationRequest->getClient()->getRedirectUri()[0] + : $authorizationRequest->getClient()->getRedirectUri() + : $authorizationRequest->getRedirectUri(); - // Finalize the requested scopes - $scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $userId); + // The user approved the client, redirect them back with an access token + if ($authorizationRequest->isAuthorizationApproved() === true) { $accessToken = $this->issueAccessToken( - $accessTokenTTL, - $client, - $userId, - $scopes + $this->accessTokenTTL, + $authorizationRequest->getClient(), + $authorizationRequest->getUser()->getIdentifier(), + $authorizationRequest->getScopes() ); $redirectPayload['access_token'] = (string) $accessToken->convertToJWT($this->privateKey); @@ -203,7 +167,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant $response = new RedirectResponse(); $response->setRedirectUri( $this->makeRedirectUri( - $redirectUri, + $finalRedirectUri, $redirectPayload, '#' ) @@ -213,6 +177,9 @@ class ImplicitGrant extends AbstractAuthorizeGrant } // The user denied the client, redirect them back with an error - throw OAuthServerException::accessDenied('The user denied the request', (string) $redirectUri); + throw OAuthServerException::accessDenied( + 'The user denied the request', + $finalRedirectUri + ); } } From 1512960d9228dea1c02c58bbbe27811cfff94dd6 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 09:23:10 -0400 Subject: [PATCH 403/444] Applied fixes from StyleCI --- src/Grant/AbstractGrant.php | 4 ++-- src/Grant/ImplicitGrant.php | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index fd7b1e48..ac5591f5 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -193,8 +193,8 @@ abstract class AbstractGrant implements GrantTypeInterface /** * Validate scopes in the request. * - * @param string $scopes - * @param string $redirectUri + * @param string $scopes + * @param string $redirectUri * * @throws \League\OAuth2\Server\Exception\OAuthServerException * diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 66100e7d..9df55546 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -152,7 +152,6 @@ class ImplicitGrant extends AbstractAuthorizeGrant // The user approved the client, redirect them back with an access token if ($authorizationRequest->isAuthorizationApproved() === true) { - $accessToken = $this->issueAccessToken( $this->accessTokenTTL, $authorizationRequest->getClient(), From e24dff2723322d8ca09c78992c16d2d1353cbeb7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 14:30:44 +0100 Subject: [PATCH 404/444] Fixed expires_in --- src/Grant/ImplicitGrant.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 66100e7d..4d9f79bb 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -162,7 +162,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant $redirectPayload['access_token'] = (string) $accessToken->convertToJWT($this->privateKey); $redirectPayload['token_type'] = 'bearer'; - $redirectPayload['expires_in'] = time() - $accessToken->getExpiryDateTime()->getTimestamp(); + $redirectPayload['expires_in'] = $accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp(); $response = new RedirectResponse(); $response->setRedirectUri( From ba30e34511f9585ee9e7f66637d188e5e6545ed8 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 14:31:05 +0100 Subject: [PATCH 405/444] Lazy set $accessTokenTTL --- src/Server.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Server.php b/src/Server.php index 48448b5e..65de57eb 100644 --- a/src/Server.php +++ b/src/Server.php @@ -111,8 +111,12 @@ class Server implements EmitterAwareInterface * @param \League\OAuth2\Server\Grant\GrantTypeInterface $grantType * @param \DateInterval $accessTokenTTL */ - public function enableGrantType(GrantTypeInterface $grantType, DateInterval $accessTokenTTL) + public function enableGrantType(GrantTypeInterface $grantType, DateInterval $accessTokenTTL = null) { + if ($accessTokenTTL instanceof DateInterval === false) { + $accessTokenTTL = new \DateInterval('PT1H'); + } + $grantType->setAccessTokenRepository($this->accessTokenRepository); $grantType->setClientRepository($this->clientRepository); $grantType->setScopeRepository($this->scopeRepository); @@ -121,7 +125,6 @@ class Server implements EmitterAwareInterface $grantType->setEmitter($this->getEmitter()); $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; - $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL; } From d3a7b442ce9d00b9938ddd6befdc64a3ae6e5e18 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 14:31:21 +0100 Subject: [PATCH 406/444] Updated implicit grant example --- examples/public/implicit.php | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/examples/public/implicit.php b/examples/public/implicit.php index a9313017..d5bce903 100644 --- a/examples/public/implicit.php +++ b/examples/public/implicit.php @@ -3,6 +3,7 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ImplicitGrant; use League\OAuth2\Server\Server; +use OAuth2ServerExamples\Entities\UserEntity; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; @@ -38,21 +39,30 @@ $app = new App([ ); // Enable the implicit grant on the server with a token TTL of 1 hour - $server->enableGrantType( - new ImplicitGrant($userRepository), - new \DateInterval('PT1H') - ); + $server->enableGrantType(new ImplicitGrant($userRepository, new \DateInterval('PT1H'))); return $server; }, ]); -$app->any('/authorize', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { +$app->get('/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); + // Validate the HTTP request and return an AuthorizationRequest object. + // The auth request object can be serialized into a user's session + $authRequest = $server->validateAuthorizationRequest($request); + + // Once the user has logged in set the user on the AuthorizationRequest + $authRequest->setUser(new UserEntity()); + + // Once the user has approved or denied the client update the status + // (true = approved, false = denied) + $authRequest->setAuthorizationApproved(true); + + // Return the HTTP redirect response + return $server->completeAuthorizationRequest($authRequest, $response); } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); } catch (\Exception $exception) { From 7a6d9a45109046654eb34945c69e6f75bdaf8e52 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 15:15:29 +0100 Subject: [PATCH 407/444] Fixed broken AuthCodeGrant tests --- tests/Grant/AuthCodeGrantTest.php | 545 ++++++++---------------------- 1 file changed, 148 insertions(+), 397 deletions(-) diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 3d1064bf..4acfba9b 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -13,6 +13,7 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\HtmlResponse; use League\OAuth2\Server\ResponseTypes\RedirectResponse; use LeagueTests\Stubs\AccessTokenEntity; @@ -51,7 +52,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->assertEquals('authorization_code', $grant->getIdentifier()); } - public function testCanRespondToRequest() + public function testCanRespondToAuthorizationRequest() { $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), @@ -74,515 +75,265 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ] ); - $this->assertTrue($grant->canRespondToRequest($request)); + $this->assertTrue($grant->canRespondToAuthorizationRequest($request)); } - public function testRespondToAuthorizationRequest() + public function testValidateAuthorizationRequest() { $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); - - $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); - - $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); - $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); - - $authCodeRepoMock = $this->getMock(AuthCodeRepositoryInterface::class); - $authCodeRepoMock->expects($this->once())->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); - - $grant = new AuthCodeGrant( - $authCodeRepoMock, - $this->getMock(RefreshTokenRepositoryInterface::class), - $userRepositoryMock, - new \DateInterval('PT10M') - ); - $grant->setClientRepository($clientRepositoryMock); - $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setScopeRepository($scopeRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - - $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], - [], - null, - 'POST', - 'php://input', - [], - [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), - ], - [ - '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 RedirectResponse); - - $response = $response->generateHttpResponse(new Response); - $this->assertTrue(strstr($response->getHeader('location')[0], 'http://foo/bar') !== false); - } - - /** - * @expectedException \League\OAuth2\Server\Exception\OAuthServerException - * @expectedExceptionCode 9 - */ - 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); - - $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); - $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $userRepositoryMock, + $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], + [], [], null, - 'POST', + null, 'php://input', - [], - [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), - ], - [ + $headers = [], + $cookies = [], + $queryParams = [ 'response_type' => 'code', 'client_id' => 'foo', - 'state' => 'foobar', - ], - [ - 'username' => 'alex', - 'password' => 'whisky', - 'action' => 'denied', + 'redirect_uri' => 'http://foo/bar', ] ); - $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + $this->assertTrue($grant->validateAuthorizationRequest($request) instanceof AuthorizationRequest); + } + + public function testValidateAuthorizationRequestRedirectUriArray() + { + $client = new ClientEntity(); + $client->setRedirectUri(['http://foo/bar']); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $this->getMock(UserRepositoryInterface::class), + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + + $request = new ServerRequest( + [], + [], + null, + null, + 'php://input', + $headers = [], + $cookies = [], + $queryParams = [ + 'response_type' => 'code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + ] + ); + + $this->assertTrue($grant->validateAuthorizationRequest($request) instanceof AuthorizationRequest); } /** * @expectedException \League\OAuth2\Server\Exception\OAuthServerException * @expectedExceptionCode 3 */ - public function testRespondToAuthorizationRequestMissingClientId() + public function testValidateAuthorizationRequestMissingClientId() { - $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, + $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], + [], [], null, - 'POST', + null, 'php://input', - [], - [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), - ], - [ + $headers = [], + $cookies = [], + $queryParams = [ 'response_type' => 'code', - ], - [ - 'username' => 'alex', - 'password' => 'whisky', - 'action' => 'approve', ] ); - $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); - } - - 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->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - - $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], - [], - null, - 'POST', - 'php://input', - [], - [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), - ], - [ - '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->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - - $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], - [], - null, - 'POST', - 'php://input', - [], - [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), - ], - [ - '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'); - } + $grant->validateAuthorizationRequest($request); } /** * @expectedException \League\OAuth2\Server\Exception\OAuthServerException - * @expectedExceptionCode 7 + * @expectedExceptionCode 4 */ - public function testRespondToAuthorizationRequestBadCookie() + public function testValidateAuthorizationRequestInvalidClientId() { - $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); + $clientRepositoryMock->method('getClientEntity')->willReturn(null); $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $userRepositoryMock, + $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], + [], [], null, - 'POST', + null, 'php://input', - [], - [ - 'oauth_authorize_request' => 'blah', - ], - [ + $headers = [], + $cookies = [], + $queryParams = [ 'response_type' => 'code', 'client_id' => 'foo', - ], - [ - 'username' => 'alex', - 'password' => 'whisky', - 'action' => 'approve', ] ); - $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + $grant->validateAuthorizationRequest($request); } - public function testRespondToAuthorizationRequestTryLogin() + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 4 + */ + public function testValidateAuthorizationRequestBadRedirectUriString() { $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); - - $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); - - $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); - $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); - - $authCodeRepoMock = $this->getMock(AuthCodeRepositoryInterface::class); - $authCodeRepoMock->expects($this->once())->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); - - $grant = new AuthCodeGrant( - $authCodeRepoMock, - $this->getMock(RefreshTokenRepositoryInterface::class), - $userRepositoryMock, - new \DateInterval('PT10M') - ); - $grant->setClientRepository($clientRepositoryMock); - $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setScopeRepository($scopeRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - - $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], - [], - null, - 'POST', - 'php://input', - [], - [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => null])), - ], - [ - '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 RedirectResponse); - - $response = $response->generateHttpResponse(new Response); - $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); - - $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); - $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $userRepositoryMock, + $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], + [], [], null, - 'POST', + null, 'php://input', - [], - [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => null])), - ], - [ + $headers = [], + $cookies = [], + $queryParams = [ 'response_type' => 'code', 'client_id' => 'foo', - ], - [ - 'username' => 'alex', - 'password' => 'whisky', - 'action' => 'approve', + 'redirect_uri' => 'http://bar', ] ); - $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); - - $this->assertTrue($response instanceof HtmlResponse); - - $response = $response->generateHttpResponse(new Response); - $this->assertTrue(strstr($response->getHeader('content-type')[0], 'text/html') !== false); - $this->assertTrue(strstr((string) $response->getBody(), 'Incorrect username or password') !== false); + $grant->validateAuthorizationRequest($request); } - public function testRespondToAuthorizationRequestShowAuthorizeForm() + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 4 + */ + public function testValidateAuthorizationRequestBadRedirectUriArray() { $client = new ClientEntity(); - $client->setRedirectUri('http://foo/bar'); - $client->setName('Test Client'); + $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(); - $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $userRepositoryMock, + $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], + [], [], null, - 'POST', + null, 'php://input', - [], - [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), - ], - [ + $headers = [], + $cookies = [], + $queryParams = [ 'response_type' => 'code', 'client_id' => 'foo', - ], - [ - 'username' => 'alex', - 'password' => 'whisky', + 'redirect_uri' => 'http://bar', ] ); - $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + $grant->validateAuthorizationRequest($request); + } - $response = $response->generateHttpResponse(new Response); - $this->assertTrue($response instanceof ResponseInterface); - $this->assertTrue(strstr($response->getHeader('set-cookie')[0], 'oauth_authorize_request') !== false); + public function testCompleteAuthorizationRequest() + { + $authRequest = new AuthorizationRequest(); + $authRequest->setAuthorizationApproved(true); + $authRequest->setClient(new ClientEntity()); + $authRequest->setGrantTypeId('authorization_code'); + $authRequest->setUser(new UserEntity()); + + $authCodeRepository = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(); + $authCodeRepository->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); + + $grant = new AuthCodeGrant( + $authCodeRepository, + $this->getMock(RefreshTokenRepositoryInterface::class), + $this->getMock(UserRepositoryInterface::class), + new \DateInterval('PT10M') + ); + + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + + $this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 9 + */ + public function testCompleteAuthorizationRequestDenied() + { + $authRequest = new AuthorizationRequest(); + $authRequest->setAuthorizationApproved(false); + $authRequest->setClient(new ClientEntity()); + $authRequest->setGrantTypeId('authorization_code'); + $authRequest->setUser(new UserEntity()); + + $authCodeRepository = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(); + $authCodeRepository->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); + + $grant = new AuthCodeGrant( + $authCodeRepository, + $this->getMock(RefreshTokenRepositoryInterface::class), + $this->getMock(UserRepositoryInterface::class), + new \DateInterval('PT10M') + ); + + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + + $grant->completeAuthorizationRequest($authRequest); } public function testRespondToAccessTokenRequest() @@ -651,7 +402,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); /** @var StubResponseType $response */ - $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + $response = $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M')); $this->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface); $this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface); @@ -695,7 +446,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); /* @var StubResponseType $response */ - $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } /** @@ -743,7 +494,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); /* @var StubResponseType $response */ - $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } public function testRespondToAccessTokenRequestExpiredCode() @@ -806,7 +557,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase try { /* @var StubResponseType $response */ - $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } catch (OAuthServerException $e) { $this->assertEquals($e->getHint(), 'Authorization code has expired'); } @@ -875,7 +626,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase try { /* @var StubResponseType $response */ - $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } catch (OAuthServerException $e) { $this->assertEquals($e->getHint(), 'Authorization code has been revoked'); } @@ -941,7 +692,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase try { /* @var StubResponseType $response */ - $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } catch (OAuthServerException $e) { $this->assertEquals($e->getHint(), 'Authorization code was not issued to this client'); } @@ -996,7 +747,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase try { /* @var StubResponseType $response */ - $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + $grant->respondToAccessTokenRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } catch (OAuthServerException $e) { $this->assertEquals($e->getHint(), 'Cannot decrypt the authorization code'); } From 5969082963ae47e3334962abc2c70734495764d1 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 15:58:01 +0100 Subject: [PATCH 408/444] Fix tests and improve code coverate --- src/Entities/Traits/ClientTrait.php | 1 + src/Exception/OAuthServerException.php | 2 + src/Grant/AuthCodeGrant.php | 1 + src/RequestEvent.php | 1 + tests/CryptTraitTest.php | 8 + tests/Grant/AbstractGrantTest.php | 25 +++ tests/Grant/AuthCodeGrantTest.php | 1 - .../AuthenticationServerMiddlewareTest.php | 21 ++- .../ResourceServerMiddlewareTest.php | 41 +++++ tests/ServerTest.php | 165 ++++++++++++------ 10 files changed, 212 insertions(+), 54 deletions(-) diff --git a/src/Entities/Traits/ClientTrait.php b/src/Entities/Traits/ClientTrait.php index bf5fb97d..db01649d 100644 --- a/src/Entities/Traits/ClientTrait.php +++ b/src/Entities/Traits/ClientTrait.php @@ -12,6 +12,7 @@ trait ClientTrait * Get the client's name. * * @return string + * @codeCoverageIgnore */ public function getName() { diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 1f08919c..2e4d8e18 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -119,6 +119,8 @@ class OAuthServerException extends \Exception * @param $hint * * @return static + * + * @codeCoverageIgnore */ public static function serverError($hint) { diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 6f3a5611..92cefe44 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -234,6 +234,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant ] ) ); + $redirectPayload['state'] = $authorizationRequest->getState(); $response = new RedirectResponse(); $response->setRedirectUri( diff --git a/src/RequestEvent.php b/src/RequestEvent.php index d8f7da08..3170beab 100644 --- a/src/RequestEvent.php +++ b/src/RequestEvent.php @@ -26,6 +26,7 @@ class RequestEvent extends Event /** * @return ServerRequestInterface + * @codeCoverageIgnore */ public function getRequest() { diff --git a/tests/CryptTraitTest.php b/tests/CryptTraitTest.php index 364d712f..d0ada49e 100644 --- a/tests/CryptTraitTest.php +++ b/tests/CryptTraitTest.php @@ -44,4 +44,12 @@ class CryptTraitTest extends \PHPUnit_Framework_TestCase $this->cryptStub->setPublicKey(new CryptKey(__DIR__ . '/Stubs/private.key')); $this->cryptStub->doDecrypt(''); } + + /** + * @expectedException \LogicException + */ + public function testNonExistentKey() + { + new CryptKey('foo/bar'); + } } diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 1321654d..0c4f6ae7 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -13,6 +13,7 @@ use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\AuthCodeEntity; use LeagueTests\Stubs\ClientEntity; @@ -402,4 +403,28 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $this->assertTrue(is_string($method->invoke($grantMock))); } + + public function testCanRespondToAuthorizationRequest() + { + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $this->assertFalse($grantMock->canRespondToAuthorizationRequest(new ServerRequest())); + } + + /** + * @expectedException \LogicException + */ + public function testValidateAuthorizationRequest() + { + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->validateAuthorizationRequest(new ServerRequest()); + } + + /** + * @expectedException \LogicException + */ + public function testCompleteAuthorizationRequest() + { + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->completeAuthorizationRequest(new AuthorizationRequest()); + } } diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 4acfba9b..93dfcae6 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -24,7 +24,6 @@ use LeagueTests\Stubs\RefreshTokenEntity; use LeagueTests\Stubs\ScopeEntity; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; -use Psr\Http\Message\ResponseInterface; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; diff --git a/tests/Middleware/AuthenticationServerMiddlewareTest.php b/tests/Middleware/AuthenticationServerMiddlewareTest.php index d5f82594..d9302cae 100644 --- a/tests/Middleware/AuthenticationServerMiddlewareTest.php +++ b/tests/Middleware/AuthenticationServerMiddlewareTest.php @@ -2,6 +2,7 @@ namespace LeagueTests\Middleware; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Middleware\AuthenticationServerMiddleware; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -36,7 +37,7 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase new StubResponseType() ); - $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M')); + $server->enableGrantType(new ClientCredentialsGrant()); $_POST['grant_type'] = 'client_credentials'; $_POST['client_id'] = 'foo'; @@ -89,4 +90,22 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase $this->assertEquals(401, $response->getStatusCode()); } + + public function testOAuthErrorResponseRedirectUri() + { + $exception = OAuthServerException::invalidScope('test', 'http://foo/bar'); + $response = $exception->generateHttpResponse(new Response()); + + $this->assertEquals(302, $response->getStatusCode()); + $this->assertEquals('http://foo/bar?error=invalid_scope&message=The+requested+scope+is+invalid%2C+unknown%2C+or+malformed&hint=Check+the+%60test%60+scope', $response->getHeader('location')[0]); + } + + public function testOAuthErrorResponseRedirectUriFragment() + { + $exception = OAuthServerException::invalidScope('test', 'http://foo/bar'); + $response = $exception->generateHttpResponse(new Response(), true); + + $this->assertEquals(302, $response->getStatusCode()); + $this->assertEquals('http://foo/bar#error=invalid_scope&message=The+requested+scope+is+invalid%2C+unknown%2C+or+malformed&hint=Check+the+%60test%60+scope', $response->getHeader('location')[0]); + } } diff --git a/tests/Middleware/ResourceServerMiddlewareTest.php b/tests/Middleware/ResourceServerMiddlewareTest.php index 5656d3d1..a71dc5ab 100644 --- a/tests/Middleware/ResourceServerMiddlewareTest.php +++ b/tests/Middleware/ResourceServerMiddlewareTest.php @@ -57,6 +57,47 @@ class ResourceServerMiddlewareTest extends \PHPUnit_Framework_TestCase $this->assertEquals(200, $response->getStatusCode()); } + public function testValidResponseExpiredToken() + { + $clientRepository = $this->getMock(ClientRepositoryInterface::class); + + $server = new Server( + $clientRepository, + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + 'file://' . __DIR__ . '/../Stubs/private.key', + 'file://' . __DIR__ . '/../Stubs/public.key', + new StubResponseType() + ); + + $client = new ClientEntity(); + $client->setIdentifier('clientName'); + + $accessToken = new AccessTokenEntity(); + $accessToken->setIdentifier('test'); + $accessToken->setUserIdentifier(123); + $accessToken->setExpiryDateTime((new \DateTime())->sub(new \DateInterval('PT1H'))); + $accessToken->setClient($client); + + $token = $accessToken->convertToJWT(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + + $request = new ServerRequest(); + $request = $request->withHeader('authorization', sprintf('Bearer %s', $token)); + + $middleware = new ResourceServerMiddleware($server); + $response = $middleware->__invoke( + $request, + new Response(), + function () { + $this->assertEquals('test', func_get_args()[0]->getAttribute('oauth_access_token_id')); + + return func_get_args()[1]; + } + ); + + $this->assertEquals(401, $response->getStatusCode()); + } + public function testErrorResponse() { $clientRepository = $this->getMock(ClientRepositoryInterface::class); diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 82d07059..2505d5e4 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -2,6 +2,7 @@ namespace LeagueTests; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\ClientCredentialsGrant; @@ -11,6 +12,7 @@ use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use League\OAuth2\Server\Server; use LeagueTests\Stubs\AccessTokenEntity; @@ -20,6 +22,7 @@ use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; use Psr\Http\Message\ResponseInterface; use Zend\Diactoros\Response; +use Zend\Diactoros\ServerRequest; use Zend\Diactoros\ServerRequestFactory; class ServerTest extends \PHPUnit_Framework_TestCase @@ -74,57 +77,6 @@ class ServerTest extends \PHPUnit_Framework_TestCase $this->assertEquals(200, $response->getStatusCode()); } - public function testRespondToRequestPsrResponse() - { - $client = new ClientEntity(); - $client->setIdentifier('foo'); - $client->setIdentifier('http://bar.com'); - - $clientRepository = $this->getMock(ClientRepositoryInterface::class); - $clientRepository->method('getClientEntity')->willReturn($client); - - $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); - $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); - - $server = new Server( - $clientRepository, - $this->getMock(AccessTokenRepositoryInterface::class), - $scopeRepositoryMock, - 'file://' . __DIR__ . '/Stubs/private.key', - 'file://' . __DIR__ . '/Stubs/public.key', - new StubResponseType() - ); - - $userRepository = $this->getMock(UserRepositoryInterface::class); - $userRepository->method('getUserEntityByUserCredentials')->willReturn(new UserEntity()); - - $authCodeRepoMock = $this->getMock(AuthCodeRepositoryInterface::class); - $authCodeRepoMock->expects($this->once())->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); - - $server->enableGrantType( - new AuthCodeGrant( - $authCodeRepoMock, - $this->getMock(RefreshTokenRepositoryInterface::class), - $userRepository, - new \DateInterval('PT1H') - ), - new \DateInterval('PT1M') - ); - - $_SERVER['HTTP_HOST'] = 'http://auth.com'; - $_SERVER['REQUEST_URI'] = '/auth'; - $_GET['response_type'] = 'code'; - $_GET['client_id'] = $client->getIdentifier(); - $_GET['redirect_uri'] = $client->getRedirectUri(); - $_POST['action'] = 'approve'; - $_POST['username'] = 'user'; - $_POST['password'] = 'pass'; - $response = $server->respondToAccessTokenRequest(ServerRequestFactory::fromGlobals(), new Response); - $this->assertTrue($response instanceof ResponseInterface); - $this->assertEquals(302, $response->getStatusCode()); - $this->assertTrue(strstr($response->getHeaderLine('location'), 'code=') !== false); - } - public function testGetResponseType() { $clientRepository = $this->getMock(ClientRepositoryInterface::class); @@ -144,7 +96,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase $this->assertTrue($method->invoke($server) instanceof BearerTokenResponse); } - public function testValidateRequest() + public function testValidateAuthenticatedRequest() { $clientRepository = $this->getMock(ClientRepositoryInterface::class); @@ -162,4 +114,113 @@ class ServerTest extends \PHPUnit_Framework_TestCase $this->assertEquals('Missing "Authorization" header', $e->getHint()); } } + + public function testCompleteAuthorizationRequest() + { + $clientRepository = $this->getMock(ClientRepositoryInterface::class); + + $server = new Server( + $clientRepository, + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + 'file://' . __DIR__ . '/Stubs/private.key', + 'file://' . __DIR__ . '/Stubs/public.key' + ); + + $authCodeRepository = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(); + $authCodeRepository->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); + + $grant = new AuthCodeGrant( + $authCodeRepository, + $this->getMock(RefreshTokenRepositoryInterface::class), + $this->getMock(UserRepositoryInterface::class), + new \DateInterval('PT10M') + ); + + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/Stubs/private.key')); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/Stubs/public.key')); + + $server->enableGrantType($grant); + + $authRequest = new AuthorizationRequest(); + $authRequest->setAuthorizationApproved(true); + $authRequest->setClient(new ClientEntity()); + $authRequest->setGrantTypeId('authorization_code'); + $authRequest->setUser(new UserEntity()); + + $this->assertTrue( + $server->completeAuthorizationRequest($authRequest, new Response) instanceof ResponseInterface + ); + } + + public function testValidateAuthorizationRequest() + { + $client = new ClientEntity(); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $this->getMock(UserRepositoryInterface::class), + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + + $server = new Server( + $clientRepositoryMock, + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + 'file://' . __DIR__ . '/Stubs/private.key', + 'file://' . __DIR__ . '/Stubs/public.key' + ); + $server->enableGrantType($grant); + + $request = new ServerRequest( + [], + [], + null, + null, + 'php://input', + $headers = [], + $cookies = [], + $queryParams = [ + 'response_type' => 'code', + 'client_id' => 'foo', + ] + ); + + $this->assertTrue($server->validateAuthorizationRequest($request) instanceof AuthorizationRequest); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 2 + */ + public function testValidateAuthorizationRequestUnregistered() + { + $server = new Server( + $this->getMock(ClientRepositoryInterface::class), + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + 'file://' . __DIR__ . '/Stubs/private.key', + 'file://' . __DIR__ . '/Stubs/public.key' + ); + + $request = new ServerRequest( + [], + [], + null, + null, + 'php://input', + $headers = [], + $cookies = [], + $queryParams = [ + 'response_type' => 'code', + 'client_id' => 'foo', + ] + ); + + $server->validateAuthorizationRequest($request); + } } From 6359535e322723f519760a89e094b455f7eac054 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 15:58:23 +0100 Subject: [PATCH 409/444] Updated examples composer requirements --- examples/composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/composer.json b/examples/composer.json index c601e3d1..0b85ac70 100644 --- a/examples/composer.json +++ b/examples/composer.json @@ -7,8 +7,7 @@ ], "require": { "slim/slim": "3.0.*", - "league/oauth2-server": "dev-V5-authorization-request-flow", - "league/plates": "^3.1" + "league/oauth2-server": "dev-V5-WIP" }, "autoload": { "psr-4": { From 6083870603d01b92d29153fcbbf53b3466d90f72 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 10:58:33 -0400 Subject: [PATCH 410/444] Applied fixes from StyleCI --- tests/Grant/AuthCodeGrantTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 93dfcae6..4e3aec78 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -14,7 +14,6 @@ use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\RequestTypes\AuthorizationRequest; -use League\OAuth2\Server\ResponseTypes\HtmlResponse; use League\OAuth2\Server\ResponseTypes\RedirectResponse; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\AuthCodeEntity; @@ -24,7 +23,6 @@ use LeagueTests\Stubs\RefreshTokenEntity; use LeagueTests\Stubs\ScopeEntity; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; -use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase From 92a483b3bd00d2de263d2e2fcf0c8b6e2f30d453 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 16:14:01 +0100 Subject: [PATCH 411/444] Improved tests --- src/Grant/AuthCodeGrant.php | 4 - src/Grant/ImplicitGrant.php | 9 +- tests/Grant/AuthCodeGrantTest.php | 39 --- tests/Grant/ImplicitGrantTest.php | 496 +++++++++++------------------- tests/ServerTest.php | 2 - 5 files changed, 184 insertions(+), 366 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 92cefe44..957171cb 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -8,7 +8,6 @@ use League\OAuth2\Server\Entities\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; -use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\RequestEvent; use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\RedirectResponse; @@ -25,18 +24,15 @@ class AuthCodeGrant extends AbstractAuthorizeGrant /** * @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository - * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository * @param \DateInterval $authCodeTTL */ public function __construct( AuthCodeRepositoryInterface $authCodeRepository, RefreshTokenRepositoryInterface $refreshTokenRepository, - UserRepositoryInterface $userRepository, \DateInterval $authCodeTTL ) { $this->setAuthCodeRepository($authCodeRepository); $this->setRefreshTokenRepository($refreshTokenRepository); - $this->setUserRepository($userRepository); $this->authCodeTTL = $authCodeTTL; $this->refreshTokenTTL = new \DateInterval('P1M'); } diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 05ab7290..1f961ad1 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -5,7 +5,6 @@ namespace League\OAuth2\Server\Grant; use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Entities\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; -use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\RequestEvent; use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\RedirectResponse; @@ -20,12 +19,10 @@ class ImplicitGrant extends AbstractAuthorizeGrant private $accessTokenTTL; /** - * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository - * @param \DateInterval $accessTokenTTL + * @param \DateInterval $accessTokenTTL */ - public function __construct(UserRepositoryInterface $userRepository, \DateInterval $accessTokenTTL) + public function __construct(\DateInterval $accessTokenTTL) { - $this->setUserRepository($userRepository); $this->refreshTokenTTL = new \DateInterval('P1M'); $this->accessTokenTTL = $accessTokenTTL; } @@ -161,7 +158,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant $redirectPayload['access_token'] = (string) $accessToken->convertToJWT($this->privateKey); $redirectPayload['token_type'] = 'bearer'; - $redirectPayload['expires_in'] = $accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp(); + $redirectPayload['expires_in'] = $accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp(); $response = new RedirectResponse(); $response->setRedirectUri( diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 93dfcae6..4b098796 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -44,7 +44,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); @@ -56,7 +55,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); @@ -87,7 +85,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); @@ -120,7 +117,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); @@ -154,7 +150,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); @@ -187,7 +182,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); @@ -223,7 +217,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); @@ -260,7 +253,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); @@ -297,7 +289,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $authCodeRepository, $this->getMock(RefreshTokenRepositoryInterface::class), - $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); @@ -325,7 +316,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $authCodeRepository, $this->getMock(RefreshTokenRepositoryInterface::class), - $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); @@ -343,10 +333,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $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); - $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); $scopeEntity = new ScopeEntity(); $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity); @@ -362,7 +348,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $userRepositoryMock, new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); @@ -414,14 +399,12 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 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); @@ -459,14 +442,12 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $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); @@ -504,10 +485,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $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(); @@ -517,7 +494,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $userRepositoryMock, new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); @@ -570,10 +546,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $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(); @@ -586,7 +558,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $authCodeRepositoryMock, $this->getMock(RefreshTokenRepositoryInterface::class), - $userRepositoryMock, new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); @@ -639,10 +610,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $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(); @@ -652,7 +619,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $userRepositoryMock, new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); @@ -705,10 +671,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $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(); @@ -718,7 +680,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $userRepositoryMock, new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index f8d42930..1090da2c 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -9,6 +9,7 @@ use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\HtmlResponse; use League\OAuth2\Server\ResponseTypes\RedirectResponse; use LeagueTests\Stubs\AccessTokenEntity; @@ -33,14 +34,35 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase public function testGetIdentifier() { - $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); - + $grant = new ImplicitGrant(new \DateInterval('PT10M')); $this->assertEquals('implicit', $grant->getIdentifier()); } - public function testCanRespondToRequest() + public function testCanRespondToAccessTokenRequest() { - $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); + $grant = new ImplicitGrant(new \DateInterval('PT10M')); + + $this->assertFalse( + $grant->canRespondToAccessTokenRequest(new ServerRequest()) + ); + } + + /** + * @expectedException \LogicException + */ + public function testRespondToAccessTokenRequest() + { + $grant = new ImplicitGrant(new \DateInterval('PT10M')); + $grant->respondToAccessTokenRequest( + new ServerRequest(), + new StubResponseType(), + new \DateInterval('PT10M') + ); + } + + public function testCanRespondToAuthorizationRequest() + { + $grant = new ImplicitGrant(new \DateInterval('PT10M')); $request = new ServerRequest( [], @@ -48,390 +70,234 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase null, null, 'php://input', - [], - [], - [ + $headers = [], + $cookies = [], + $queryParams = [ 'response_type' => 'token', + 'client_id' => 'foo', ] ); - $this->assertTrue($grant->canRespondToRequest($request)); + $this->assertTrue($grant->canRespondToAuthorizationRequest($request)); } - public function testRespondToAuthorizationRequest() + public function testValidateAuthorizationRequest() { $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); - - $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); - $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); - - $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); - $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); - - $grant = new ImplicitGrant($userRepositoryMock); + $grant = new ImplicitGrant(new \DateInterval('PT10M')); $grant->setClientRepository($clientRepositoryMock); - $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setScopeRepository($scopeRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], + [], [], null, - 'POST', + null, 'php://input', - [], - [], - [ - 'response_type' => 'token', + $headers = [], + $cookies = [], + $queryParams = [ + 'response_type' => 'code', 'client_id' => 'foo', - 'state' => 'foobar', - ], - [ - 'username' => 'alex', - 'password' => 'whisky', - 'action' => 'approve', + 'redirect_uri' => 'http://foo/bar', ] ); - $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + $this->assertTrue($grant->validateAuthorizationRequest($request) instanceof AuthorizationRequest); + } - $this->assertTrue($response instanceof RedirectResponse); + public function testValidateAuthorizationRequestRedirectUriArray() + { + $client = new ClientEntity(); + $client->setRedirectUri(['http://foo/bar']); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $grant = new ImplicitGrant(new \DateInterval('PT10M')); + $grant->setClientRepository($clientRepositoryMock); + + $request = new ServerRequest( + [], + [], + null, + null, + 'php://input', + $headers = [], + $cookies = [], + $queryParams = [ + 'response_type' => 'code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + ] + ); + + $this->assertTrue($grant->validateAuthorizationRequest($request) instanceof AuthorizationRequest); } /** * @expectedException \League\OAuth2\Server\Exception\OAuthServerException * @expectedExceptionCode 3 */ - public function testRespondToAuthorizationRequestMissingClientId() + public function testValidateAuthorizationRequestMissingClientId() { - $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - - $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], - [], - null, - 'POST', - 'php://input', - [], - [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), - ], - [ - 'response_type' => 'token', - ], - [ - 'username' => 'alex', - 'password' => 'whisky', - 'action' => 'approve', - ] - ); - - $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); - } - - public function testRespondToAuthorizationRequestBadClient() - { - $client = null; $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); - $clientRepositoryMock->method('getClientEntity')->willReturn($client); - $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); + $grant = new ImplicitGrant(new \DateInterval('PT10M')); $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], + [], [], null, - 'POST', + null, 'php://input', - [], - [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), - ], - [ - 'response_type' => 'token', - 'client_id' => 'foo', - ], - [ - 'username' => 'alex', - 'password' => 'whisky', - 'action' => 'approve', + $headers = [], + $cookies = [], + $queryParams = [ + 'response_type' => 'code', ] ); - 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 ImplicitGrant($this->getMock(UserRepositoryInterface::class)); - $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - - $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], - [], - null, - 'POST', - 'php://input', - [], - [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), - ], - [ - 'response_type' => 'token', - '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'); - } + $grant->validateAuthorizationRequest($request); } /** * @expectedException \League\OAuth2\Server\Exception\OAuthServerException - * @expectedExceptionCode 7 + * @expectedExceptionCode 4 */ - public function testRespondToAuthorizationRequestBadCookie() + public function testValidateAuthorizationRequestInvalidClientId() { - $client = new ClientEntity(); - $client->setRedirectUri('http://foo/bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); - $clientRepositoryMock->method('getClientEntity')->willReturn($client); + $clientRepositoryMock->method('getClientEntity')->willReturn(null); - $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); - $userEntity = new UserEntity(); - $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); - - $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); + $grant = new ImplicitGrant(new \DateInterval('PT10M')); $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], + [], [], null, - 'POST', - 'php://input', - [], - [ - 'oauth_authorize_request' => 'blah', - ], - [ - 'response_type' => 'token', - 'client_id' => 'foo', - ], - [ - 'username' => 'alex', - 'password' => 'whisky', - 'action' => 'approve', - ] - ); - - $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); - } - - 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); - - $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); - - $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); - $grant->setClientRepository($clientRepositoryMock); - $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - - $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], - [], null, - 'POST', 'php://input', - [], - [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => null])), - ], - [ - 'response_type' => 'token', - 'client_id' => 'foo', - ], - [ - 'username' => 'alex', - 'password' => 'whisky', - 'action' => 'approve', - ] - ); - - $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); - $this->assertTrue($response instanceof HtmlResponse); - - $response = $response->generateHttpResponse(new Response); - $this->assertTrue(strstr((string) $response->getBody(), '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); - - $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); - $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); - - $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); - $grant->setClientRepository($clientRepositoryMock); - $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - - $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], - [], - null, - 'POST', - 'php://input', - [], - [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), - ], - [ + $headers = [], + $cookies = [], + $queryParams = [ 'response_type' => 'code', 'client_id' => 'foo', - ], - [ - 'username' => 'alex', - 'password' => 'whisky', ] ); - $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + $grant->validateAuthorizationRequest($request); + } - $this->assertTrue($response instanceof HtmlResponse); + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 4 + */ + public function testValidateAuthorizationRequestBadRedirectUriString() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); - $response = $response->generateHttpResponse(new Response); - $this->assertTrue(strstr($response->getHeader('set-cookie')[0], 'oauth_authorize_request') !== false); + $grant = new ImplicitGrant(new \DateInterval('PT10M')); + $grant->setClientRepository($clientRepositoryMock); + + $request = new ServerRequest( + [], + [], + null, + null, + 'php://input', + $headers = [], + $cookies = [], + $queryParams = [ + 'response_type' => 'code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://bar', + ] + ); + + $grant->validateAuthorizationRequest($request); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 4 + */ + public function testValidateAuthorizationRequestBadRedirectUriArray() + { + $client = new ClientEntity(); + $client->setRedirectUri(['http://foo/bar']); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $grant = new ImplicitGrant(new \DateInterval('PT10M')); + $grant->setClientRepository($clientRepositoryMock); + + $request = new ServerRequest( + [], + [], + null, + null, + 'php://input', + $headers = [], + $cookies = [], + $queryParams = [ + 'response_type' => 'code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://bar', + ] + ); + + $grant->validateAuthorizationRequest($request); + } + + public function testCompleteAuthorizationRequest() + { + $authRequest = new AuthorizationRequest(); + $authRequest->setAuthorizationApproved(true); + $authRequest->setClient(new ClientEntity()); + $authRequest->setGrantTypeId('authorization_code'); + $authRequest->setUser(new UserEntity()); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $grant = new ImplicitGrant(new \DateInterval('PT10M')); + $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + + $this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse); } /** * @expectedException \League\OAuth2\Server\Exception\OAuthServerException * @expectedExceptionCode 9 */ - public function testRespondToAuthorizationRequestUserDenied() + public function testCompleteAuthorizationRequestDenied() { - $client = new ClientEntity(); - $client->setRedirectUri('http://foo/bar'); - $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); - $clientRepositoryMock->method('getClientEntity')->willReturn($client); + $authRequest = new AuthorizationRequest(); + $authRequest->setAuthorizationApproved(false); + $authRequest->setClient(new ClientEntity()); + $authRequest->setGrantTypeId('authorization_code'); + $authRequest->setUser(new UserEntity()); - $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); - $userEntity = new UserEntity(); - $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); - $grant = new ImplicitGrant($this->getMock(UserRepositoryInterface::class)); - $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant = new ImplicitGrant(new \DateInterval('PT10M')); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $request = new ServerRequest( - [ - 'HTTP_HOST' => 'auth-server.tld', - 'REQUEST_URI' => '/authorize', - ], - [], - null, - 'POST', - 'php://input', - [], - [ - 'oauth_authorize_request' => $this->cryptStub->doEncrypt(json_encode(['user_id' => 123])), - ], - [ - 'response_type' => 'code', - 'client_id' => 'foo', - 'state' => 'foobar', - ], - [ - 'username' => 'alex', - 'password' => 'whisky', - 'action' => 'denied', - ] - ); - - $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + $grant->completeAuthorizationRequest($authRequest); } } diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 2505d5e4..79f7378c 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -133,7 +133,6 @@ class ServerTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $authCodeRepository, $this->getMock(RefreshTokenRepositoryInterface::class), - $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); @@ -162,7 +161,6 @@ class ServerTest extends \PHPUnit_Framework_TestCase $grant = new AuthCodeGrant( $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), - $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); From 495b55d1e832d72b029ece6be700f9b24578e075 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 11:14:08 -0400 Subject: [PATCH 412/444] Applied fixes from StyleCI --- tests/Grant/AuthCodeGrantTest.php | 3 --- tests/Grant/ImplicitGrantTest.php | 5 ----- tests/ServerTest.php | 1 - 3 files changed, 9 deletions(-) diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 4b098796..a3a9eaa4 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -12,9 +12,7 @@ use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; -use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\RequestTypes\AuthorizationRequest; -use League\OAuth2\Server\ResponseTypes\HtmlResponse; use League\OAuth2\Server\ResponseTypes\RedirectResponse; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\AuthCodeEntity; @@ -24,7 +22,6 @@ use LeagueTests\Stubs\RefreshTokenEntity; use LeagueTests\Stubs\ScopeEntity; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; -use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 1090da2c..fbf60b8c 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -3,21 +3,16 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\CryptKey; -use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ImplicitGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; -use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; -use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\RequestTypes\AuthorizationRequest; -use League\OAuth2\Server\ResponseTypes\HtmlResponse; use League\OAuth2\Server\ResponseTypes\RedirectResponse; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\CryptTraitStub; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; -use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; class ImplicitGrantTest extends \PHPUnit_Framework_TestCase diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 79f7378c..ff11754f 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -11,7 +11,6 @@ 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\Repositories\UserRepositoryInterface; use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; use League\OAuth2\Server\Server; From c017b5934274b7da2bd4acefa882d390d3763153 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 16:15:26 +0100 Subject: [PATCH 413/444] Removed dead code --- examples/public/auth_code.php | 2 -- examples/public/implicit.php | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index 12f7cc49..d0ee1a5e 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -29,7 +29,6 @@ $app = new App([ $accessTokenRepository = new AccessTokenRepository(); $authCodeRepository = new AuthCodeRepository(); $refreshTokenRepository = new RefreshTokenRepository(); - $userRepository = new UserRepository(); $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; @@ -48,7 +47,6 @@ $app = new App([ new AuthCodeGrant( $authCodeRepository, $refreshTokenRepository, - $userRepository, new \DateInterval('PT10M') ), new \DateInterval('PT1H') diff --git a/examples/public/implicit.php b/examples/public/implicit.php index d5bce903..a7c441cc 100644 --- a/examples/public/implicit.php +++ b/examples/public/implicit.php @@ -7,7 +7,6 @@ use OAuth2ServerExamples\Entities\UserEntity; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; -use OAuth2ServerExamples\Repositories\UserRepository; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Slim\App; @@ -24,7 +23,6 @@ $app = new App([ $clientRepository = new ClientRepository(); $scopeRepository = new ScopeRepository(); $accessTokenRepository = new AccessTokenRepository(); - $userRepository = new UserRepository(); $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; @@ -39,7 +37,7 @@ $app = new App([ ); // Enable the implicit grant on the server with a token TTL of 1 hour - $server->enableGrantType(new ImplicitGrant($userRepository, new \DateInterval('PT1H'))); + $server->enableGrantType(new ImplicitGrant(new \DateInterval('PT1H'))); return $server; }, From a722659200a68f2c1fba14eb1b74c9e8d78a9e42 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 11:20:06 -0400 Subject: [PATCH 414/444] Applied fixes from StyleCI --- examples/public/auth_code.php | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index d0ee1a5e..88ea114f 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -10,7 +10,6 @@ use OAuth2ServerExamples\Repositories\AuthCodeRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; -use OAuth2ServerExamples\Repositories\UserRepository; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Slim\App; From 883ba8b573065e5132bc78f672815f4bdc8597f6 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 16:27:07 +0100 Subject: [PATCH 415/444] Updated changelog --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb4cb1c4..153e0f78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 5.0.0-RC2 (released 2016-04-XX) + +* Allow multiple client redirect URIs (Issue #511) +* Remove unused mac token interface (Issue #503) +* Handle RSA key passphrase (Issue #502) +* Remove access token repository from response types (Issue #501) +* Remove unnecessary methods from entity interfaces (Issue #490) +* Ensure incoming JWT hasn't expired (Issue #509) +* Fix client identifier passed where user identifier is expected (Issue #498) +* Removed built-in entities; added traits to for quick re-use (Issue #504) +* Redirect uri is required only if the "redirect_uri" parameter was included in the authorization request (Issue #514) +* Removed templating for auth code and implicit grants (Issue #499) + ## 5.0.0-RC1 (release 2016-03-24) Version 5 is a complete code rewrite. From 4c6dab3f5501e7ce3856f96ecec12a5dd22269e0 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 16:28:54 +0100 Subject: [PATCH 416/444] openssl extension requirement added --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 29e0e0e2..b1120086 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,8 @@ The following versions of PHP are supported: * PHP 7.0 * HHVM +The `openssl` extension is also required. + ## Documentation The library documentation can be found at [http://oauth2.thephpleague.com](http://oauth2.thephpleague.com). From 204706f1ff686056878e1f1eee5ec24fbd244204 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 16:31:05 +0100 Subject: [PATCH 417/444] Updated README --- README.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b1120086..71e1fd8a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# PHP OAuth 2.0 Server by [@alexbilbie](https://twitter.com/alexbilbie) +# PHP OAuth 2.0 Server [![Latest Version](http://img.shields.io/packagist/v/league/oauth2-server.svg?style=flat-square)](https://github.com/thephpleague/oauth2-server/releases) [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) @@ -17,14 +17,7 @@ It supports out of the box the following grants: * Resource owner password credentials grant * Refresh grant -You can also easily define your own grants. - -In addition it supports the following token response types: - -* Bearer (JWT) tokens -* MAC tokens - -You can also create you own tokens. +This library was created by Alex Bilbie. Find him on Twitter at [@alexbilbie](https://twitter.com/alexbilbie). ## Requirements From 7b803365f91601c907c669674743c7c4e36c791e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 16:31:55 +0100 Subject: [PATCH 418/444] Updated links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 71e1fd8a..f457c57e 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,8 @@ The `openssl` extension is also required. ## Documentation -The library documentation can be found at [http://oauth2.thephpleague.com](http://oauth2.thephpleague.com). -You can contribute to this documentation in the [gh-pages branch](https://github.com/thephpleague/oauth2-server/tree/gh-pages/). +The library documentation can be found at [https://oauth2.thephpleague.com](https://oauth2.thephpleague.com). +You can contribute to the documentation in the [gh-pages branch](https://github.com/thephpleague/oauth2-server/tree/gh-pages/). ## Changelog From 03e8eb6157ea5ef439f6b36b67f71ecb0632e6d8 Mon Sep 17 00:00:00 2001 From: Bobselp Date: Sun, 10 Apr 2016 18:05:16 +0200 Subject: [PATCH 419/444] revoke an used auth code --- src/Grant/AuthCodeGrant.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 957171cb..01c59f80 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -109,6 +109,9 @@ class AuthCodeGrant extends AbstractAuthorizeGrant // Inject tokens into response type $responseType->setAccessToken($accessToken); $responseType->setRefreshToken($refreshToken); + + // Revoke used auth code + $this->authCodeRepository->revokeAuthCode($authCodePayload->auth_code_id); return $responseType; } From eb7526ae977e84e089aa9b86b617fcb00061c01b Mon Sep 17 00:00:00 2001 From: Bobselp Date: Sun, 10 Apr 2016 18:07:18 +0200 Subject: [PATCH 420/444] finalize scopes for AuthCodeGrant --- src/Grant/AuthCodeGrant.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 01c59f80..d62fc2ed 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -98,6 +98,9 @@ class AuthCodeGrant extends AbstractAuthorizeGrant $scopes[] = $scope; } + + // Finalize the requested scopes + $scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $authCodePayload->user_id); } catch (\LogicException $e) { throw OAuthServerException::invalidRequest('code', 'Cannot decrypt the authorization code'); } From 103b0cc50d43860f8fab1d5d93051ed67c903de4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 17:15:48 +0100 Subject: [PATCH 421/444] Fixed broken test --- tests/Grant/AuthCodeGrantTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index a3a9eaa4..3783d349 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -333,6 +333,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); $scopeEntity = new ScopeEntity(); $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scopeEntity); + $scopeRepositoryMock->method('finalizeScopes')->willReturnArgument(0); $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); From 2328f5960134eee99c225d8f21086d6c9890c90b Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 10 Apr 2016 12:16:40 -0400 Subject: [PATCH 422/444] Applied fixes from StyleCI --- src/Grant/AuthCodeGrant.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index d62fc2ed..5540dd25 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -112,7 +112,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant // Inject tokens into response type $responseType->setAccessToken($accessToken); $responseType->setRefreshToken($refreshToken); - + // Revoke used auth code $this->authCodeRepository->revokeAuthCode($authCodePayload->auth_code_id); From 6e583fdf8a56e1271e86b0bf2cab8c69a24738c4 Mon Sep 17 00:00:00 2001 From: Bobselp Date: Sun, 10 Apr 2016 22:19:42 +0200 Subject: [PATCH 423/444] less verbose exceptions for RefreshTokenGrant For the LogicException you could also use `throw OAuthServerException::invalidRequest('refresh_token', 'Cannot decrypt the authorization code');`, to get the exact same error AuthCodeGrant-php throws if decryption of `code` fails there. The second error hint provides information which doesn't help users of the API, although it is next to impossible to trigger this error due to the encryption. --- src/Grant/RefreshTokenGrant.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 168e9908..0e27af45 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -101,17 +101,13 @@ class RefreshTokenGrant extends AbstractGrant try { $refreshToken = $this->decrypt($encryptedRefreshToken); } catch (\LogicException $e) { - throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: ' . $e->getMessage()); + throw OAuthServerException::invalidRefreshToken('Cannot decrypt the refresh token'); } $refreshTokenData = json_decode($refreshToken, true); if ($refreshTokenData['client_id'] !== $clientId) { $this->getEmitter()->emit(new RequestEvent('refresh_token.client.failed', $request)); - throw OAuthServerException::invalidRefreshToken( - 'Token is not linked to client,' . - ' got: ' . $clientId . - ' expected: ' . $refreshTokenData['client_id'] - ); + throw OAuthServerException::invalidRefreshToken('Token is not linked to client'); } if ($refreshTokenData['expire_time'] < time()) { From f7413c2f15aaa8ba28dc9f5b644f10aef745de6d Mon Sep 17 00:00:00 2001 From: ivyhjk Date: Sun, 10 Apr 2016 19:05:32 -0300 Subject: [PATCH 424/444] Update BearerTokenResponse.php --- src/ResponseTypes/BearerTokenResponse.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index 63598265..a65ecaae 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -39,7 +39,7 @@ class BearerTokenResponse extends AbstractResponseType 'access_token_id' => $this->accessToken->getIdentifier(), 'scopes' => $this->accessToken->getScopes(), 'user_id' => $this->accessToken->getUserIdentifier(), - 'expire_time' => $expireDateTime, + 'expire_time' => $this->refreshToken->getExpiryDateTime()->getTimestamp(), ] ) ); From de635f826fbb9ab6dad1f4c6e81cc8560a7ac59d Mon Sep 17 00:00:00 2001 From: Luca Degasperi Date: Mon, 11 Apr 2016 15:59:47 +0200 Subject: [PATCH 425/444] Update AbstractGrant.php The hint is not necessary since it gets created by the exception with the parameter. --- src/Grant/AbstractGrant.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index ac5591f5..495a08f6 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -148,7 +148,7 @@ abstract class AbstractGrant implements GrantTypeInterface $this->getServerParameter('PHP_AUTH_USER', $request) ); if (is_null($clientId)) { - throw OAuthServerException::invalidRequest('client_id', '`%s` parameter is missing'); + throw OAuthServerException::invalidRequest('client_id'); } // If the client is confidential require the client secret From 16ed4ea51c0a6ad3ba1afa45f5710d0a53fdca1b Mon Sep 17 00:00:00 2001 From: Vincent Klaiber Date: Mon, 11 Apr 2016 16:22:20 +0200 Subject: [PATCH 426/444] Add 5.5.9 to travis We should test against 5.5.9 as well since that is the lowest requirement. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3ebf76cd..1023fe36 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ cache: - vendor php: + - 5.5.9 - 5.5 - 5.6 - 7.0 @@ -21,4 +22,4 @@ script: branches: only: - master - - V5-WIP \ No newline at end of file + - V5-WIP From 8e8ac35dcbcc5db54db493a9c109ff69e4b695d6 Mon Sep 17 00:00:00 2001 From: Vincent Klaiber Date: Mon, 11 Apr 2016 16:23:24 +0200 Subject: [PATCH 427/444] Allow phpunit 5.0 We can allow phpunit 5.0 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5a11fd07..de38ee81 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "psr/http-message": "^1.0" }, "require-dev": { - "phpunit/phpunit": "^4.8", + "phpunit/phpunit": "^4.8 || ^5.0", "zendframework/zend-diactoros": "^1.0" }, "repositories": [ From 88b01b792af98be8b3aa9a787f025fc754992873 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 12 Apr 2016 20:23:05 +0100 Subject: [PATCH 428/444] Clarified example --- examples/public/refresh_token.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index c8c0a396..643431c8 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -37,10 +37,13 @@ $app = new App([ $publicKeyPath ); - // Enable the refresh token grant on the server with a token TTL of 1 hour + // Enable the refresh token grant on the server + $grant = new RefreshTokenGrant($refreshTokenRepository); + $grant->setRefreshTokenTTL(new \DateInterval('P1M')); // The refresh token will expire in 1 month + $server->enableGrantType( - new RefreshTokenGrant($refreshTokenRepository), - new \DateInterval('PT1H') + $grant, + new \DateInterval('PT1H') // The new access token will expire after 1 hour ); return $server; From 94a1c18fa98cc70d9d419c9293903c8d6fca2f06 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Apr 2016 12:12:49 +0100 Subject: [PATCH 429/444] Implict grant does not return return refresh tokens --- src/Grant/ImplicitGrant.php | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 1f961ad1..3c058599 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -5,6 +5,7 @@ namespace League\OAuth2\Server\Grant; use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Entities\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; +use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\RequestEvent; use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\RedirectResponse; @@ -23,10 +24,29 @@ class ImplicitGrant extends AbstractAuthorizeGrant */ public function __construct(\DateInterval $accessTokenTTL) { - $this->refreshTokenTTL = new \DateInterval('P1M'); $this->accessTokenTTL = $accessTokenTTL; } + /** + * @param \DateInterval $refreshTokenTTL + * + * @throw \LogicException + */ + public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL) + { + throw new \LogicException('The Implicit Grant does nto return refresh tokens'); + } + + /** + * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository + * + * @throw \LogicException + */ + public function setRefreshTokenRepository(RefreshTokenRepositoryInterface $refreshTokenRepository) + { + throw new \LogicException('The Implicit Grant does nto return refresh tokens'); + } + /** * {@inheritdoc} */ From 70e32ce9bf8d400a72745fd11fe21ee9cfcb4391 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Apr 2016 12:23:38 +0100 Subject: [PATCH 430/444] Updated changelog --- CHANGELOG.md | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 153e0f78..2386cf4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,42 @@ # Changelog -## 5.0.0-RC2 (released 2016-04-XX) +## 5.0.0 (release 2016-04-17) + +Version 5 is a complete code rewrite. + +* JWT support +* PSR-7 support +* Improved exception errors +* Replace all occurrences of the term "Storage" with "Repository" +* Simplify repositories +* Entities conform to interfaces and use traits +* Auth code grant updated + * Allow support for public clients + * Add support for #439 +* Client credentials grant updated +* Password grant updated + * Allow support for public clients +* Refresh token grant updated +* Implement Implicit grant +* Bearer token output type +* Remove MAC token output type +* Authorization server rewrite +* Resource server class moved to PSR-7 middleware +* Tests +* Much much better documentation + +Changes since RC2: + +* Run unit tests again PHP 5.5.9 as it's the minimum supported version +* Enable PHPUnit 5.0 support +* Improved examples and documentation +* Make it clearer that the implicit grant doesn't support refresh tokens +* Improved refresh token validation errors +* Fixed refresh token expiry date + +## 5.0.0-RC2 (released 2016-04-10) + +Changes since RC1: * Allow multiple client redirect URIs (Issue #511) * Remove unused mac token interface (Issue #503) From 08c356a1e17406341c96312b911b7a5078370f89 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Apr 2016 12:33:29 +0100 Subject: [PATCH 431/444] Added ResourceServer class --- src/Middleware/ResourceServerMiddleware.php | 8 +-- src/ResourceServer.php | 74 +++++++++++++++++++++ 2 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 src/ResourceServer.php diff --git a/src/Middleware/ResourceServerMiddleware.php b/src/Middleware/ResourceServerMiddleware.php index 1b127608..7836a4ce 100644 --- a/src/Middleware/ResourceServerMiddleware.php +++ b/src/Middleware/ResourceServerMiddleware.php @@ -3,23 +3,23 @@ namespace League\OAuth2\Server\Middleware; use League\OAuth2\Server\Exception\OAuthServerException; -use League\OAuth2\Server\Server; +use League\OAuth2\Server\ResourceServer; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; class ResourceServerMiddleware { /** - * @var \League\OAuth2\Server\Server + * @var \League\OAuth2\Server\ResourceServer */ private $server; /** * ResourceServerMiddleware constructor. * - * @param \League\OAuth2\Server\Server $server + * @param \League\OAuth2\Server\ResourceServer $server */ - public function __construct(Server $server) + public function __construct(ResourceServer $server) { $this->server = $server; } diff --git a/src/ResourceServer.php b/src/ResourceServer.php new file mode 100644 index 00000000..1b12e8de --- /dev/null +++ b/src/ResourceServer.php @@ -0,0 +1,74 @@ +accessTokenRepository = $accessTokenRepository; + + if (!$publicKey instanceof CryptKey) { + $publicKey = new CryptKey($publicKey); + } + $this->publicKey = $publicKey; + + $this->authorizationValidator = $authorizationValidator; + } + + /** + * @return \League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface + */ + protected function getAuthorizationValidator() + { + if (!$this->authorizationValidator instanceof AuthorizationValidatorInterface) { + $this->authorizationValidator = new BearerTokenValidator($this->accessTokenRepository); + } + + $this->authorizationValidator->setPublicKey($this->publicKey); + + return $this->authorizationValidator; + } + + /** + * Determine the access token validity. + * + * @param \Psr\Http\Message\ServerRequestInterface $request + * + * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \Psr\Http\Message\ServerRequestInterface + */ + public function validateAuthenticatedRequest(ServerRequestInterface $request) + { + return $this->getAuthorizationValidator()->validateAuthorization($request); + } +} From 9f3648039b92cab9061e9e6dd71a82f0ee6b4bcf Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Apr 2016 12:41:28 +0100 Subject: [PATCH 432/444] Use resource server instead --- examples/public/api.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/examples/public/api.php b/examples/public/api.php index 3c446abb..c82ac5b3 100644 --- a/examples/public/api.php +++ b/examples/public/api.php @@ -1,9 +1,8 @@ function () { // Setup the authorization server - $server = new Server( - new ClientRepository(), + $server = new ResourceServer( new AccessTokenRepository(), - new ScopeRepository(), - 'file://' . __DIR__ . '/../private.key', 'file://' . __DIR__ . '/../public.key' ); @@ -54,12 +50,14 @@ $app->get('/users', function (ServerRequestInterface $request, ResponseInterface ], ]; + // If the access token doesn't have the `basic` scope hide users' names if (in_array('basic', $request->getAttribute('oauth_scopes')) === false) { for ($i = 0; $i < count($users); $i++) { unset($users[$i]['name']); } } + // If the access token doesn't have the `emal` scope hide users' email addresses if (in_array('email', $request->getAttribute('oauth_scopes')) === false) { for ($i = 0; $i < count($users); $i++) { unset($users[$i]['email']); From 6205611a71b31955ca7c23be2edfe4a2234ad05c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Apr 2016 12:42:42 +0100 Subject: [PATCH 433/444] Removed unused methods --- src/Server.php | 40 +--------------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/src/Server.php b/src/Server.php index 65de57eb..84838ba6 100644 --- a/src/Server.php +++ b/src/Server.php @@ -5,8 +5,6 @@ namespace League\OAuth2\Server; use DateInterval; use League\Event\EmitterAwareInterface; use League\Event\EmitterAwareTrait; -use League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface; -use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\GrantTypeInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -62,11 +60,6 @@ class Server implements EmitterAwareInterface */ private $scopeRepository; - /** - * @var \League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface - */ - private $authorizationValidator; - /** * New server instance. * @@ -76,7 +69,6 @@ class Server implements EmitterAwareInterface * @param \League\OAuth2\Server\CryptKey|string $privateKey * @param \League\OAuth2\Server\CryptKey|string $publicKey * @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType - * @param null|\League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface $authorizationValidator */ public function __construct( ClientRepositoryInterface $clientRepository, @@ -84,8 +76,7 @@ class Server implements EmitterAwareInterface ScopeRepositoryInterface $scopeRepository, $privateKey, $publicKey, - ResponseTypeInterface $responseType = null, - AuthorizationValidatorInterface $authorizationValidator = null + ResponseTypeInterface $responseType = null ) { $this->clientRepository = $clientRepository; $this->accessTokenRepository = $accessTokenRepository; @@ -102,7 +93,6 @@ class Server implements EmitterAwareInterface $this->publicKey = $publicKey; $this->responseType = $responseType; - $this->authorizationValidator = $authorizationValidator; } /** @@ -199,20 +189,6 @@ class Server implements EmitterAwareInterface throw OAuthServerException::unsupportedGrantType(); } - /** - * Determine the access token validity. - * - * @param \Psr\Http\Message\ServerRequestInterface $request - * - * @throws \League\OAuth2\Server\Exception\OAuthServerException - * - * @return \Psr\Http\Message\ServerRequestInterface - */ - public function validateAuthenticatedRequest(ServerRequestInterface $request) - { - return $this->getAuthorizationValidator()->validateAuthorization($request); - } - /** * Get the token type that grants will return in the HTTP response. * @@ -228,18 +204,4 @@ class Server implements EmitterAwareInterface return $this->responseType; } - - /** - * @return \League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface - */ - protected function getAuthorizationValidator() - { - if (!$this->authorizationValidator instanceof AuthorizationValidatorInterface) { - $this->authorizationValidator = new BearerTokenValidator($this->accessTokenRepository); - } - - $this->authorizationValidator->setPublicKey($this->publicKey); - - return $this->authorizationValidator; - } } From af5a06098b0b2378a8a5d927ca0252270efdd24b Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Apr 2016 12:43:13 +0100 Subject: [PATCH 434/444] Removed --no-dev statement --- examples/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/README.md b/examples/README.md index 35fdc516..bc785ee6 100644 --- a/examples/README.md +++ b/examples/README.md @@ -2,7 +2,7 @@ ## Installation -0. Run `composer install --no-dev` in this directory to install dependencies +0. Run `composer install` in this directory to install dependencies 0. Create a private key `openssl genrsa -out private.key 1024` 0. Create a public key `openssl rsa -in private.key -pubout > public.key` 0. `cd` into the public directory From c3a7c418daa9dbc45dac31dc2a43b28b2d5d7030 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Apr 2016 12:43:25 +0100 Subject: [PATCH 435/444] Updated composer.json --- examples/composer.json | 18 +- examples/composer.lock | 452 +++++++++++++++-------------------------- 2 files changed, 170 insertions(+), 300 deletions(-) diff --git a/examples/composer.json b/examples/composer.json index 0b85ac70..3c6e550b 100644 --- a/examples/composer.json +++ b/examples/composer.json @@ -1,17 +1,17 @@ { - "repositories": [ - { - "type": "path", - "url": ".." - } - ], "require": { - "slim/slim": "3.0.*", - "league/oauth2-server": "dev-V5-WIP" + "slim/slim": "3.0.*" + }, + "require-dev": { + "league/event": "^2.1", + "lcobucci/jwt": "^3.1", + "paragonie/random_compat": "^1.1", + "psr/http-message": "^1.0" }, "autoload": { "psr-4": { - "OAuth2ServerExamples\\": "src/" + "OAuth2ServerExamples\\": "src/", + "League\\OAuth2\\Server\\": "../src/" } } } diff --git a/examples/composer.lock b/examples/composer.lock index 38924cca..9c6c83cb 100644 --- a/examples/composer.lock +++ b/examples/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "ec2df46ff78a00052e1a241ce5988d81", - "content-hash": "46a1c1e42c62d3e3645279fc54ae95b7", + "hash": "48bcb7a3514d7c7f271c554ba1440124", + "content-hash": "e41be75973527cb9d63f27ad14ac8624", "packages": [ { "name": "container-interop/container-interop", @@ -34,243 +34,6 @@ "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", "time": "2014-12-30 15:22:37" }, - { - "name": "lcobucci/jwt", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/lcobucci/jwt.git", - "reference": "afea8e682e911a21574fd8519321b32522fa25b5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/lcobucci/jwt/zipball/afea8e682e911a21574fd8519321b32522fa25b5", - "reference": "afea8e682e911a21574fd8519321b32522fa25b5", - "shasum": "" - }, - "require": { - "ext-openssl": "*", - "php": ">=5.5" - }, - "require-dev": { - "mdanter/ecc": "~0.3", - "mikey179/vfsstream": "~1.5", - "phpmd/phpmd": "~2.2", - "phpunit/php-invoker": "~1.1", - "phpunit/phpunit": "~4.5", - "squizlabs/php_codesniffer": "~2.3" - }, - "suggest": { - "mdanter/ecc": "Required to use Elliptic Curves based algorithms." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "psr-4": { - "Lcobucci\\JWT\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Luís Otávio Cobucci Oblonczyk", - "email": "lcobucci@gmail.com", - "role": "Developer" - } - ], - "description": "A simple library to work with JSON Web Token and JSON Web Signature", - "keywords": [ - "JWS", - "jwt" - ], - "time": "2016-03-24 22:46:13" - }, - { - "name": "league/event", - "version": "2.1.2", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/event.git", - "reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/event/zipball/e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd", - "reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "henrikbjorn/phpspec-code-coverage": "~1.0.1", - "phpspec/phpspec": "~2.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.2-dev" - } - }, - "autoload": { - "psr-4": { - "League\\Event\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Frank de Jonge", - "email": "info@frenky.net" - } - ], - "description": "Event package", - "keywords": [ - "emitter", - "event", - "listener" - ], - "time": "2015-05-21 12:24:47" - }, - { - "name": "league/oauth2-server", - "version": "dev-V5-authorization-request-flow", - "dist": { - "type": "path", - "url": "../", - "reference": "5410a42bb66f5a61969c3ec1a8e7ab30d225875c", - "shasum": null - }, - "require": { - "lcobucci/jwt": "^3.1", - "league/event": "^2.1", - "paragonie/random_compat": "^1.1", - "php": ">=5.5.9", - "psr/http-message": "^1.0" - }, - "replace": { - "league/oauth2server": "*", - "lncd/oauth2": "*" - }, - "require-dev": { - "league/plates": "^3.1", - "phpunit/phpunit": "^4.8", - "zendframework/zend-diactoros": "^1.0" - }, - "suggest": { - "league/plates": "Used for parsing authorization code templates", - "mustache/mustache": "Used for parsing authorization code templates", - "smarty/smarty": "Used for parsing authorization code templates", - "twig/twig": "Used for parsing authorization code templates" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-V5-WIP": "5.0-dev" - } - }, - "autoload": { - "psr-4": { - "League\\OAuth2\\Server\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "LeagueTests\\": "tests/" - } - }, - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Alex Bilbie", - "email": "hello@alexbilbie.com", - "homepage": "http://www.alexbilbie.com", - "role": "Developer" - } - ], - "description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.", - "homepage": "http://oauth2.thephpleague.com/", - "keywords": [ - "api", - "auth", - "auth", - "authentication", - "authorisation", - "authorization", - "oauth", - "oauth 2", - "oauth 2.0", - "oauth2", - "protect", - "resource", - "secure", - "server" - ] - }, - { - "name": "league/plates", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/plates.git", - "reference": "2d8569e9f140a70d6a05db38006926f7547cb802" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/plates/zipball/2d8569e9f140a70d6a05db38006926f7547cb802", - "reference": "2d8569e9f140a70d6a05db38006926f7547cb802", - "shasum": "" - }, - "require-dev": { - "mikey179/vfsstream": "~1.4.0", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~1.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "psr-4": { - "League\\Plates\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jonathan Reinink", - "email": "jonathan@reinink.ca", - "role": "Developer" - } - ], - "description": "Plates, the native PHP template system that's fast, easy to use and easy to extend.", - "homepage": "http://platesphp.com", - "keywords": [ - "league", - "package", - "templates", - "templating", - "views" - ], - "time": "2015-07-09 02:14:40" - }, { "name": "nikic/fast-route", "version": "v0.6.0", @@ -314,54 +77,6 @@ ], "time": "2015-06-18 19:15:47" }, - { - "name": "paragonie/random_compat", - "version": "v1.4.1", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "c7e26a21ba357863de030f0b9e701c7d04593774" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/c7e26a21ba357863de030f0b9e701c7d04593774", - "reference": "c7e26a21ba357863de030f0b9e701c7d04593774", - "shasum": "" - }, - "require": { - "php": ">=5.2.0" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "type": "library", - "autoload": { - "files": [ - "lib/random.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com" - } - ], - "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", - "keywords": [ - "csprng", - "pseudorandom", - "random" - ], - "time": "2016-03-18 20:34:03" - }, { "name": "pimple/pimple", "version": "v3.0.2", @@ -524,12 +239,167 @@ "time": "2015-12-07 14:11:09" } ], - "packages-dev": [], + "packages-dev": [ + { + "name": "lcobucci/jwt", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "afea8e682e911a21574fd8519321b32522fa25b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/afea8e682e911a21574fd8519321b32522fa25b5", + "reference": "afea8e682e911a21574fd8519321b32522fa25b5", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">=5.5" + }, + "require-dev": { + "mdanter/ecc": "~0.3", + "mikey179/vfsstream": "~1.5", + "phpmd/phpmd": "~2.2", + "phpunit/php-invoker": "~1.1", + "phpunit/phpunit": "~4.5", + "squizlabs/php_codesniffer": "~2.3" + }, + "suggest": { + "mdanter/ecc": "Required to use Elliptic Curves based algorithms." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Luís Otávio Cobucci Oblonczyk", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "keywords": [ + "JWS", + "jwt" + ], + "time": "2016-03-24 22:46:13" + }, + { + "name": "league/event", + "version": "2.1.2", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/event.git", + "reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/event/zipball/e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd", + "reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "henrikbjorn/phpspec-code-coverage": "~1.0.1", + "phpspec/phpspec": "~2.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Event\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Event package", + "keywords": [ + "emitter", + "event", + "listener" + ], + "time": "2015-05-21 12:24:47" + }, + { + "name": "paragonie/random_compat", + "version": "v1.4.1", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "c7e26a21ba357863de030f0b9e701c7d04593774" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/c7e26a21ba357863de030f0b9e701c7d04593774", + "reference": "c7e26a21ba357863de030f0b9e701c7d04593774", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "pseudorandom", + "random" + ], + "time": "2016-03-18 20:34:03" + } + ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "league/oauth2-server": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": [], From 3904767873cad465c8b50ad78f19feeb34b19288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Unger?= Date: Sun, 17 Apr 2016 13:50:56 +0200 Subject: [PATCH 436/444] Fix scope loading in grants --- src/Grant/AbstractGrant.php | 2 +- src/Grant/AuthCodeGrant.php | 3 ++- src/Grant/RefreshTokenGrant.php | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 495a08f6..21909712 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -215,7 +215,7 @@ abstract class AbstractGrant implements GrantTypeInterface foreach ($scopesList as $scopeItem) { $scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeItem); - if (($scope instanceof ScopeEntityInterface) === false) { + if (!$scope instanceof ScopeEntityInterface) { throw OAuthServerException::invalidScope($scopeItem, $redirectUri); } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 5540dd25..569d72f1 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -4,6 +4,7 @@ namespace League\OAuth2\Server\Grant; use DateInterval; use League\OAuth2\Server\Entities\ClientEntityInterface; +use League\OAuth2\Server\Entities\ScopeEntityInterface; use League\OAuth2\Server\Entities\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; @@ -90,7 +91,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant foreach ($authCodePayload->scopes as $scopeId) { $scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeId); - if ($scope === false) { + if (!$scope instanceof ScopeEntityInterface) { // @codeCoverageIgnoreStart throw OAuthServerException::invalidScope($scopeId); // @codeCoverageIgnoreEnd diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 0e27af45..0d65fae6 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -10,6 +10,7 @@ */ namespace League\OAuth2\Server\Grant; +use League\OAuth2\Server\Entities\ScopeEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\RequestEvent; @@ -49,7 +50,7 @@ class RefreshTokenGrant extends AbstractGrant $scopes = array_map(function ($scopeId) use ($client) { $scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeId); - if (!$scope) { + if (!$scope instanceof ScopeEntityInterface) { // @codeCoverageIgnoreStart throw OAuthServerException::invalidScope($scopeId); // @codeCoverageIgnoreEnd From f6f39698d90e5598ca03bc39c9c7d9b0f2eaa192 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Apr 2016 12:54:25 +0100 Subject: [PATCH 437/444] Renamed Server to AuthorizationServer --- src/{Server.php => AuthorizationServer.php} | 2 +- ....php => AuthorizationServerMiddleware.php} | 12 +++--- ...erTest.php => AuthorizationServerTest.php} | 37 +++++-------------- ... => AuthorizationServerMiddlewareTest.php} | 14 +++---- 4 files changed, 23 insertions(+), 42 deletions(-) rename src/{Server.php => AuthorizationServer.php} (99%) rename src/Middleware/{AuthenticationServerMiddleware.php => AuthorizationServerMiddleware.php} (80%) rename tests/{ServerTest.php => AuthorizationServerTest.php} (88%) rename tests/Middleware/{AuthenticationServerMiddlewareTest.php => AuthorizationServerMiddlewareTest.php} (90%) diff --git a/src/Server.php b/src/AuthorizationServer.php similarity index 99% rename from src/Server.php rename to src/AuthorizationServer.php index 84838ba6..2c4d62e8 100644 --- a/src/Server.php +++ b/src/AuthorizationServer.php @@ -16,7 +16,7 @@ use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -class Server implements EmitterAwareInterface +class AuthorizationServer implements EmitterAwareInterface { use EmitterAwareTrait; diff --git a/src/Middleware/AuthenticationServerMiddleware.php b/src/Middleware/AuthorizationServerMiddleware.php similarity index 80% rename from src/Middleware/AuthenticationServerMiddleware.php rename to src/Middleware/AuthorizationServerMiddleware.php index 83f3f1c5..d4f2e758 100644 --- a/src/Middleware/AuthenticationServerMiddleware.php +++ b/src/Middleware/AuthorizationServerMiddleware.php @@ -3,23 +3,23 @@ namespace League\OAuth2\Server\Middleware; use League\OAuth2\Server\Exception\OAuthServerException; -use League\OAuth2\Server\Server; +use League\OAuth2\Server\AuthorizationServer; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; -class AuthenticationServerMiddleware +class AuthorizationServerMiddleware { /** - * @var \League\OAuth2\Server\Server + * @var \League\OAuth2\Server\AuthorizationServer */ private $server; /** - * AuthenticationServerMiddleware constructor. + * AuthorizationServerMiddleware constructor. * - * @param \League\OAuth2\Server\Server $server + * @param \League\OAuth2\Server\AuthorizationServer $server */ - public function __construct(Server $server) + public function __construct(AuthorizationServer $server) { $this->server = $server; } diff --git a/tests/ServerTest.php b/tests/AuthorizationServerTest.php similarity index 88% rename from tests/ServerTest.php rename to tests/AuthorizationServerTest.php index ff11754f..86eb24df 100644 --- a/tests/ServerTest.php +++ b/tests/AuthorizationServerTest.php @@ -13,7 +13,7 @@ use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; -use League\OAuth2\Server\Server; +use League\OAuth2\Server\AuthorizationServer; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\AuthCodeEntity; use LeagueTests\Stubs\ClientEntity; @@ -24,11 +24,11 @@ use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; use Zend\Diactoros\ServerRequestFactory; -class ServerTest extends \PHPUnit_Framework_TestCase +class AuthorizationServerTest extends \PHPUnit_Framework_TestCase { public function testRespondToRequestInvalidGrantType() { - $server = new Server( + $server = new AuthorizationServer( $this->getMock(ClientRepositoryInterface::class), $this->getMock(AccessTokenRepositoryInterface::class), $this->getMock(ScopeRepositoryInterface::class), @@ -58,7 +58,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock = $this->getMock(AccessTokenRepositoryInterface::class); $accessTokenRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); - $server = new Server( + $server = new AuthorizationServer( $clientRepository, $accessTokenRepositoryMock, $scopeRepositoryMock, @@ -80,7 +80,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase { $clientRepository = $this->getMock(ClientRepositoryInterface::class); - $server = new Server( + $server = new AuthorizationServer( $clientRepository, $this->getMock(AccessTokenRepositoryInterface::class), $this->getMock(ScopeRepositoryInterface::class), @@ -94,31 +94,12 @@ class ServerTest extends \PHPUnit_Framework_TestCase $this->assertTrue($method->invoke($server) instanceof BearerTokenResponse); } - - public function testValidateAuthenticatedRequest() - { - $clientRepository = $this->getMock(ClientRepositoryInterface::class); - - $server = new Server( - $clientRepository, - $this->getMock(AccessTokenRepositoryInterface::class), - $this->getMock(ScopeRepositoryInterface::class), - 'file://' . __DIR__ . '/Stubs/private.key', - 'file://' . __DIR__ . '/Stubs/public.key' - ); - - try { - $server->validateAuthenticatedRequest(ServerRequestFactory::fromGlobals()); - } catch (OAuthServerException $e) { - $this->assertEquals('Missing "Authorization" header', $e->getHint()); - } - } - + public function testCompleteAuthorizationRequest() { $clientRepository = $this->getMock(ClientRepositoryInterface::class); - $server = new Server( + $server = new AuthorizationServer( $clientRepository, $this->getMock(AccessTokenRepositoryInterface::class), $this->getMock(ScopeRepositoryInterface::class), @@ -164,7 +145,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase ); $grant->setClientRepository($clientRepositoryMock); - $server = new Server( + $server = new AuthorizationServer( $clientRepositoryMock, $this->getMock(AccessTokenRepositoryInterface::class), $this->getMock(ScopeRepositoryInterface::class), @@ -196,7 +177,7 @@ class ServerTest extends \PHPUnit_Framework_TestCase */ public function testValidateAuthorizationRequestUnregistered() { - $server = new Server( + $server = new AuthorizationServer( $this->getMock(ClientRepositoryInterface::class), $this->getMock(AccessTokenRepositoryInterface::class), $this->getMock(ScopeRepositoryInterface::class), diff --git a/tests/Middleware/AuthenticationServerMiddlewareTest.php b/tests/Middleware/AuthorizationServerMiddlewareTest.php similarity index 90% rename from tests/Middleware/AuthenticationServerMiddlewareTest.php rename to tests/Middleware/AuthorizationServerMiddlewareTest.php index d9302cae..f04b7572 100644 --- a/tests/Middleware/AuthenticationServerMiddlewareTest.php +++ b/tests/Middleware/AuthorizationServerMiddlewareTest.php @@ -4,18 +4,18 @@ namespace LeagueTests\Middleware; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ClientCredentialsGrant; -use League\OAuth2\Server\Middleware\AuthenticationServerMiddleware; +use League\OAuth2\Server\Middleware\AuthorizationServerMiddleware; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; -use League\OAuth2\Server\Server; +use League\OAuth2\Server\AuthorizationServer; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequestFactory; -class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase +class AuthorizationServerMiddlewareTest extends \PHPUnit_Framework_TestCase { public function testValidResponse() { @@ -28,7 +28,7 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase $accessRepositoryMock = $this->getMock(AccessTokenRepositoryInterface::class); $accessRepositoryMock->method('getNewToken')->willReturn(new AccessTokenEntity()); - $server = new Server( + $server = new AuthorizationServer( $clientRepository, $accessRepositoryMock, $scopeRepositoryMock, @@ -45,7 +45,7 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase $request = ServerRequestFactory::fromGlobals(); - $middleware = new AuthenticationServerMiddleware($server); + $middleware = new AuthorizationServerMiddleware($server); $response = $middleware->__invoke( $request, new Response(), @@ -61,7 +61,7 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase $clientRepository = $this->getMock(ClientRepositoryInterface::class); $clientRepository->method('getClientEntity')->willReturn(null); - $server = new Server( + $server = new AuthorizationServer( $clientRepository, $this->getMock(AccessTokenRepositoryInterface::class), $this->getMock(ScopeRepositoryInterface::class), @@ -78,7 +78,7 @@ class AuthenticationServerMiddlewareTest extends \PHPUnit_Framework_TestCase $request = ServerRequestFactory::fromGlobals(); - $middleware = new AuthenticationServerMiddleware($server); + $middleware = new AuthorizationServerMiddleware($server); $response = $middleware->__invoke( $request, From 7c35778316e365c8447a5988730ca312ddfbdfb2 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Apr 2016 12:54:39 +0100 Subject: [PATCH 438/444] Added tests for resource server middleware --- .../ResourceServerMiddlewareTest.php | 35 ++++--------------- tests/ResourceServerTest.php | 28 +++++++++++++++ 2 files changed, 35 insertions(+), 28 deletions(-) create mode 100644 tests/ResourceServerTest.php diff --git a/tests/Middleware/ResourceServerMiddlewareTest.php b/tests/Middleware/ResourceServerMiddlewareTest.php index a71dc5ab..e91e9b9b 100644 --- a/tests/Middleware/ResourceServerMiddlewareTest.php +++ b/tests/Middleware/ResourceServerMiddlewareTest.php @@ -5,12 +5,9 @@ namespace LeagueTests\Middleware; use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Middleware\ResourceServerMiddleware; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; -use League\OAuth2\Server\Repositories\ClientRepositoryInterface; -use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; -use League\OAuth2\Server\Server; +use League\OAuth2\Server\ResourceServer; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; -use LeagueTests\Stubs\StubResponseType; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; @@ -18,15 +15,9 @@ class ResourceServerMiddlewareTest extends \PHPUnit_Framework_TestCase { public function testValidResponse() { - $clientRepository = $this->getMock(ClientRepositoryInterface::class); - - $server = new Server( - $clientRepository, + $server = new ResourceServer( $this->getMock(AccessTokenRepositoryInterface::class), - $this->getMock(ScopeRepositoryInterface::class), - 'file://' . __DIR__ . '/../Stubs/private.key', - 'file://' . __DIR__ . '/../Stubs/public.key', - new StubResponseType() + 'file://' . __DIR__ . '/../Stubs/public.key' ); $client = new ClientEntity(); @@ -59,15 +50,9 @@ class ResourceServerMiddlewareTest extends \PHPUnit_Framework_TestCase public function testValidResponseExpiredToken() { - $clientRepository = $this->getMock(ClientRepositoryInterface::class); - - $server = new Server( - $clientRepository, + $server = new ResourceServer( $this->getMock(AccessTokenRepositoryInterface::class), - $this->getMock(ScopeRepositoryInterface::class), - 'file://' . __DIR__ . '/../Stubs/private.key', - 'file://' . __DIR__ . '/../Stubs/public.key', - new StubResponseType() + 'file://' . __DIR__ . '/../Stubs/public.key' ); $client = new ClientEntity(); @@ -100,15 +85,9 @@ class ResourceServerMiddlewareTest extends \PHPUnit_Framework_TestCase public function testErrorResponse() { - $clientRepository = $this->getMock(ClientRepositoryInterface::class); - - $server = new Server( - $clientRepository, + $server = new ResourceServer( $this->getMock(AccessTokenRepositoryInterface::class), - $this->getMock(ScopeRepositoryInterface::class), - 'file://' . __DIR__ . '/../Stubs/private.key', - 'file://' . __DIR__ . '/../Stubs/public.key', - new StubResponseType() + 'file://' . __DIR__ . '/../Stubs/public.key' ); $request = new ServerRequest(); diff --git a/tests/ResourceServerTest.php b/tests/ResourceServerTest.php new file mode 100644 index 00000000..12365c47 --- /dev/null +++ b/tests/ResourceServerTest.php @@ -0,0 +1,28 @@ +getMock(AccessTokenRepositoryInterface::class), + 'file://' . __DIR__ . '/Stubs/public.key' + ); + + try { + $server->validateAuthenticatedRequest(ServerRequestFactory::fromGlobals()); + } catch (OAuthServerException $e) { + $this->assertEquals('Missing "Authorization" header', $e->getHint()); + } + } + +} From 6ed9cbf70162cdcef7a0647e0c06a01afe7aaf75 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Apr 2016 12:54:49 +0100 Subject: [PATCH 439/444] Class rename fixes --- examples/public/api.php | 5 ++--- examples/public/auth_code.php | 15 +++++++-------- examples/public/implicit.php | 10 +++++----- examples/public/middleware_use.php | 17 +++++++---------- examples/public/password.php | 10 +++++----- examples/public/refresh_token.php | 10 +++++----- 6 files changed, 31 insertions(+), 36 deletions(-) diff --git a/examples/public/api.php b/examples/public/api.php index c82ac5b3..26474f0d 100644 --- a/examples/public/api.php +++ b/examples/public/api.php @@ -1,7 +1,6 @@ [ 'displayErrorDetails' => true, ], - Server::class => function () { + ResourceServer::class => function () { // Setup the authorization server $server = new ResourceServer( new AccessTokenRepository(), @@ -26,7 +25,7 @@ $app = new App([ $app->add( new \League\OAuth2\Server\Middleware\ResourceServerMiddleware( - $app->getContainer()->get(Server::class) + $app->getContainer()->get(ResourceServer::class) ) ); diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index 88ea114f..2a0b4c41 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -2,8 +2,7 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; -use League\OAuth2\Server\RequestTypes\AuthorizationRequest; -use League\OAuth2\Server\Server; +use League\OAuth2\Server\AuthorizationServer; use OAuth2ServerExamples\Entities\UserEntity; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\AuthCodeRepository; @@ -21,7 +20,7 @@ $app = new App([ 'settings' => [ 'displayErrorDetails' => true, ], - Server::class => function () { + AuthorizationServer::class => function () { // Init our repositories $clientRepository = new ClientRepository(); $scopeRepository = new ScopeRepository(); @@ -33,7 +32,7 @@ $app = new App([ $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server - $server = new Server( + $server = new AuthorizationServer( $clientRepository, $accessTokenRepository, $scopeRepository, @@ -56,8 +55,8 @@ $app = new App([ ]); $app->get('/authorize', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { - /* @var \League\OAuth2\Server\Server $server */ - $server = $app->getContainer()->get(Server::class); + /* @var \League\OAuth2\Server\AuthorizationServer $server */ + $server = $app->getContainer()->get(AuthorizationServer::class); try { // Validate the HTTP request and return an AuthorizationRequest object. @@ -84,8 +83,8 @@ $app->get('/authorize', function (ServerRequestInterface $request, ResponseInter }); $app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { - /* @var \League\OAuth2\Server\Server $server */ - $server = $app->getContainer()->get(Server::class); + /* @var \League\OAuth2\Server\AuthorizationServer $server */ + $server = $app->getContainer()->get(AuthorizationServer::class); try { return $server->respondToAccessTokenRequest($request, $response); diff --git a/examples/public/implicit.php b/examples/public/implicit.php index a7c441cc..eee6abb3 100644 --- a/examples/public/implicit.php +++ b/examples/public/implicit.php @@ -2,7 +2,7 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ImplicitGrant; -use League\OAuth2\Server\Server; +use League\OAuth2\Server\AuthorizationServer; use OAuth2ServerExamples\Entities\UserEntity; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; @@ -18,7 +18,7 @@ $app = new App([ 'settings' => [ 'displayErrorDetails' => true, ], - Server::class => function () { + AuthorizationServer::class => function () { // Init our repositories $clientRepository = new ClientRepository(); $scopeRepository = new ScopeRepository(); @@ -28,7 +28,7 @@ $app = new App([ $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server - $server = new Server( + $server = new AuthorizationServer( $clientRepository, $accessTokenRepository, $scopeRepository, @@ -44,8 +44,8 @@ $app = new App([ ]); $app->get('/authorize', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { - /* @var \League\OAuth2\Server\Server $server */ - $server = $app->getContainer()->get(Server::class); + /* @var \League\OAuth2\Server\AuthorizationServer $server */ + $server = $app->getContainer()->get(AuthorizationServer::class); try { // Validate the HTTP request and return an AuthorizationRequest object. diff --git a/examples/public/middleware_use.php b/examples/public/middleware_use.php index 9b8e0991..ae8b6f05 100644 --- a/examples/public/middleware_use.php +++ b/examples/public/middleware_use.php @@ -2,15 +2,14 @@ use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\RefreshTokenGrant; -use League\OAuth2\Server\Middleware\AuthenticationServerMiddleware; +use League\OAuth2\Server\Middleware\AuthorizationServerMiddleware; use League\OAuth2\Server\Middleware\ResourceServerMiddleware; -use League\OAuth2\Server\Server; +use League\OAuth2\Server\AuthorizationServer; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\AuthCodeRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; -use OAuth2ServerExamples\Repositories\UserRepository; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Slim\App; @@ -19,23 +18,22 @@ use Zend\Diactoros\Stream; include __DIR__ . '/../vendor/autoload.php'; $app = new App([ - 'settings' => [ + 'settings' => [ 'displayErrorDetails' => true, ], - Server::class => function () { + AuthorizationServer::class => function () { // Init our repositories $clientRepository = new ClientRepository(); $accessTokenRepository = new AccessTokenRepository(); $scopeRepository = new ScopeRepository(); $authCodeRepository = new AuthCodeRepository(); $refreshTokenRepository = new RefreshTokenRepository(); - $userRepository = new UserRepository(); $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server - $server = new Server( + $server = new AuthorizationServer( $clientRepository, $accessTokenRepository, $scopeRepository, @@ -48,7 +46,6 @@ $app = new App([ new AuthCodeGrant( $authCodeRepository, $refreshTokenRepository, - $userRepository, new \DateInterval('PT10M') ), new \DateInterval('PT1H') @@ -66,7 +63,7 @@ $app = new App([ // Access token issuer $app->post('/access_token', function () { -})->add(new AuthenticationServerMiddleware($app->getContainer()->get(Server::class))); +})->add(new AuthorizationServerMiddleware($app->getContainer()->get(AuthorizationServer::class))); // Secured API $app->group('/api', function () { @@ -90,6 +87,6 @@ $app->group('/api', function () { return $response->withBody($body); }); -})->add(new ResourceServerMiddleware($app->getContainer()->get(Server::class))); +})->add(new ResourceServerMiddleware($app->getContainer()->get(AuthorizationServer::class))); $app->run(); diff --git a/examples/public/password.php b/examples/public/password.php index d8145050..f588def6 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -2,7 +2,7 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\PasswordGrant; -use League\OAuth2\Server\Server; +use League\OAuth2\Server\AuthorizationServer; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; @@ -19,7 +19,7 @@ $app = new App([ 'settings' => [ 'displayErrorDetails' => true, ], - Server::class => function () { + AuthorizationServer::class => function () { // Init our repositories $clientRepository = new ClientRepository(); $accessTokenRepository = new AccessTokenRepository(); @@ -31,7 +31,7 @@ $app = new App([ $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server - $server = new Server( + $server = new AuthorizationServer( $clientRepository, $accessTokenRepository, $scopeRepository, @@ -50,8 +50,8 @@ $app = new App([ ]); $app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { - /* @var \League\OAuth2\Server\Server $server */ - $server = $app->getContainer()->get(Server::class); + /* @var \League\OAuth2\Server\AuthorizationServer $server */ + $server = $app->getContainer()->get(AuthorizationServer::class); try { return $server->respondToAccessTokenRequest($request, $response); diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index 643431c8..85912e3d 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -2,7 +2,7 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\RefreshTokenGrant; -use League\OAuth2\Server\Server; +use League\OAuth2\Server\AuthorizationServer; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; @@ -18,7 +18,7 @@ $app = new App([ 'settings' => [ 'displayErrorDetails' => true, ], - Server::class => function () { + AuthorizationServer::class => function () { // Init our repositories $clientRepository = new ClientRepository(); $accessTokenRepository = new AccessTokenRepository(); @@ -29,7 +29,7 @@ $app = new App([ $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server - $server = new Server( + $server = new AuthorizationServer( $clientRepository, $accessTokenRepository, $scopeRepository, @@ -51,8 +51,8 @@ $app = new App([ ]); $app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { - /* @var \League\OAuth2\Server\Server $server */ - $server = $app->getContainer()->get(Server::class); + /* @var \League\OAuth2\Server\AuthorizationServer $server */ + $server = $app->getContainer()->get(AuthorizationServer::class); try { return $server->respondToAccessTokenRequest($request, $response); From 25c2e9b31bae0080bea0b3d3105a5cb7b15fc4f1 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Apr 2016 13:00:49 +0100 Subject: [PATCH 440/444] Code tidy client_credentials --- examples/public/client_credentials.php | 52 +++++++++++++++++--------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index c1ca45f0..e2547df3 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -1,8 +1,14 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Exception\OAuthServerException; -use League\OAuth2\Server\Grant\ClientCredentialsGrant; -use League\OAuth2\Server\Server; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; @@ -14,31 +20,33 @@ use Zend\Diactoros\Stream; include __DIR__ . '/../vendor/autoload.php'; $app = new App([ - 'settings' => [ + 'settings' => [ 'displayErrorDetails' => true, ], - Server::class => function () { + AuthorizationServer::class => function () { // Init our repositories - $clientRepository = new ClientRepository(); - $accessTokenRepository = new AccessTokenRepository(); - $scopeRepository = new ScopeRepository(); + $clientRepository = new ClientRepository(); // instance of ClientRepositoryInterface + $scopeRepository = new ScopeRepository(); // instance of ScopeRepositoryInterface + $accessTokenRepository = new AccessTokenRepository(); // instance of AccessTokenRepositoryInterface - $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + // Path to public and private keys + $privateKey = 'file://path/to/private.key'; + //$privateKey = new CryptKey('file://path/to/private.key', 'passphrase'); // if private key has a pass phrase + $publicKey = 'file://path/to/public.key'; // Setup the authorization server - $server = new Server( + $server = new AuthorizationServer( $clientRepository, $accessTokenRepository, $scopeRepository, - $privateKeyPath, - $publicKeyPath + $privateKey, + $publicKey ); - // Enable the client credentials grant on the server with a token TTL of 1 hour + // Enable the client credentials grant on the server $server->enableGrantType( - new ClientCredentialsGrant(), - new \DateInterval('PT1H') + new \League\OAuth2\Server\Grant\ClientCredentialsGrant(), + new \DateInterval('PT1H') // access tokens will expire after 1 hour ); return $server; @@ -46,18 +54,28 @@ $app = new App([ ]); $app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { - /* @var \League\OAuth2\Server\Server $server */ - $server = $app->getContainer()->get(Server::class); + + /* @var \League\OAuth2\Server\AuthorizationServer $server */ + $server = $app->getContainer()->get(AuthorizationServer::class); try { + + // Try to respond to the request return $server->respondToAccessTokenRequest($request, $response); + } catch (OAuthServerException $exception) { + + // All instances of OAuthServerException can be formatted into a HTTP response return $exception->generateHttpResponse($response); + } catch (\Exception $exception) { + + // Unknown exception $body = new Stream('php://temp', 'r+'); $body->write($exception->getMessage()); return $response->withStatus(500)->withBody($body); + } }); From f007e25070b14d807aba18b5434a43dc2fc7972d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Apr 2016 13:06:05 +0100 Subject: [PATCH 441/444] Added copyright docblocks --- examples/public/api.php | 7 +++++++ examples/public/auth_code.php | 7 +++++++ examples/public/implicit.php | 7 +++++++ examples/public/middleware_use.php | 7 +++++++ examples/public/password.php | 7 +++++++ examples/public/refresh_token.php | 7 +++++++ examples/src/Entities/AccessTokenEntity.php | 7 +++++++ examples/src/Entities/AuthCodeEntity.php | 7 +++++++ examples/src/Entities/ClientEntity.php | 7 +++++++ examples/src/Entities/RefreshTokenEntity.php | 7 +++++++ examples/src/Entities/ScopeEntity.php | 7 +++++++ examples/src/Entities/UserEntity.php | 7 +++++++ examples/src/Repositories/AccessTokenRepository.php | 7 +++++++ examples/src/Repositories/AuthCodeRepository.php | 7 +++++++ examples/src/Repositories/ClientRepository.php | 7 +++++++ examples/src/Repositories/RefreshTokenRepository.php | 7 +++++++ examples/src/Repositories/ScopeRepository.php | 7 +++++++ examples/src/Repositories/UserRepository.php | 7 +++++++ src/AuthorizationServer.php | 7 +++++++ .../AuthorizationValidatorInterface.php | 7 +++++++ src/AuthorizationValidators/BearerTokenValidator.php | 7 +++++++ src/Entities/AccessTokenEntityInterface.php | 7 +++++++ src/Entities/AuthCodeEntityInterface.php | 7 +++++++ src/Entities/ClientEntityInterface.php | 7 +++++++ src/Entities/RefreshTokenEntityInterface.php | 7 +++++++ src/Entities/ScopeEntityInterface.php | 7 +++++++ src/Entities/TokenInterface.php | 7 +++++++ src/Entities/Traits/AccessTokenTrait.php | 7 +++++++ src/Entities/Traits/AuthCodeTrait.php | 7 +++++++ src/Entities/Traits/ClientTrait.php | 7 +++++++ src/Entities/Traits/EntityTrait.php | 7 +++++++ src/Entities/Traits/RefreshTokenTrait.php | 7 +++++++ src/Entities/Traits/TokenEntityTrait.php | 7 +++++++ src/Entities/UserEntityInterface.php | 7 +++++++ src/Exception/OAuthServerException.php | 7 +++++++ src/Grant/AuthCodeGrant.php | 7 +++++++ src/Grant/ImplicitGrant.php | 7 +++++++ src/Middleware/AuthorizationServerMiddleware.php | 7 +++++++ src/Middleware/ResourceServerMiddleware.php | 7 +++++++ src/Repositories/AccessTokenRepositoryInterface.php | 3 +-- src/Repositories/AuthCodeRepositoryInterface.php | 2 -- src/Repositories/ClientRepositoryInterface.php | 2 -- src/Repositories/RefreshTokenRepositoryInterface.php | 2 -- src/Repositories/RepositoryInterface.php | 2 -- src/Repositories/ScopeRepositoryInterface.php | 3 +-- src/Repositories/UserRepositoryInterface.php | 7 +++++++ src/RequestEvent.php | 8 +++++++- src/RequestTypes/AuthorizationRequest.php | 7 +++++++ src/ResourceServer.php | 8 +++++++- 49 files changed, 303 insertions(+), 14 deletions(-) diff --git a/examples/public/api.php b/examples/public/api.php index 26474f0d..2df5d1cf 100644 --- a/examples/public/api.php +++ b/examples/public/api.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ use League\OAuth2\Server\ResourceServer; use OAuth2ServerExamples\Repositories\AccessTokenRepository; diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index 2a0b4c41..063bbdc0 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; diff --git a/examples/public/implicit.php b/examples/public/implicit.php index eee6abb3..cc365037 100644 --- a/examples/public/implicit.php +++ b/examples/public/implicit.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ImplicitGrant; diff --git a/examples/public/middleware_use.php b/examples/public/middleware_use.php index ae8b6f05..5ae6f6e3 100644 --- a/examples/public/middleware_use.php +++ b/examples/public/middleware_use.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\RefreshTokenGrant; diff --git a/examples/public/password.php b/examples/public/password.php index f588def6..98d1f395 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\PasswordGrant; diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index 85912e3d..0cf83734 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\RefreshTokenGrant; diff --git a/examples/src/Entities/AccessTokenEntity.php b/examples/src/Entities/AccessTokenEntity.php index 802bafe0..f55246b3 100644 --- a/examples/src/Entities/AccessTokenEntity.php +++ b/examples/src/Entities/AccessTokenEntity.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace OAuth2ServerExamples\Entities; diff --git a/examples/src/Entities/AuthCodeEntity.php b/examples/src/Entities/AuthCodeEntity.php index 65590532..acfbc3b6 100644 --- a/examples/src/Entities/AuthCodeEntity.php +++ b/examples/src/Entities/AuthCodeEntity.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace OAuth2ServerExamples\Entities; diff --git a/examples/src/Entities/ClientEntity.php b/examples/src/Entities/ClientEntity.php index 6a495cdb..9d682a45 100644 --- a/examples/src/Entities/ClientEntity.php +++ b/examples/src/Entities/ClientEntity.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace OAuth2ServerExamples\Entities; diff --git a/examples/src/Entities/RefreshTokenEntity.php b/examples/src/Entities/RefreshTokenEntity.php index ab4561eb..60109c02 100644 --- a/examples/src/Entities/RefreshTokenEntity.php +++ b/examples/src/Entities/RefreshTokenEntity.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace OAuth2ServerExamples\Entities; diff --git a/examples/src/Entities/ScopeEntity.php b/examples/src/Entities/ScopeEntity.php index ba6da73b..ec83cf51 100644 --- a/examples/src/Entities/ScopeEntity.php +++ b/examples/src/Entities/ScopeEntity.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace OAuth2ServerExamples\Entities; diff --git a/examples/src/Entities/UserEntity.php b/examples/src/Entities/UserEntity.php index d56bdaab..22c1b4e5 100644 --- a/examples/src/Entities/UserEntity.php +++ b/examples/src/Entities/UserEntity.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace OAuth2ServerExamples\Entities; diff --git a/examples/src/Repositories/AccessTokenRepository.php b/examples/src/Repositories/AccessTokenRepository.php index eb61a326..d7736c76 100644 --- a/examples/src/Repositories/AccessTokenRepository.php +++ b/examples/src/Repositories/AccessTokenRepository.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace OAuth2ServerExamples\Repositories; diff --git a/examples/src/Repositories/AuthCodeRepository.php b/examples/src/Repositories/AuthCodeRepository.php index 19a57a29..d3ca4825 100644 --- a/examples/src/Repositories/AuthCodeRepository.php +++ b/examples/src/Repositories/AuthCodeRepository.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace OAuth2ServerExamples\Repositories; diff --git a/examples/src/Repositories/ClientRepository.php b/examples/src/Repositories/ClientRepository.php index 7cd78ca1..f3f57fa1 100644 --- a/examples/src/Repositories/ClientRepository.php +++ b/examples/src/Repositories/ClientRepository.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace OAuth2ServerExamples\Repositories; diff --git a/examples/src/Repositories/RefreshTokenRepository.php b/examples/src/Repositories/RefreshTokenRepository.php index 4e00a741..39a0b8cd 100644 --- a/examples/src/Repositories/RefreshTokenRepository.php +++ b/examples/src/Repositories/RefreshTokenRepository.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace OAuth2ServerExamples\Repositories; diff --git a/examples/src/Repositories/ScopeRepository.php b/examples/src/Repositories/ScopeRepository.php index 228c629b..fbd64b3e 100644 --- a/examples/src/Repositories/ScopeRepository.php +++ b/examples/src/Repositories/ScopeRepository.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace OAuth2ServerExamples\Repositories; diff --git a/examples/src/Repositories/UserRepository.php b/examples/src/Repositories/UserRepository.php index 9726be25..86f99970 100644 --- a/examples/src/Repositories/UserRepository.php +++ b/examples/src/Repositories/UserRepository.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace OAuth2ServerExamples\Repositories; diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index 2c4d62e8..bd1c1490 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server; diff --git a/src/AuthorizationValidators/AuthorizationValidatorInterface.php b/src/AuthorizationValidators/AuthorizationValidatorInterface.php index 9fc24891..7e49f847 100644 --- a/src/AuthorizationValidators/AuthorizationValidatorInterface.php +++ b/src/AuthorizationValidators/AuthorizationValidatorInterface.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\AuthorizationValidators; diff --git a/src/AuthorizationValidators/BearerTokenValidator.php b/src/AuthorizationValidators/BearerTokenValidator.php index f7ad7267..88034750 100644 --- a/src/AuthorizationValidators/BearerTokenValidator.php +++ b/src/AuthorizationValidators/BearerTokenValidator.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\AuthorizationValidators; diff --git a/src/Entities/AccessTokenEntityInterface.php b/src/Entities/AccessTokenEntityInterface.php index 82ce640c..642cc99f 100644 --- a/src/Entities/AccessTokenEntityInterface.php +++ b/src/Entities/AccessTokenEntityInterface.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Entities; diff --git a/src/Entities/AuthCodeEntityInterface.php b/src/Entities/AuthCodeEntityInterface.php index 9f290fa8..e71aa2c8 100644 --- a/src/Entities/AuthCodeEntityInterface.php +++ b/src/Entities/AuthCodeEntityInterface.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Entities; diff --git a/src/Entities/ClientEntityInterface.php b/src/Entities/ClientEntityInterface.php index 413d1498..80cc70c8 100644 --- a/src/Entities/ClientEntityInterface.php +++ b/src/Entities/ClientEntityInterface.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Entities; diff --git a/src/Entities/RefreshTokenEntityInterface.php b/src/Entities/RefreshTokenEntityInterface.php index 7b9d3433..8b7d587d 100644 --- a/src/Entities/RefreshTokenEntityInterface.php +++ b/src/Entities/RefreshTokenEntityInterface.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Entities; diff --git a/src/Entities/ScopeEntityInterface.php b/src/Entities/ScopeEntityInterface.php index 1c8c6d17..34ef75f0 100644 --- a/src/Entities/ScopeEntityInterface.php +++ b/src/Entities/ScopeEntityInterface.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Entities; diff --git a/src/Entities/TokenInterface.php b/src/Entities/TokenInterface.php index b25d3912..7d7c6d33 100644 --- a/src/Entities/TokenInterface.php +++ b/src/Entities/TokenInterface.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Entities; diff --git a/src/Entities/Traits/AccessTokenTrait.php b/src/Entities/Traits/AccessTokenTrait.php index 17a8f7d4..f45b8b6a 100644 --- a/src/Entities/Traits/AccessTokenTrait.php +++ b/src/Entities/Traits/AccessTokenTrait.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Entities\Traits; diff --git a/src/Entities/Traits/AuthCodeTrait.php b/src/Entities/Traits/AuthCodeTrait.php index 61a1e65c..5bb9e306 100644 --- a/src/Entities/Traits/AuthCodeTrait.php +++ b/src/Entities/Traits/AuthCodeTrait.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Entities\Traits; diff --git a/src/Entities/Traits/ClientTrait.php b/src/Entities/Traits/ClientTrait.php index db01649d..8e44ce09 100644 --- a/src/Entities/Traits/ClientTrait.php +++ b/src/Entities/Traits/ClientTrait.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Entities\Traits; diff --git a/src/Entities/Traits/EntityTrait.php b/src/Entities/Traits/EntityTrait.php index 7142e5fe..20c86591 100644 --- a/src/Entities/Traits/EntityTrait.php +++ b/src/Entities/Traits/EntityTrait.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Entities\Traits; diff --git a/src/Entities/Traits/RefreshTokenTrait.php b/src/Entities/Traits/RefreshTokenTrait.php index 96d429fe..28d31a02 100644 --- a/src/Entities/Traits/RefreshTokenTrait.php +++ b/src/Entities/Traits/RefreshTokenTrait.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Entities\Traits; diff --git a/src/Entities/Traits/TokenEntityTrait.php b/src/Entities/Traits/TokenEntityTrait.php index 3c91542f..87fdd2f4 100644 --- a/src/Entities/Traits/TokenEntityTrait.php +++ b/src/Entities/Traits/TokenEntityTrait.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Entities\Traits; diff --git a/src/Entities/UserEntityInterface.php b/src/Entities/UserEntityInterface.php index 52cd277a..c71cb9c5 100644 --- a/src/Entities/UserEntityInterface.php +++ b/src/Entities/UserEntityInterface.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Entities; diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 2e4d8e18..2f698341 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Exception; diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 5540dd25..ba84f950 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Grant; diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 3c058599..e7ac0d15 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Grant; diff --git a/src/Middleware/AuthorizationServerMiddleware.php b/src/Middleware/AuthorizationServerMiddleware.php index d4f2e758..45a8348f 100644 --- a/src/Middleware/AuthorizationServerMiddleware.php +++ b/src/Middleware/AuthorizationServerMiddleware.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Middleware; diff --git a/src/Middleware/ResourceServerMiddleware.php b/src/Middleware/ResourceServerMiddleware.php index 7836a4ce..6d67cb68 100644 --- a/src/Middleware/ResourceServerMiddleware.php +++ b/src/Middleware/ResourceServerMiddleware.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Middleware; diff --git a/src/Repositories/AccessTokenRepositoryInterface.php b/src/Repositories/AccessTokenRepositoryInterface.php index a8655253..aab8eab8 100644 --- a/src/Repositories/AccessTokenRepositoryInterface.php +++ b/src/Repositories/AccessTokenRepositoryInterface.php @@ -1,13 +1,12 @@ * @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\AccessTokenEntityInterface; diff --git a/src/Repositories/AuthCodeRepositoryInterface.php b/src/Repositories/AuthCodeRepositoryInterface.php index 052fb849..cfe3b4d8 100644 --- a/src/Repositories/AuthCodeRepositoryInterface.php +++ b/src/Repositories/AuthCodeRepositoryInterface.php @@ -1,7 +1,5 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ diff --git a/src/Repositories/ClientRepositoryInterface.php b/src/Repositories/ClientRepositoryInterface.php index ce6c2b0e..a5d4c32d 100644 --- a/src/Repositories/ClientRepositoryInterface.php +++ b/src/Repositories/ClientRepositoryInterface.php @@ -1,7 +1,5 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ diff --git a/src/Repositories/RefreshTokenRepositoryInterface.php b/src/Repositories/RefreshTokenRepositoryInterface.php index d7e496c4..49d3ea4a 100644 --- a/src/Repositories/RefreshTokenRepositoryInterface.php +++ b/src/Repositories/RefreshTokenRepositoryInterface.php @@ -1,7 +1,5 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ diff --git a/src/Repositories/RepositoryInterface.php b/src/Repositories/RepositoryInterface.php index 5273057c..3e50d4de 100644 --- a/src/Repositories/RepositoryInterface.php +++ b/src/Repositories/RepositoryInterface.php @@ -1,7 +1,5 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ diff --git a/src/Repositories/ScopeRepositoryInterface.php b/src/Repositories/ScopeRepositoryInterface.php index a1363c2b..568f0e57 100644 --- a/src/Repositories/ScopeRepositoryInterface.php +++ b/src/Repositories/ScopeRepositoryInterface.php @@ -1,13 +1,12 @@ * @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\ClientEntityInterface; diff --git a/src/Repositories/UserRepositoryInterface.php b/src/Repositories/UserRepositoryInterface.php index f6745c1d..b2de24d6 100644 --- a/src/Repositories/UserRepositoryInterface.php +++ b/src/Repositories/UserRepositoryInterface.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\Repositories; diff --git a/src/RequestEvent.php b/src/RequestEvent.php index 3170beab..f6cf4d92 100644 --- a/src/RequestEvent.php +++ b/src/RequestEvent.php @@ -1,5 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server; use League\Event\Event; diff --git a/src/RequestTypes/AuthorizationRequest.php b/src/RequestTypes/AuthorizationRequest.php index 031c58b2..eaf78e39 100644 --- a/src/RequestTypes/AuthorizationRequest.php +++ b/src/RequestTypes/AuthorizationRequest.php @@ -1,4 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server\RequestTypes; diff --git a/src/ResourceServer.php b/src/ResourceServer.php index 1b12e8de..6fe8b1fc 100644 --- a/src/ResourceServer.php +++ b/src/ResourceServer.php @@ -1,5 +1,11 @@ + * @copyright Copyright (c) Alex Bilbie + * @license http://mit-license.org/ + * + * @link https://github.com/thephpleague/oauth2-server + */ namespace League\OAuth2\Server; use League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface; From 77737e7894c2dc5272bea98911c7753c88a9f90b Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Apr 2016 08:06:17 -0400 Subject: [PATCH 442/444] Applied fixes from StyleCI --- examples/public/auth_code.php | 2 +- examples/public/client_credentials.php | 3 --- examples/public/implicit.php | 2 +- examples/public/middleware_use.php | 2 +- examples/public/password.php | 2 +- examples/public/refresh_token.php | 2 +- src/AuthorizationServer.php | 12 ++++++------ src/Middleware/AuthorizationServerMiddleware.php | 2 +- tests/AuthorizationServerTest.php | 4 ++-- .../Middleware/AuthorizationServerMiddlewareTest.php | 2 +- tests/ResourceServerTest.php | 2 -- 11 files changed, 15 insertions(+), 20 deletions(-) diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index 063bbdc0..e014f55a 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -7,9 +7,9 @@ * @link https://github.com/thephpleague/oauth2-server */ +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; -use League\OAuth2\Server\AuthorizationServer; use OAuth2ServerExamples\Entities\UserEntity; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\AuthCodeRepository; diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index e2547df3..0825b61a 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -62,12 +62,10 @@ $app->post('/access_token', function (ServerRequestInterface $request, ResponseI // Try to respond to the request return $server->respondToAccessTokenRequest($request, $response); - } catch (OAuthServerException $exception) { // All instances of OAuthServerException can be formatted into a HTTP response return $exception->generateHttpResponse($response); - } catch (\Exception $exception) { // Unknown exception @@ -75,7 +73,6 @@ $app->post('/access_token', function (ServerRequestInterface $request, ResponseI $body->write($exception->getMessage()); return $response->withStatus(500)->withBody($body); - } }); diff --git a/examples/public/implicit.php b/examples/public/implicit.php index cc365037..2a82097f 100644 --- a/examples/public/implicit.php +++ b/examples/public/implicit.php @@ -7,9 +7,9 @@ * @link https://github.com/thephpleague/oauth2-server */ +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ImplicitGrant; -use League\OAuth2\Server\AuthorizationServer; use OAuth2ServerExamples\Entities\UserEntity; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; diff --git a/examples/public/middleware_use.php b/examples/public/middleware_use.php index 5ae6f6e3..2dfe1834 100644 --- a/examples/public/middleware_use.php +++ b/examples/public/middleware_use.php @@ -7,11 +7,11 @@ * @link https://github.com/thephpleague/oauth2-server */ +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Middleware\AuthorizationServerMiddleware; use League\OAuth2\Server\Middleware\ResourceServerMiddleware; -use League\OAuth2\Server\AuthorizationServer; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\AuthCodeRepository; use OAuth2ServerExamples\Repositories\ClientRepository; diff --git a/examples/public/password.php b/examples/public/password.php index 98d1f395..18eb6ddf 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -7,9 +7,9 @@ * @link https://github.com/thephpleague/oauth2-server */ +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\PasswordGrant; -use League\OAuth2\Server\AuthorizationServer; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index 0cf83734..0649c117 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -7,9 +7,9 @@ * @link https://github.com/thephpleague/oauth2-server */ +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\RefreshTokenGrant; -use League\OAuth2\Server\AuthorizationServer; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index bd1c1490..b0ba7598 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -70,12 +70,12 @@ class AuthorizationServer implements EmitterAwareInterface /** * New server instance. * - * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository - * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository - * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository - * @param \League\OAuth2\Server\CryptKey|string $privateKey - * @param \League\OAuth2\Server\CryptKey|string $publicKey - * @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType + * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository + * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository + * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository + * @param \League\OAuth2\Server\CryptKey|string $privateKey + * @param \League\OAuth2\Server\CryptKey|string $publicKey + * @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType */ public function __construct( ClientRepositoryInterface $clientRepository, diff --git a/src/Middleware/AuthorizationServerMiddleware.php b/src/Middleware/AuthorizationServerMiddleware.php index 45a8348f..d33cbd31 100644 --- a/src/Middleware/AuthorizationServerMiddleware.php +++ b/src/Middleware/AuthorizationServerMiddleware.php @@ -9,8 +9,8 @@ namespace League\OAuth2\Server\Middleware; -use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\AuthorizationServer; +use League\OAuth2\Server\Exception\OAuthServerException; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; diff --git a/tests/AuthorizationServerTest.php b/tests/AuthorizationServerTest.php index 86eb24df..2303b713 100644 --- a/tests/AuthorizationServerTest.php +++ b/tests/AuthorizationServerTest.php @@ -2,6 +2,7 @@ namespace LeagueTests; +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; @@ -13,7 +14,6 @@ use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; -use League\OAuth2\Server\AuthorizationServer; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\AuthCodeEntity; use LeagueTests\Stubs\ClientEntity; @@ -94,7 +94,7 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase $this->assertTrue($method->invoke($server) instanceof BearerTokenResponse); } - + public function testCompleteAuthorizationRequest() { $clientRepository = $this->getMock(ClientRepositoryInterface::class); diff --git a/tests/Middleware/AuthorizationServerMiddlewareTest.php b/tests/Middleware/AuthorizationServerMiddlewareTest.php index f04b7572..bb068179 100644 --- a/tests/Middleware/AuthorizationServerMiddlewareTest.php +++ b/tests/Middleware/AuthorizationServerMiddlewareTest.php @@ -2,13 +2,13 @@ namespace LeagueTests\Middleware; +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Middleware\AuthorizationServerMiddleware; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; -use League\OAuth2\Server\AuthorizationServer; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; diff --git a/tests/ResourceServerTest.php b/tests/ResourceServerTest.php index 12365c47..c1dafe27 100644 --- a/tests/ResourceServerTest.php +++ b/tests/ResourceServerTest.php @@ -3,7 +3,6 @@ namespace LeagueTests; - use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\ResourceServer; @@ -24,5 +23,4 @@ class ResourceServerTest extends \PHPUnit_Framework_TestCase $this->assertEquals('Missing "Authorization" header', $e->getHint()); } } - } From f765f134c919ef26277898ac4e654184027151fb Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Apr 2016 08:07:03 -0400 Subject: [PATCH 443/444] Applied fixes from StyleCI --- examples/public/auth_code.php | 2 +- examples/public/client_credentials.php | 3 --- examples/public/implicit.php | 2 +- examples/public/middleware_use.php | 2 +- examples/public/password.php | 2 +- examples/public/refresh_token.php | 2 +- src/AuthorizationServer.php | 12 ++++++------ src/Middleware/AuthorizationServerMiddleware.php | 2 +- tests/AuthorizationServerTest.php | 4 ++-- .../Middleware/AuthorizationServerMiddlewareTest.php | 2 +- tests/ResourceServerTest.php | 2 -- 11 files changed, 15 insertions(+), 20 deletions(-) diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index 063bbdc0..e014f55a 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -7,9 +7,9 @@ * @link https://github.com/thephpleague/oauth2-server */ +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; -use League\OAuth2\Server\AuthorizationServer; use OAuth2ServerExamples\Entities\UserEntity; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\AuthCodeRepository; diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index e2547df3..0825b61a 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -62,12 +62,10 @@ $app->post('/access_token', function (ServerRequestInterface $request, ResponseI // Try to respond to the request return $server->respondToAccessTokenRequest($request, $response); - } catch (OAuthServerException $exception) { // All instances of OAuthServerException can be formatted into a HTTP response return $exception->generateHttpResponse($response); - } catch (\Exception $exception) { // Unknown exception @@ -75,7 +73,6 @@ $app->post('/access_token', function (ServerRequestInterface $request, ResponseI $body->write($exception->getMessage()); return $response->withStatus(500)->withBody($body); - } }); diff --git a/examples/public/implicit.php b/examples/public/implicit.php index cc365037..2a82097f 100644 --- a/examples/public/implicit.php +++ b/examples/public/implicit.php @@ -7,9 +7,9 @@ * @link https://github.com/thephpleague/oauth2-server */ +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ImplicitGrant; -use League\OAuth2\Server\AuthorizationServer; use OAuth2ServerExamples\Entities\UserEntity; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; diff --git a/examples/public/middleware_use.php b/examples/public/middleware_use.php index 5ae6f6e3..2dfe1834 100644 --- a/examples/public/middleware_use.php +++ b/examples/public/middleware_use.php @@ -7,11 +7,11 @@ * @link https://github.com/thephpleague/oauth2-server */ +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Middleware\AuthorizationServerMiddleware; use League\OAuth2\Server\Middleware\ResourceServerMiddleware; -use League\OAuth2\Server\AuthorizationServer; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\AuthCodeRepository; use OAuth2ServerExamples\Repositories\ClientRepository; diff --git a/examples/public/password.php b/examples/public/password.php index 98d1f395..18eb6ddf 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -7,9 +7,9 @@ * @link https://github.com/thephpleague/oauth2-server */ +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\PasswordGrant; -use League\OAuth2\Server\AuthorizationServer; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index 0cf83734..0649c117 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -7,9 +7,9 @@ * @link https://github.com/thephpleague/oauth2-server */ +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\RefreshTokenGrant; -use League\OAuth2\Server\AuthorizationServer; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index bd1c1490..b0ba7598 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -70,12 +70,12 @@ class AuthorizationServer implements EmitterAwareInterface /** * New server instance. * - * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository - * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository - * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository - * @param \League\OAuth2\Server\CryptKey|string $privateKey - * @param \League\OAuth2\Server\CryptKey|string $publicKey - * @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType + * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository + * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository + * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository + * @param \League\OAuth2\Server\CryptKey|string $privateKey + * @param \League\OAuth2\Server\CryptKey|string $publicKey + * @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType */ public function __construct( ClientRepositoryInterface $clientRepository, diff --git a/src/Middleware/AuthorizationServerMiddleware.php b/src/Middleware/AuthorizationServerMiddleware.php index 45a8348f..d33cbd31 100644 --- a/src/Middleware/AuthorizationServerMiddleware.php +++ b/src/Middleware/AuthorizationServerMiddleware.php @@ -9,8 +9,8 @@ namespace League\OAuth2\Server\Middleware; -use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\AuthorizationServer; +use League\OAuth2\Server\Exception\OAuthServerException; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; diff --git a/tests/AuthorizationServerTest.php b/tests/AuthorizationServerTest.php index 86eb24df..2303b713 100644 --- a/tests/AuthorizationServerTest.php +++ b/tests/AuthorizationServerTest.php @@ -2,6 +2,7 @@ namespace LeagueTests; +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; @@ -13,7 +14,6 @@ use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; -use League\OAuth2\Server\AuthorizationServer; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\AuthCodeEntity; use LeagueTests\Stubs\ClientEntity; @@ -94,7 +94,7 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase $this->assertTrue($method->invoke($server) instanceof BearerTokenResponse); } - + public function testCompleteAuthorizationRequest() { $clientRepository = $this->getMock(ClientRepositoryInterface::class); diff --git a/tests/Middleware/AuthorizationServerMiddlewareTest.php b/tests/Middleware/AuthorizationServerMiddlewareTest.php index f04b7572..bb068179 100644 --- a/tests/Middleware/AuthorizationServerMiddlewareTest.php +++ b/tests/Middleware/AuthorizationServerMiddlewareTest.php @@ -2,13 +2,13 @@ namespace LeagueTests\Middleware; +use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Middleware\AuthorizationServerMiddleware; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; -use League\OAuth2\Server\AuthorizationServer; use LeagueTests\Stubs\AccessTokenEntity; use LeagueTests\Stubs\ClientEntity; use LeagueTests\Stubs\StubResponseType; diff --git a/tests/ResourceServerTest.php b/tests/ResourceServerTest.php index 12365c47..c1dafe27 100644 --- a/tests/ResourceServerTest.php +++ b/tests/ResourceServerTest.php @@ -3,7 +3,6 @@ namespace LeagueTests; - use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\ResourceServer; @@ -24,5 +23,4 @@ class ResourceServerTest extends \PHPUnit_Framework_TestCase $this->assertEquals('Missing "Authorization" header', $e->getHint()); } } - } From 4942585f4f75ff7f3ca838ec4126e35e260bb839 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 17 Apr 2016 13:18:12 +0100 Subject: [PATCH 444/444] Updated changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2386cf4e..4d2cba7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ Version 5 is a complete code rewrite. Changes since RC2: +* Renamed Server class to AuthorizationServer +* Added ResourceServer class * Run unit tests again PHP 5.5.9 as it's the minimum supported version * Enable PHPUnit 5.0 support * Improved examples and documentation