diff options
| author | Brent Shaffer <bshafs@gmail.com> | 2012-12-20 20:09:08 +0400 |
|---|---|---|
| committer | Brent Shaffer <bshafs@gmail.com> | 2012-12-20 20:09:08 +0400 |
| commit | 8cb2360d9d76db082f6db9fbaccf05d1e2dcbb5b (patch) | |
| tree | 5fbe976d7e3a50539a81fc96533579aaefec3677 | |
| parent | 5e4d75e3b155c449ebe1d4a734568780d3e57d69 (diff) | |
| parent | 81ceb467b9b6745574a9ece4b3b2bbebf1e7c9b9 (diff) | |
| download | oauth2-server-php-0.2.tar.xz | |
Merge branch 'develop'v0.2
35 files changed, 370 insertions, 144 deletions
@@ -36,7 +36,7 @@ Before getting started, take a look at the [Oauth2 Demo Application](http://bren The quickest way to get started is to use the following code, plugging in your database information to the constructor of `OAuth2_Storage_Pdo`: - $storage = new OAuth2_Storage_Pdo($dsn, $username, $password); + $storage = new OAuth2_Storage_Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password)); $server = new OAuth2_Server($storage); $server->addGrantType(new OAuth2_GrantType_UserCredentials($storage)); // or some other grant type. This is the simplest $server->handleGrantRequest(OAuth2_Request::createFromGlobals())->send(); @@ -45,7 +45,7 @@ Let's break this down line by line. The first line is how the OAuth2 data is sto There are several built in storage types, for your convenience. To use PDO Storage, instantiate the `OAuth2_Storage_Pdo` class and provide the database connection arguments: - $storage = new OAuth2_Storage_Pdo($dsn, $username, $password); + $storage = new OAuth2_Storage_Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password)); $server = new OAuth2_Server($storage); The next step is to add a grant type. This example uses the "User Credentials" grant type, which grants a token based on diff --git a/src/OAuth2/Controller/AccessController.php b/src/OAuth2/Controller/AccessController.php index 8c2449a..883c64a 100644 --- a/src/OAuth2/Controller/AccessController.php +++ b/src/OAuth2/Controller/AccessController.php @@ -25,7 +25,7 @@ class OAuth2_Controller_AccessController implements OAuth2_Controller_AccessCont $this->util = $util; } - public function verifyAccessRequest(OAuth2_Request $request) + public function verifyAccessRequest(OAuth2_RequestInterface $request) { $token = $this->tokenType->getAccessTokenParameter($request); $this->response = $this->tokenType->getResponse(); diff --git a/src/OAuth2/Controller/AccessControllerInterface.php b/src/OAuth2/Controller/AccessControllerInterface.php index ff63b13..a7b77c8 100644 --- a/src/OAuth2/Controller/AccessControllerInterface.php +++ b/src/OAuth2/Controller/AccessControllerInterface.php @@ -2,7 +2,7 @@ interface OAuth2_Controller_AccessControllerInterface extends OAuth2_Response_ProviderInterface { - public function verifyAccessRequest(OAuth2_Request $request); + public function verifyAccessRequest(OAuth2_RequestInterface $request); public function getAccessTokenData($token_param, $scope = null); }
\ No newline at end of file diff --git a/src/OAuth2/Controller/AuthorizeController.php b/src/OAuth2/Controller/AuthorizeController.php index c7603ff..09ff56c 100644 --- a/src/OAuth2/Controller/AuthorizeController.php +++ b/src/OAuth2/Controller/AuthorizeController.php @@ -27,7 +27,7 @@ class OAuth2_Controller_AuthorizeController implements OAuth2_Controller_Authori $this->util = $util; } - public function handleAuthorizeRequest(OAuth2_Request $request, $is_authorized, $user_id = null) + public function handleAuthorizeRequest(OAuth2_RequestInterface $request, $is_authorized, $user_id = null) { if (!is_bool($is_authorized)) { throw new InvalidArgumentException('Argument "is_authorized" must be a boolean. This method must know if the user has granted access to the client.'); @@ -56,7 +56,7 @@ class OAuth2_Controller_AuthorizeController implements OAuth2_Controller_Authori return new OAuth2_Response_Redirect($uri); } - public function validateAuthorizeRequest(OAuth2_Request $request) + public function validateAuthorizeRequest(OAuth2_RequestInterface $request) { // Make sure a valid client id was supplied (we can not redirect because we were unable to verify the URI) if (!$client_id = $request->query("client_id")) { @@ -139,7 +139,7 @@ class OAuth2_Controller_AuthorizeController implements OAuth2_Controller_Authori } // Return retrieved client details together with input - return ($request->query + $clientData + array('state' => null)); + return ((array)$request->getAllQueryParameters() + $clientData + array('state' => null)); } public function getResponse() diff --git a/src/OAuth2/Controller/AuthorizeControllerInterface.php b/src/OAuth2/Controller/AuthorizeControllerInterface.php index 463ebda..4110297 100644 --- a/src/OAuth2/Controller/AuthorizeControllerInterface.php +++ b/src/OAuth2/Controller/AuthorizeControllerInterface.php @@ -14,7 +14,7 @@ interface OAuth2_Controller_AuthorizeControllerInterface extends OAuth2_Response const RESPONSE_TYPE_AUTHORIZATION_CODE = 'code'; const RESPONSE_TYPE_ACCESS_TOKEN = 'token'; - public function handleAuthorizeRequest(OAuth2_Request $request, $is_authorized, $user_id = null); + public function handleAuthorizeRequest(OAuth2_RequestInterface $request, $is_authorized, $user_id = null); - public function validateAuthorizeRequest(OAuth2_Request $request); + public function validateAuthorizeRequest(OAuth2_RequestInterface $request); }
\ No newline at end of file diff --git a/src/OAuth2/Controller/GrantController.php b/src/OAuth2/Controller/GrantController.php index d22ddd8..0e46802 100644 --- a/src/OAuth2/Controller/GrantController.php +++ b/src/OAuth2/Controller/GrantController.php @@ -15,15 +15,16 @@ class OAuth2_Controller_GrantController implements OAuth2_Controller_GrantContro foreach ($grantTypes as $grantType) { $this->addGrantType($grantType); } + if (is_null($util)) { $util = new OAuth2_Util(); } $this->util = $util; } - public function handleGrantRequest(OAuth2_Request $request, $grantType = null) + public function handleGrantRequest(OAuth2_RequestInterface $request) { - if ($token = $this->grantAccessToken($request, $grantType)) { + if ($token = $this->grantAccessToken($request)) { $this->response = new OAuth2_Response($token); } return $this->response; @@ -32,9 +33,9 @@ class OAuth2_Controller_GrantController implements OAuth2_Controller_GrantContro /** * Grant or deny a requested access token. * This would be called from the "/token" endpoint as defined in the spec. - * Obviously, you can call your endpoint whatever you want. + * You can call your endpoint whatever you want. * - * @param $request - OAuth2_Request + * @param $request - OAuth2_RequestInterface * Request object to grant access token * @param $grantType - mixed * OAuth2_GrantTypeInterface instance or one of the grant types configured in the constructor @@ -48,31 +49,27 @@ class OAuth2_Controller_GrantController implements OAuth2_Controller_GrantContro * * @ingroup oauth2_section_4 */ - public function grantAccessToken(OAuth2_Request $request, $grantType = null) + public function grantAccessToken(OAuth2_RequestInterface $request) { - if (!$grantType instanceof OAuth2_GrantTypeInterface) { - if (is_null($grantType)) { - if (!$grantType = $request->parameter('grant_type')) { - $this->response = new OAuth2_Response_Error(400, 'invalid_request', 'The grant type was not specified in the request'); - return null; - } - } else if (!is_string($grantType)) { - throw new InvalidArgumentException('parameter $grantType must be an instance of OAuth2_GrantTypeInterface, a string representing a configured grant type, or null to pull grant type from request'); - } - if (!isset($this->grantTypes[$grantType])) { - /* TODO: If this is an OAuth2 supported grant type that we have chosen not to implement, throw a 501 Not Implemented instead */ - $this->response = new OAuth2_Response_Error(400, 'unsupported_grant_type', sprintf('Grant type "%s" not supported', $grantType)); - return null; - } - $grantType = $this->grantTypes[$grantType]; + // Determine grant type from request + if (!($grantType = $request->query('grant_type')) && !($grantType = $request->request('grant_type'))) { + $this->response = new OAuth2_Response_Error(400, 'invalid_request', 'The grant type was not specified in the request'); + return null; } + if (!isset($this->grantTypes[$grantType])) { + /* TODO: If this is an OAuth2 supported grant type that we have chosen not to implement, throw a 501 Not Implemented instead */ + $this->response = new OAuth2_Response_Error(400, 'unsupported_grant_type', sprintf('Grant type "%s" not supported', $grantType)); + return null; + } + $grantType = $this->grantTypes[$grantType]; + // get and validate client authorization from the request if (!$clientData = $this->getClientCredentials($request)) { return null; } if (!isset($clientData['client_id']) || !isset($clientData['client_secret'])) { - throw new LogicException('the clientData array must have "client_id" and "client_secret" values set. Use getClientCredentials()'); + throw new LogicException('the clientData array must have "client_id" and "client_secret" values set.'); } if ($this->clientStorage->checkClientCredentials($clientData['client_id'], $clientData['client_secret']) === false) { @@ -80,13 +77,12 @@ class OAuth2_Controller_GrantController implements OAuth2_Controller_GrantContro return null; } - if (!$this->clientStorage->checkRestrictedGrantType($clientData['client_id'], $grantType)) { + if (!$this->clientStorage->checkRestrictedGrantType($clientData['client_id'], $grantType->getQuerystringIdentifier())) { $this->response = new OAuth2_Response_Error(400, 'unauthorized_client', 'The grant type is unauthorized for this client_id'); return null; } - /* TODO: Find a better way to handle grantTypes and their responses */ - + // validate the request for the token if (!$grantType->validateRequest($request)) { if ($grantType instanceof OAuth2_Response_ProviderInterface && $response = $grantType->getResponse()) { $this->response = $response; @@ -122,18 +118,14 @@ class OAuth2_Controller_GrantController implements OAuth2_Controller_GrantContro } // Check scope, if provided - if (isset($request->query['scope']) && (!is_array($tokenData) || !isset($tokenData["scope"]) || !$this->util->checkScope($request->query['scope'], $tokenData["scope"]))) { + if (null != $request->query('scope') && (!is_array($tokenData) || !isset($tokenData["scope"]) || !$this->util->checkScope($request->query('scope'), $tokenData["scope"]))) { $this->response = new OAuth2_Response_Error(400, 'invalid_scope', 'An unsupported scope was requested.'); return null; } - $user_id = isset($tokenData['user_id']) ? $tokenData['user_id'] : null; - $token = $this->accessToken->createAccessToken($clientData['client_id'], $user_id, $tokenData['scope']); - - // TODO: Remove this - $grantType->finishGrantRequest($token); + $tokenData['user_id'] = isset($tokenData['user_id']) ? $tokenData['user_id'] : null; - return $token; + return $grantType->createAccessToken($this->accessToken, $clientData, $tokenData); } /** @@ -156,7 +148,7 @@ class OAuth2_Controller_GrantController implements OAuth2_Controller_GrantContro * * @ingroup oauth2_section_2 */ - public function getClientCredentials(OAuth2_Request $request) + public function getClientCredentials(OAuth2_RequestInterface $request) { if (!is_null($request->headers('PHP_AUTH_USER')) && !is_null($request->headers('PHP_AUTH_PW'))) { return array('client_id' => $request->headers('PHP_AUTH_USER'), 'client_secret' => $request->headers('PHP_AUTH_PW')); @@ -186,7 +178,7 @@ class OAuth2_Controller_GrantController implements OAuth2_Controller_GrantContro public function addGrantType(OAuth2_GrantTypeInterface $grantType, $identifier = null) { if (is_null($identifier) || is_numeric($identifier)) { - $identifier = $grantType->getIdentifier(); + $identifier = $grantType->getQuerystringIdentifier(); } $this->grantTypes[$identifier] = $grantType; diff --git a/src/OAuth2/Controller/GrantControllerInterface.php b/src/OAuth2/Controller/GrantControllerInterface.php index 77fd66f..2bdcfd0 100644 --- a/src/OAuth2/Controller/GrantControllerInterface.php +++ b/src/OAuth2/Controller/GrantControllerInterface.php @@ -2,9 +2,16 @@ interface OAuth2_Controller_GrantControllerInterface extends OAuth2_Response_ProviderInterface { - public function handleGrantRequest(OAuth2_Request $request, $grantType = null); + /** + * handleGrantRequest + * + * @param $request + * OAuth2_RequestInterface - The current http request + * + **/ + public function handleGrantRequest(OAuth2_RequestInterface $request); - public function grantAccessToken(OAuth2_Request $request, $grantType = null); + public function grantAccessToken(OAuth2_RequestInterface $request); - public function getClientCredentials(OAuth2_Request $request); + public function getClientCredentials(OAuth2_RequestInterface $request); }
\ No newline at end of file diff --git a/src/OAuth2/GrantType/AuthorizationCode.php b/src/OAuth2/GrantType/AuthorizationCode.php index 5ae1bd1..2a40b2f 100644 --- a/src/OAuth2/GrantType/AuthorizationCode.php +++ b/src/OAuth2/GrantType/AuthorizationCode.php @@ -13,14 +13,14 @@ class OAuth2_GrantType_AuthorizationCode implements OAuth2_GrantTypeInterface, O $this->storage = $storage; } - public function getIdentifier() + public function getQuerystringIdentifier() { return 'authorization_code'; } public function validateRequest($request) { - if (!isset($request->query['code']) || !$request->query['code']) { + if (!$request->query('code')) { $this->response = new OAuth2_Response_Error(400, 'invalid_request', 'Missing parameter: "code" is required'); return false; } @@ -30,7 +30,7 @@ class OAuth2_GrantType_AuthorizationCode implements OAuth2_GrantTypeInterface, O public function getTokenDataFromRequest($request) { - if (!$tokenData = $this->storage->getAuthorizationCode($request->query['code'])) { + if (!$tokenData = $this->storage->getAuthorizationCode($request->query('code'))) { $this->response = new OAuth2_Response_Error(400, 'invalid_grant', "Authorization code doesn't exist or is invalid for the client"); return null; } @@ -49,7 +49,7 @@ class OAuth2_GrantType_AuthorizationCode implements OAuth2_GrantTypeInterface, O return $tokenData; } - public function validateTokenData(array $tokenData, array $clientData) + public function validateTokenData($tokenData, array $clientData) { // Check the code exists if ($tokenData === null || $clientData['client_id'] != $tokenData['client_id']) { @@ -66,8 +66,10 @@ class OAuth2_GrantType_AuthorizationCode implements OAuth2_GrantTypeInterface, O return true; } - public function finishGrantRequest($token) - {} + public function createAccessToken(OAuth2_ResponseType_AccessTokenInterface $accessToken, array $clientData, array $tokenData) + { + return $accessToken->createAccessToken($clientData['client_id'], $tokenData['user_id'], $tokenData['scope']); + } public function getResponse() { diff --git a/src/OAuth2/GrantType/ClientCredentials.php b/src/OAuth2/GrantType/ClientCredentials.php index 4d47c6b..2dae255 100644 --- a/src/OAuth2/GrantType/ClientCredentials.php +++ b/src/OAuth2/GrantType/ClientCredentials.php @@ -2,7 +2,7 @@ class OAuth2_GrantType_ClientCredentials implements OAuth2_GrantTypeInterface { - public function getIdentifier() + public function getQuerystringIdentifier() { return 'client_credentials'; } @@ -22,12 +22,19 @@ class OAuth2_GrantType_ClientCredentials implements OAuth2_GrantTypeInterface ); } - public function validateTokenData(array $tokenData, array $clientData) + public function validateTokenData($tokenData, array $clientData) { // Scope is validated in the client class return true; } - public function finishGrantRequest($token) - {} + public function createAccessToken(OAuth2_ResponseType_AccessTokenInterface $accessToken, array $clientData, array $tokenData) + { + /* + * Client Credentials Grant does NOT include a refresh token + * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-4.4.3 + */ + $includeRefreshToken = false; + return $accessToken->createAccessToken($clientData['client_id'], $tokenData['user_id'], $tokenData['scope'], $includeRefreshToken); + } }
\ No newline at end of file diff --git a/src/OAuth2/GrantType/RefreshToken.php b/src/OAuth2/GrantType/RefreshToken.php index 36057fd..5bc9732 100644 --- a/src/OAuth2/GrantType/RefreshToken.php +++ b/src/OAuth2/GrantType/RefreshToken.php @@ -7,21 +7,25 @@ class OAuth2_GrantType_RefreshToken implements OAuth2_GrantTypeInterface, OAuth2 { private $storage; private $response; + private $config; private $oldRefreshToken; - public function __construct(OAuth2_Storage_RefreshTokenInterface $storage) + public function __construct(OAuth2_Storage_RefreshTokenInterface $storage, $config = array()) { + $this->config = array_merge(array( + 'always_issue_new_refresh_token' => false + ), $config); $this->storage = $storage; } - public function getIdentifier() + public function getQuerystringIdentifier() { return 'refresh_token'; } public function validateRequest($request) { - if (!isset($request->query["refresh_token"]) || !$request->query['refresh_token']) { + if (!$request->query("refresh_token")) { $this->response = new OAuth2_Response_Error(400, 'invalid_request', 'Missing parameter: "refresh_token" is required'); return false; } @@ -31,7 +35,7 @@ class OAuth2_GrantType_RefreshToken implements OAuth2_GrantTypeInterface, OAuth2 public function getTokenDataFromRequest($request) { - if (!$stored = $this->storage->getRefreshToken($request->query["refresh_token"])) { + if (!$stored = $this->storage->getRefreshToken($request->query("refresh_token"))) { $this->response = new OAuth2_Response_Error(400, 'invalid_grant', 'Invalid refresh token'); return false; } @@ -39,7 +43,7 @@ class OAuth2_GrantType_RefreshToken implements OAuth2_GrantTypeInterface, OAuth2 return $stored; } - public function validateTokenData(array $tokenData, array $clientData) + public function validateTokenData($tokenData, array $clientData) { if ($tokenData === null || $clientData['client_id'] != $tokenData["client_id"]) { $this->response = new OAuth2_Response_Error(400, 'invalid_grant', 'Invalid refresh token'); @@ -57,9 +61,21 @@ class OAuth2_GrantType_RefreshToken implements OAuth2_GrantTypeInterface, OAuth2 return true; } - public function finishGrantRequest($token) + public function createAccessToken(OAuth2_ResponseType_AccessTokenInterface $accessToken, array $clientData, array $tokenData) { - $this->storage->unsetRefreshToken($this->oldRefreshToken); + /* + * It is optional to force a new refresh token when a refresh token is used. + * However, if a new refresh token is issued, the old one MUST be expired + * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-6 + */ + $issueNewRefreshToken = $this->config['always_issue_new_refresh_token']; + $token = $accessToken->createAccessToken($clientData['client_id'], $tokenData['user_id'], $tokenData['scope'], $issueNewRefreshToken); + + if ($issueNewRefreshToken) { + $this->storage->unsetRefreshToken($this->oldRefreshToken); + } + + return $token; } public function getResponse() diff --git a/src/OAuth2/GrantType/UserCredentials.php b/src/OAuth2/GrantType/UserCredentials.php index 5a5dabe..51d05aa 100644 --- a/src/OAuth2/GrantType/UserCredentials.php +++ b/src/OAuth2/GrantType/UserCredentials.php @@ -13,14 +13,14 @@ class OAuth2_GrantType_UserCredentials implements OAuth2_GrantTypeInterface, OAu $this->storage = $storage; } - public function getIdentifier() + public function getQuerystringIdentifier() { return 'password'; } public function validateRequest($request) { - if (!isset($request->query["username"]) || !isset($request->query["password"]) || !$request->query["username"] || !$request->query["password"]) { + if (!$request->query("password") || !$request->query("username")) { $this->response = new OAuth2_Response_Error(400, 'invalid_request', 'Missing parameters: "username" and "password" required'); return false; } @@ -30,22 +30,32 @@ class OAuth2_GrantType_UserCredentials implements OAuth2_GrantTypeInterface, OAu public function getTokenDataFromRequest($request) { - if (!$tokenData = $this->storage->checkUserCredentials($request->query["username"], $request->query["password"])) { + if (!$this->storage->checkUserCredentials($request->query("username"), $request->query("password"))) { $this->response = new OAuth2_Response_Error(400, 'invalid_grant', 'Invalid username and password combination'); return false; } + $tokenData = $this->storage->getUserDetails($request->query("username")); + + // tokenData can be an empty array + if (false === $tokenData || is_null($tokenData)) { + $this->response = new OAuth2_Response_Error(400, 'invalid_grant', 'Unable to retrieve user information'); + return false; + } + return $tokenData; } - public function validateTokenData(array $tokenData, array $clientData) + public function validateTokenData($tokenData, array $clientData) { // Scope is validated in the client class return true; } - public function finishGrantRequest($token) - {} + public function createAccessToken(OAuth2_ResponseType_AccessTokenInterface $accessToken, array $clientData, array $tokenData) + { + return $accessToken->createAccessToken($clientData['client_id'], $tokenData['user_id'], $tokenData['scope']); + } public function getResponse() { diff --git a/src/OAuth2/GrantTypeInterface.php b/src/OAuth2/GrantTypeInterface.php index 25146de..0573f9d 100644 --- a/src/OAuth2/GrantTypeInterface.php +++ b/src/OAuth2/GrantTypeInterface.php @@ -2,9 +2,9 @@ interface OAuth2_GrantTypeInterface { - public function getIdentifier(); + public function getQuerystringIdentifier(); public function validateRequest($request); public function getTokenDataFromRequest($request); - public function validateTokenData(array $tokenData, array $clientData); - public function finishGrantRequest($token); + public function validateTokenData($tokenData, array $clientData); + public function createAccessToken(OAuth2_ResponseType_AccessTokenInterface $accessToken, array $clientData, array $tokenData); }
\ No newline at end of file diff --git a/src/OAuth2/Request.php b/src/OAuth2/Request.php index 3f745c9..3ddc3ff 100644 --- a/src/OAuth2/Request.php +++ b/src/OAuth2/Request.php @@ -14,6 +14,7 @@ class OAuth2_Request implements OAuth2_RequestInterface public $files; public $cookies; public $headers; + public $content; /** * Constructor. @@ -79,9 +80,9 @@ class OAuth2_Request implements OAuth2_RequestInterface return isset($this->headers[$name]) ? $this->headers[$name] : $default; } - public function parameter($name, $default = null) + public function getAllQueryParameters() { - return $this->query($name) ? $this->query($name) : $this->request($name, $default); + return $this->query; } /** diff --git a/src/OAuth2/RequestInterface.php b/src/OAuth2/RequestInterface.php index c23eb55..0195605 100644 --- a/src/OAuth2/RequestInterface.php +++ b/src/OAuth2/RequestInterface.php @@ -2,4 +2,13 @@ interface OAuth2_RequestInterface { + public function query($name, $default = null); + + public function request($name, $default = null); + + public function server($name, $default = null); + + public function headers($name, $default = null); + + public function getAllQueryParameters(); }
\ No newline at end of file diff --git a/src/OAuth2/Response/AuthenticationError.php b/src/OAuth2/Response/AuthenticationError.php index 7c2566a..c3c5a62 100644 --- a/src/OAuth2/Response/AuthenticationError.php +++ b/src/OAuth2/Response/AuthenticationError.php @@ -8,7 +8,7 @@ class OAuth2_Response_AuthenticationError extends OAuth2_Response_Error public function __construct($statusCode, $error, $errorDescription, $tokenType, $realm, $scope = null) { parent::__construct($statusCode, $error, $errorDescription); - $authHeader = sprintf('WWW-Authenticate: %s realm=%s', $tokenType, $realm); + $authHeader = sprintf('%s realm=%s', $tokenType, $realm); if ($scope) { $authHeader = sprintf('%s, scope=%s', $authHeader, $scope); } diff --git a/src/OAuth2/ResponseType/AccessToken.php b/src/OAuth2/ResponseType/AccessToken.php index 43efc95..37b5e54 100644 --- a/src/OAuth2/ResponseType/AccessToken.php +++ b/src/OAuth2/ResponseType/AccessToken.php @@ -17,7 +17,7 @@ class OAuth2_ResponseType_AccessToken implements OAuth2_ResponseType_AccessToken 'token_type' => 'bearer', 'access_lifetime' => 3600, 'refresh_token_lifetime' => 1209600, - )); + ), $config); } // same params as above @@ -28,8 +28,13 @@ class OAuth2_ResponseType_AccessToken implements OAuth2_ResponseType_AccessToken $params += array('scope' => null, 'state' => null); - // should this call from a grant type? - $result["fragment"] = $this->createAccessToken($params['client_id'], $user_id, $params['scope']); + /* + * a refresh token MUST NOT be included in the fragment + * + * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-4.2.2 + */ + $includeRefreshToken = false; + $result["fragment"] = $this->createAccessToken($params['client_id'], $user_id, $params['scope'], $includeRefreshToken); if (isset($params['state'])) { $result["fragment"]["state"] = $params['state']; @@ -48,11 +53,13 @@ class OAuth2_ResponseType_AccessToken implements OAuth2_ResponseType_AccessToken * Client identifier related to the access token. * @param $scope * (optional) Scopes to be stored in space-separated string. + * @param bool $excludeRefreshToken + * If true, the refresh_token will be omitted from the response * * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-20#section-5 * @ingroup oauth2_section_5 */ - public function createAccessToken($client_id, $user_id, $scope = null) + public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true) { $token = array( "access_token" => $this->generateAccessToken(), @@ -63,9 +70,13 @@ class OAuth2_ResponseType_AccessToken implements OAuth2_ResponseType_AccessToken $this->tokenStorage->setAccessToken($token["access_token"], $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope); - // Issue a refresh token also, if we support them - /* TODO: How do we handle this? */ - if ($this->refreshStorage) { + /* + * Issue a refresh token also, if we support them + * + * Refresh Tokens are considered supported if an instance of OAuth2_Storage_RefreshTokenInterface + * is supplied in the constructor + */ + if ($includeRefreshToken && $this->refreshStorage) { $token["refresh_token"] = $this->generateRefreshToken(); $this->refreshStorage->setRefreshToken($token['refresh_token'], $client_id, $user_id, time() + $this->config['refresh_token_lifetime'], $scope); } diff --git a/src/OAuth2/ResponseType/AccessTokenInterface.php b/src/OAuth2/ResponseType/AccessTokenInterface.php index 5247f6f..457c3b8 100644 --- a/src/OAuth2/ResponseType/AccessTokenInterface.php +++ b/src/OAuth2/ResponseType/AccessTokenInterface.php @@ -2,5 +2,5 @@ interface OAuth2_ResponseType_AccessTokenInterface extends OAuth2_ResponseTypeInterface { - public function createAccessToken($client_id, $user_id, $scope = null); + public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true); }
\ No newline at end of file diff --git a/src/OAuth2/Server.php b/src/OAuth2/Server.php index bfad2ab..c67057d 100644 --- a/src/OAuth2/Server.php +++ b/src/OAuth2/Server.php @@ -2,7 +2,10 @@ /** * Service class for OAuth -* Inspired by oauth2-php (https://github.com/quizlet/oauth2-php) +* This class serves only to wrap the other Controller classes +* @see OAuth2_Controller_AccessController +* @see OAuth2_Controller_AuthorizeController +* @see OAuth2_Controller_GrantController */ class OAuth2_Server implements OAuth2_Controller_AccessControllerInterface, OAuth2_Controller_AuthorizeControllerInterface, OAuth2_Controller_GrantControllerInterface @@ -27,14 +30,18 @@ class OAuth2_Server implements OAuth2_Controller_AccessControllerInterface, * array - array of Objects to implement storage * OAuth2_Storage object implementing all required storage types (ClientCredentialsInterface and AccessTokenInterface as a minimum) * + * @param array $config + * specify a different token lifetime, token header name, etc + * * @param array $grantTypes * An array of OAuth2_GrantTypeInterface to use for granting access tokens * - * @param array $config - * specify a different token lifetime, token header name, etc + * @param array $responseTypes + * Response types to use. array keys should be "code" and and "token" for + * Access Token and Authorization Code response types * - * @param array $response - * Send in an instance of OAuth2_ResponseInterface to use a different response object + * @param OAuth2_ResponseType_AccessTokenInterface $accessTokenResponseType + * Response type to use for access token * * @return * TRUE if everything in required scope is contained in available scope, @@ -44,7 +51,7 @@ class OAuth2_Server implements OAuth2_Controller_AccessControllerInterface, * * @ingroup oauth2_section_7 */ - public function __construct($storage = array(), array $config = array(), array $grantTypes = array(), array $responseTypes = array(), OAuth2_ResponseType_AccessToken $accessTokenResponseType = null) + public function __construct($storage = array(), array $config = array(), array $grantTypes = array(), array $responseTypes = array(), OAuth2_ResponseType_AccessTokenInterface $accessTokenResponseType = null) { $validStorage = array( 'access_token' => 'OAuth2_Storage_AccessTokenInterface', @@ -147,7 +154,7 @@ class OAuth2_Server implements OAuth2_Controller_AccessControllerInterface, if (isset($this->storages['refresh_token'])) { $refreshStorage = $this->storages['refresh_token']; } - $config = array_intersect_key($this->config, array_flip(explode(' ', 'token_type access_lifetime'))); + $config = array_intersect_key($this->config, array_flip(explode(' ', 'token_type access_lifetime refresh_token_lifetime'))); $this->accessTokenResponseType = new OAuth2_ResponseType_AccessToken($this->storages['access_token'], $refreshStorage, $config); } } @@ -167,7 +174,7 @@ class OAuth2_Server implements OAuth2_Controller_AccessControllerInterface, if (isset($this->storages['refresh_token'])) { $refreshStorage = $this->storages['refresh_token']; } - $config = array_intersect_key($this->config, array_flip(explode(' ', 'token_type access_lifetime'))); + $config = array_intersect_key($this->config, array_flip(explode(' ', 'token_type access_lifetime refresh_token_lifetime'))); $responseTypes['token'] = new OAuth2_ResponseType_AccessToken($this->storages['access_token'], $refreshStorage, $config); } @@ -217,8 +224,9 @@ class OAuth2_Server implements OAuth2_Controller_AccessControllerInterface, * * @param $request - OAuth2_Request * Request object to grant access token - * @param $grantType - mixed - * OAuth2_GrantTypeInterface instance or one of the grant types configured in the constructor + * + * @return + * OAuth_Response * * @throws InvalidArgumentException * @throws LogicException @@ -229,21 +237,21 @@ class OAuth2_Server implements OAuth2_Controller_AccessControllerInterface, * * @ingroup oauth2_section_4 */ - public function handleGrantRequest(OAuth2_Request $request, $grantType = null) + public function handleGrantRequest(OAuth2_RequestInterface $request) { - $value = $this->getGrantController()->handleGrantRequest($request, $grantType); + $value = $this->getGrantController()->handleGrantRequest($request); $this->response = $this->grantController->getResponse(); return $value; } - public function grantAccessToken(OAuth2_Request $request, $grantType = null) + public function grantAccessToken(OAuth2_RequestInterface $request) { - $value = $this->getGrantController()->grantAccessToken($request, $grantType); + $value = $this->getGrantController()->grantAccessToken($request); $this->response = $this->grantController->getResponse(); return $value; } - public function getClientCredentials(OAuth2_Request $request) + public function getClientCredentials(OAuth2_RequestInterface $request) { $value = $this->getGrantController()->getClientCredentials($request); $this->response = $this->grantController->getResponse(); @@ -269,8 +277,10 @@ class OAuth2_Server implements OAuth2_Controller_AccessControllerInterface, * list of space-delimited strings. * - state: (optional) An opaque value used by the client to maintain * state between the request and callback. + * * @param $is_authorized * TRUE or FALSE depending on whether the user authorized the access. + * * @param $user_id * Identifier of user who authorized the client * @@ -278,7 +288,7 @@ class OAuth2_Server implements OAuth2_Controller_AccessControllerInterface, * * @ingroup oauth2_section_4 */ - public function handleAuthorizeRequest(OAuth2_Request $request, $is_authorized, $user_id = null) + public function handleAuthorizeRequest(OAuth2_RequestInterface $request, $is_authorized, $user_id = null) { $value = $this->getAuthorizeController()->handleAuthorizeRequest($request, $is_authorized, $user_id); $this->response = $this->authorizeController->getResponse(); @@ -304,14 +314,14 @@ class OAuth2_Server implements OAuth2_Controller_AccessControllerInterface, * * @ingroup oauth2_section_3 */ - public function validateAuthorizeRequest(OAuth2_Request $request) + public function validateAuthorizeRequest(OAuth2_RequestInterface $request) { $value = $this->getAuthorizeController()->validateAuthorizeRequest($request); $this->response = $this->authorizeController->getResponse(); return $value; } - public function verifyAccessRequest(OAuth2_Request $request) + public function verifyAccessRequest(OAuth2_RequestInterface $request) { $value = $this->getAccessController()->verifyAccessRequest($request); $this->response = $this->accessController->getResponse(); diff --git a/src/OAuth2/Storage/ClientCredentialsInterface.php b/src/OAuth2/Storage/ClientCredentialsInterface.php index 0110c9f..374d628 100644 --- a/src/OAuth2/Storage/ClientCredentialsInterface.php +++ b/src/OAuth2/Storage/ClientCredentialsInterface.php @@ -35,8 +35,7 @@ interface OAuth2_Storage_ClientCredentialsInterface extends OAuth2_Storage_Clien * @param $client_id * Client identifier to be check with. * @param $grant_type - * Grant type to be check with, would be one of the values contained in - * OAuth2::GRANT_TYPE_REGEXP. + * Grant type to be check with * * @return * TRUE if the grant type is supported by this client identifier, and diff --git a/src/OAuth2/Storage/Memory.php b/src/OAuth2/Storage/Memory.php index c986076..ec5d97a 100644 --- a/src/OAuth2/Storage/Memory.php +++ b/src/OAuth2/Storage/Memory.php @@ -58,7 +58,12 @@ class OAuth2_Storage_Memory implements OAuth2_Storage_AuthorizationCodeInterface public function setUserCredentials($user_credentials) { - $this->userCredentials = $user_credentials; + return isset($this->userCredentials[$username]) ? $this->userCredentials[$username] : null; + } + + public function getUserDetails($username) + { + return $this->getUser($username); } /* ClientCredentialsInterface */ diff --git a/src/OAuth2/Storage/Pdo.php b/src/OAuth2/Storage/Pdo.php index e806bed..de659e2 100644 --- a/src/OAuth2/Storage/Pdo.php +++ b/src/OAuth2/Storage/Pdo.php @@ -5,7 +5,7 @@ */ class OAuth2_Storage_Pdo implements OAuth2_Storage_AuthorizationCodeInterface, OAuth2_Storage_AccessTokenInterface, OAuth2_Storage_ClientCredentialsInterface, - OAuth2_Storage_UserCredentialsInterface + OAuth2_Storage_UserCredentialsInterface, OAuth2_Storage_RefreshTokenInterface { private $db; private $config; @@ -32,17 +32,18 @@ class OAuth2_Storage_Pdo implements OAuth2_Storage_AuthorizationCodeInterface, $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->config = array_merge(array( - 'client_table_name' => 'oauth_clients', - 'token_table_name' => 'oauth_access_tokens', - 'code_table_name' => 'oauth_authorization_codes', - 'user_table_name' => 'oauth_users', + 'client_table' => 'oauth_clients', + 'access_token_table' => 'oauth_access_tokens', + 'refresh_token_table' => 'oauth_refresh_tokens', + 'code_table' => 'oauth_authorization_codes', + 'user_table' => 'oauth_users', ), $config); } /* ClientCredentialsInterface */ public function checkClientCredentials($client_id, $client_secret = null) { - $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = "%s"', $this->config['client_table_name'], $client_id)); + $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = "%s"', $this->config['client_table'], $client_id)); $stmt->execute(); $result = $stmt->fetch(); @@ -52,7 +53,7 @@ class OAuth2_Storage_Pdo implements OAuth2_Storage_AuthorizationCodeInterface, public function getClientDetails($client_id) { - $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = "%s"', $this->config['client_table_name'], $client_id)); + $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = "%s"', $this->config['client_table'], $client_id)); $stmt->execute(); return $stmt->fetch(); @@ -72,7 +73,7 @@ class OAuth2_Storage_Pdo implements OAuth2_Storage_AuthorizationCodeInterface, /* AccessTokenInterface */ public function getAccessToken($access_token) { - $stmt = $this->db->prepare(sprintf('SELECT * from %s where access_token = "%s"', $this->config['token_table_name'], $access_token)); + $stmt = $this->db->prepare(sprintf('SELECT * from %s where access_token = "%s"', $this->config['access_token_table'], $access_token)); $token = $stmt->execute(); if ($token = $stmt->fetch()) { @@ -90,9 +91,9 @@ class OAuth2_Storage_Pdo implements OAuth2_Storage_AuthorizationCodeInterface, // if it exists, update it. if ($this->getAccessToken($access_token)) { - $stmt = $this->db->prepare(sprintf('UPDATE %s SET client_id=:client_id, expires=:expires, user_id=:user_id, scope=:scope where access_token=:access_token', $this->config['token_table_name'])); + $stmt = $this->db->prepare(sprintf('UPDATE %s SET client_id=:client_id, expires=:expires, user_id=:user_id, scope=:scope where access_token=:access_token', $this->config['access_token_table'])); } else { - $stmt = $this->db->prepare(sprintf('INSERT INTO %s (access_token, client_id, expires, user_id, scope) VALUES (:access_token, :client_id, :expires, :user_id, :scope)', $this->config['token_table_name'])); + $stmt = $this->db->prepare(sprintf('INSERT INTO %s (access_token, client_id, expires, user_id, scope) VALUES (:access_token, :client_id, :expires, :user_id, :scope)', $this->config['access_token_table'])); } return $stmt->execute(compact('access_token', 'client_id', 'user_id', 'expires', 'scope')); } @@ -100,7 +101,7 @@ class OAuth2_Storage_Pdo implements OAuth2_Storage_AuthorizationCodeInterface, /* AuthorizationCodeInterface */ public function getAuthorizationCode($code) { - $stmt = $this->db->prepare(sprintf('SELECT * from %s where authorization_code = "%s"', $this->config['code_table_name'], $code)); + $stmt = $this->db->prepare(sprintf('SELECT * from %s where authorization_code = "%s"', $this->config['code_table'], $code)); $stmt->execute(); if ($code = $stmt->fetch()) { @@ -118,9 +119,9 @@ class OAuth2_Storage_Pdo implements OAuth2_Storage_AuthorizationCodeInterface, // if it exists, update it. if ($this->getAuthorizationCode($code)) { - $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope where authorization_code=:code', $this->config['code_table_name'])); + $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope where authorization_code=:code', $this->config['code_table'])); } else { - $stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope)', $this->config['code_table_name'])); + $stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope)', $this->config['code_table'])); } return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope')); } @@ -134,6 +135,42 @@ class OAuth2_Storage_Pdo implements OAuth2_Storage_AuthorizationCodeInterface, return false; } + public function getUserDetails($username) + { + return $this->getUser($username); + } + + /* RefreshTokenInterface */ + public function getRefreshToken($refresh_token) + { + $stmt = $this->db->prepare(sprintf('SELECT * FROM %s WHERE refresh_token = "%s"', $this->config['refresh_token_table'], $refresh_token)); + + $token = $stmt->execute(); + if ($token = $stmt->fetch()) { + // convert expires to epoch time + $token['expires'] = strtotime($token['expires']); + } + + return $token; + } + + public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = NULL) + { + // convert expires to datestring + $expires = date('Y-m-d H:i:s', $expires); + + $stmt = $this->db->prepare(sprintf('INSERT INTO %s (refresh_token, client_id, user_id, expires, scope) VALUES (:refresh_token, :client_id, :user_id, :expires, :scope)', $this->config['refresh_token_table'])); + + return $stmt->execute(compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope')); + } + + public function unsetRefreshToken($refresh_token) + { + $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE refresh_token = "%s"', $this->config['refresh_token_table'], $refresh_token)); + + return $stmt->execute(); + } + // plaintext passwords are bad! Override this for your application protected function checkPassword($user, $password) { @@ -142,7 +179,7 @@ class OAuth2_Storage_Pdo implements OAuth2_Storage_AuthorizationCodeInterface, public function getUser($username) { - $stmt = $this->db->prepare($sql = sprintf('SELECT * from %s where username=:username', $this->config['user_table_name'])); + $stmt = $this->db->prepare($sql = sprintf('SELECT * from %s where username=:username', $this->config['user_table'])); $stmt->execute(array('username' => $username)); return $stmt->fetch(); } @@ -151,10 +188,10 @@ class OAuth2_Storage_Pdo implements OAuth2_Storage_AuthorizationCodeInterface, { // if it exists, update it. if ($this->getUser($username)) { - $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET username=:username, password=:password, first_name=:firstName, last_name=:lastName where username=:username', $this->config['user_table_name'])); + $stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET username=:username, password=:password, first_name=:firstName, last_name=:lastName where username=:username', $this->config['user_table'])); } else { - $stmt = $this->db->prepare(sprintf('INSERT INTO %s (username, password, first_name, last_name) VALUES (:username, :password, :firstName, :lastName)', $this->config['user_table_name'])); + $stmt = $this->db->prepare(sprintf('INSERT INTO %s (username, password, first_name, last_name) VALUES (:username, :password, :firstName, :lastName)', $this->config['user_table'])); } return $stmt->execute(compact('username', 'password', 'firstName', 'lastName')); } -}
\ No newline at end of file +}
diff --git a/src/OAuth2/Storage/UserCredentialsInterface.php b/src/OAuth2/Storage/UserCredentialsInterface.php index 8ecf866..9fff562 100644 --- a/src/OAuth2/Storage/UserCredentialsInterface.php +++ b/src/OAuth2/Storage/UserCredentialsInterface.php @@ -3,13 +3,13 @@ /** * Storage engines that support the "Resource Owner Password Credentials" * grant type should implement this interface - * + * * @author Dave Rochwerger <catch.dave@gmail.com> * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-20#section-4.3 */ interface OAuth2_Storage_UserCredentialsInterface { - + /** * Grant access tokens for basic user credentials. * @@ -42,4 +42,12 @@ interface OAuth2_Storage_UserCredentialsInterface * @ingroup oauth2_section_4 */ public function checkUserCredentials($username, $password); + + /** + * @return + * ARRAY the associated "scope" or "user_id" values if applicable, or an empty array + * if this does not apply + * + */ + public function getUserDetails($username); }
\ No newline at end of file diff --git a/src/OAuth2/TokenType/Bearer.php b/src/OAuth2/TokenType/Bearer.php index bcccd08..08492a4 100644 --- a/src/OAuth2/TokenType/Bearer.php +++ b/src/OAuth2/TokenType/Bearer.php @@ -42,14 +42,10 @@ class OAuth2_TokenType_Bearer implements OAuth2_TokenTypeInterface, OAuth2_Respo * Old Android version bug (at least with version 2.2) * @see http://code.google.com/p/android/issues/detail?id=6684 * - * We don't want to test this functionality as it relies on superglobals and headers: - * @codeCoverageIgnoreStart */ - public function getAccessTokenParameter(OAuth2_Request $request) + public function getAccessTokenParameter(OAuth2_RequestInterface $request) { - if (isset($request->server['AUTHORIZATION'])) { - $headers = $request->server['AUTHORIZATION']; - } + $headers = $request->server('AUTHORIZATION'); // Check that exactly one method was used $methodsUsed = !empty($headers) + !is_null($request->query($this->config['token_param_name'])) + !is_null($request->request($this->config['token_param_name'])); diff --git a/src/OAuth2/TokenType/MAC.php b/src/OAuth2/TokenType/MAC.php index c809a3b..6d47932 100644 --- a/src/OAuth2/TokenType/MAC.php +++ b/src/OAuth2/TokenType/MAC.php @@ -10,7 +10,7 @@ class OAuth2_TokenType_MAC implements OAuth2_TokenTypeInterface return 'mac'; } - public function getAccessTokenParameter(OAuth2_Request $request) + public function getAccessTokenParameter(OAuth2_RequestInterface $request) { throw new LogicException("Not supported"); diff --git a/src/OAuth2/TokenTypeInterface.php b/src/OAuth2/TokenTypeInterface.php index ab8ac9f..27ca292 100644 --- a/src/OAuth2/TokenTypeInterface.php +++ b/src/OAuth2/TokenTypeInterface.php @@ -3,5 +3,5 @@ interface OAuth2_TokenTypeInterface { public function getTokenType(); - public function getAccessTokenParameter(OAuth2_Request $request); + public function getAccessTokenParameter(OAuth2_RequestInterface $request); }
\ No newline at end of file diff --git a/test/OAuth2/GrantType/AuthorizationCodeTest.php b/test/OAuth2/GrantType/AuthorizationCodeTest.php index 012a7ae..b4af1d5 100644 --- a/test/OAuth2/GrantType/AuthorizationCodeTest.php +++ b/test/OAuth2/GrantType/AuthorizationCodeTest.php @@ -9,8 +9,7 @@ class OAuth2_GrantType_AuthorizationCodeTest extends PHPUnit_Framework_TestCase $request->query['grant_type'] = 'authorization_code'; // valid grant type $request->query['client_id'] = 'Test Client ID'; // valid client id $request->query['client_secret'] = 'TestSecret'; // valid client secret - $server->grantAccessToken($request); - $response = $server->getResponse(); + $response = $server->handleGrantRequest($request); $this->assertEquals($response->getStatusCode(), 400); $this->assertEquals($response->getParameter('error'), 'invalid_request'); @@ -25,8 +24,7 @@ class OAuth2_GrantType_AuthorizationCodeTest extends PHPUnit_Framework_TestCase $request->query['client_id'] = 'Test Client ID'; // valid client id $request->query['client_secret'] = 'TestSecret'; // valid client secret $request->query['code'] = 'InvalidCode'; // invalid authorization code - $ret = $server->grantAccessToken($request); - $response = $server->getResponse(); + $response = $server->handleGrantRequest($request); $this->assertEquals($response->getStatusCode(), 400); $this->assertEquals($response->getParameter('error'), 'invalid_grant'); diff --git a/test/OAuth2/GrantType/ClientCredentialsTest.php b/test/OAuth2/GrantType/ClientCredentialsTest.php index a6591cd..f6934f8 100644 --- a/test/OAuth2/GrantType/ClientCredentialsTest.php +++ b/test/OAuth2/GrantType/ClientCredentialsTest.php @@ -9,8 +9,7 @@ class OAuth2_GrantType_ClientCredentialsTest extends PHPUnit_Framework_TestCase $request->query['grant_type'] = 'client_credentials'; // valid grant type $request->query['client_id'] = 'Test Client ID'; // valid client id $request->query['client_secret'] = 'FakeSecret'; // valid client secret - $server->grantAccessToken($request); - $response = $server->getResponse(); + $response = $server->handleGrantRequest($request); $this->assertEquals($response->getStatusCode(), 400); $this->assertEquals($response->getParameter('error'), 'invalid_client'); diff --git a/test/OAuth2/GrantType/RefreshTokenTest.php b/test/OAuth2/GrantType/RefreshTokenTest.php index b5d1539..7c23ca7 100644 --- a/test/OAuth2/GrantType/RefreshTokenTest.php +++ b/test/OAuth2/GrantType/RefreshTokenTest.php @@ -7,6 +7,8 @@ class OAuth2_GrantType_RefreshTokenTest extends PHPUnit_Framework_TestCase public function testNoRefreshToken() { $server = $this->getTestServer(); + $server->addGrantType(new OAuth2_GrantType_RefreshToken($this->storage)); + $request = OAuth2_Request::createFromGlobals(); $request->query['grant_type'] = 'refresh_token'; // valid grant type $request->query['client_id'] = 'Test Client ID'; // valid client id @@ -22,6 +24,8 @@ class OAuth2_GrantType_RefreshTokenTest extends PHPUnit_Framework_TestCase public function testInvalidRefreshToken() { $server = $this->getTestServer(); + $server->addGrantType(new OAuth2_GrantType_RefreshToken($this->storage)); + $request = OAuth2_Request::createFromGlobals(); $request->query['grant_type'] = 'refresh_token'; // valid grant type $request->query['client_id'] = 'Test Client ID'; // valid client id @@ -35,28 +39,49 @@ class OAuth2_GrantType_RefreshTokenTest extends PHPUnit_Framework_TestCase $this->assertEquals($response->getParameter('error_description'), 'Invalid refresh token'); } - public function testValidRefreshToken() + public function testValidRefreshTokenWithNewRefreshTokenInResponse() { $server = $this->getTestServer(); + $server->addGrantType(new OAuth2_GrantType_RefreshToken($this->storage, array('always_issue_new_refresh_token' => true))); + $request = OAuth2_Request::createFromGlobals(); $request->query['grant_type'] = 'refresh_token'; // valid grant type $request->query['client_id'] = 'Test Client ID'; // valid client id $request->query['client_secret'] = 'TestSecret'; // valid client secret $request->query['refresh_token'] = 'test-refreshtoken'; // valid client secret $token = $server->grantAccessToken($request); - $this->assertTrue(isset($token['refresh_token'])); + $this->assertTrue(isset($token['refresh_token']), 'refresh token should always refresh'); $refresh_token = $this->storage->getRefreshToken($token['refresh_token']); $this->assertNotNull($refresh_token); $this->assertEquals($refresh_token['refresh_token'], $token['refresh_token']); $this->assertEquals($refresh_token['client_id'], $request->query('client_id')); + $this->assertTrue($token['refresh_token'] != 'test-refreshtoken', 'the refresh token returned is not the one used'); + $used_token = $this->storage->getRefreshToken('test-refreshtoken'); + $this->assertNull($used_token, 'the refresh token used is no longer valid'); + } + + public function testValidRefreshTokenWithNoRefreshTokenInResponse() + { + $server = $this->getTestServer(); + $server->addGrantType(new OAuth2_GrantType_RefreshToken($this->storage, array('always_issue_new_refresh_token' => false))); + + $request = OAuth2_Request::createFromGlobals(); + $request->query['grant_type'] = 'refresh_token'; // valid grant type + $request->query['client_id'] = 'Test Client ID'; // valid client id + $request->query['client_secret'] = 'TestSecret'; // valid client secret + $request->query['refresh_token'] = 'test-refreshtoken'; // valid client secret + $token = $server->grantAccessToken($request); + $this->assertFalse(isset($token['refresh_token']), 'refresh token should not be returned'); + + $used_token = $this->storage->getRefreshToken('test-refreshtoken'); + $this->assertNotNull($used_token, 'the refresh token used is still valid'); } private function getTestServer() { $this->storage = new OAuth2_Storage_Memory(json_decode(file_get_contents(dirname(__FILE__).'/../../config/storage.json'), true)); $server = new OAuth2_Server($this->storage); - $server->addGrantType(new OAuth2_GrantType_RefreshToken($this->storage)); return $server; } diff --git a/test/OAuth2/RequestTest.php b/test/OAuth2/RequestTest.php new file mode 100644 index 0000000..a362c2f --- /dev/null +++ b/test/OAuth2/RequestTest.php @@ -0,0 +1,43 @@ +<?php + +class OAuth2_RequestTest extends PHPUnit_Framework_TestCase +{ + public function testRequestOverride() + { + $request = new OAuth2_Request_TestRequest(); + $server = $this->getTestServer(); + + // Smoke test for override request class + // $response = $server->handleGrantRequest($request); + // $this->assertInstanceOf('OAuth2_Response', $response); + // $response = $server->handleAuthorizeRequest($request, true); + // $this->assertInstanceOf('OAuth2_Response', $response); + // $response = $server->verifyAccessRequest($request); + // $this->assertTrue(is_bool($response)); + + /*** make some valid requests ***/ + + // Valid Grant Request + $request->setQuery(array( + 'grant_type' => 'authorization_code', + 'client_id' => 'Test Client ID', + 'client_secret' => 'TestSecret', + 'code' => 'testcode', + )); + $response = $server->handleGrantRequest($request); + $this->assertEquals($response->getStatusCode(), 200); + $this->assertNull($response->getParameter('error')); + $this->assertNotNUll($response->getParameter('access_token')); + } + + private function getTestServer($config = array()) + { + $storage = OAuth2_Storage_Bootstrap::getInstance()->getMemoryStorage(); + $server = new OAuth2_Server($storage, $config); + + // Add the two types supported for authorization grant + $server->addGrantType(new OAuth2_GrantType_AuthorizationCode($storage)); + + return $server; + } +}
\ No newline at end of file diff --git a/test/OAuth2/Server/Access/BasicValidationTest.php b/test/OAuth2/Server/Access/BasicValidationTest.php index 12f73ed..9060c27 100644 --- a/test/OAuth2/Server/Access/BasicValidationTest.php +++ b/test/OAuth2/Server/Access/BasicValidationTest.php @@ -153,7 +153,7 @@ class OAuth2_Server_Access_BasicValidationTest extends PHPUnit_Framework_TestCas private function getTestServer($config = array()) { - $storage = new OAuth2_Storage_Memory(json_decode(file_get_contents(dirname(__FILE__).'/../../../config/storage.json'), true)); + $storage = OAuth2_Storage_Bootstrap::getInstance()->getMemoryStorage(); $server = new OAuth2_Server($storage, $config); // Add the two types supported for authorization grant diff --git a/test/OAuth2/Server/Authorize/BasicValidationTest.php b/test/OAuth2/Server/Authorize/BasicValidationTest.php index c14484d..acaeb92 100644 --- a/test/OAuth2/Server/Authorize/BasicValidationTest.php +++ b/test/OAuth2/Server/Authorize/BasicValidationTest.php @@ -106,7 +106,7 @@ class OAuth2_Server_Authorize_BasicValidationTest extends PHPUnit_Framework_Test private function getTestServer($config = array()) { - $storage = new OAuth2_Storage_Memory(json_decode(file_get_contents(dirname(__FILE__).'/../../../config/storage.json'), true)); + $storage = OAuth2_Storage_Bootstrap::getInstance()->getMemoryStorage(); $server = new OAuth2_Server($storage, $config); // Add the two types supported for authorization grant diff --git a/test/OAuth2/Server/Grant/BasicValidationTest.php b/test/OAuth2/Server/Grant/BasicValidationTest.php index 986a346..c834f04 100644 --- a/test/OAuth2/Server/Grant/BasicValidationTest.php +++ b/test/OAuth2/Server/Grant/BasicValidationTest.php @@ -98,7 +98,7 @@ class OAuth2_Server_Grant_BasicValidationTest extends PHPUnit_Framework_TestCase private function getTestServer() { - $storage = new OAuth2_Storage_Memory(json_decode(file_get_contents(dirname(__FILE__).'/../../../config/storage.json'), true)); + $storage = OAuth2_Storage_Bootstrap::getInstance()->getMemoryStorage(); $server = new OAuth2_Server($storage); $server->addGrantType(new OAuth2_GrantType_AuthorizationCode($storage)); // or some other grant type. This is the simplest diff --git a/test/bootstrap.php b/test/bootstrap.php index e8a13ba..02bcc90 100644 --- a/test/bootstrap.php +++ b/test/bootstrap.php @@ -4,4 +4,4 @@ require_once(dirname(__FILE__).'/../src/OAuth2/Autoloader.php'); OAuth2_Autoloader::register(); // register test classes -OAuth2_Autoloader::register(dirname(__FILE__));
\ No newline at end of file +OAuth2_Autoloader::register(dirname(__FILE__).'/lib');
\ No newline at end of file diff --git a/test/lib/OAuth2/Request/TestRequest.php b/test/lib/OAuth2/Request/TestRequest.php new file mode 100644 index 0000000..623d139 --- /dev/null +++ b/test/lib/OAuth2/Request/TestRequest.php @@ -0,0 +1,46 @@ +<?php + +/** +* +*/ +class OAuth2_Request_TestRequest implements OAuth2_RequestInterface +{ + private $query, $post, $server; + + public function __construct() + { + $this->query = $_GET; + $this->post = $_POST; + $this->server = $_SERVER; + } + + public function query($name, $default = null) + { + return isset($this->query[$name]) ? $this->query[$name] : $default; + } + + public function request($name, $default = null) + { + return isset($this->post[$name]) ? $this->post[$name] : $default; + } + + public function server($name, $default = null) + { + return isset($this->server[$name]) ? $this->server[$name] : $default; + } + + public function headers($name, $default = null) + { + return $default; + } + + public function getAllQueryParameters() + { + return $this->query; + } + + public function setQuery(array $query) + { + $this->query = $query; + } +}
\ No newline at end of file diff --git a/test/OAuth2/Storage/Bootstrap.php b/test/lib/OAuth2/Storage/Bootstrap.php index dcb6ad7..4a214b3 100644 --- a/test/OAuth2/Storage/Bootstrap.php +++ b/test/lib/OAuth2/Storage/Bootstrap.php @@ -27,6 +27,11 @@ class OAuth2_Storage_Bootstrap return $this->sqlite; } + public function getMemoryStorage() + { + return new OAuth2_Storage_Memory(json_decode(file_get_contents(dirname(__FILE__).'/../../../config/storage.json'), true)); + } + public function getMysqlPdo() { if (!$this->mysql) { @@ -84,6 +89,6 @@ class OAuth2_Storage_Bootstrap private function getSqliteDir() { - return dirname(__FILE__).'/../../config/test.sqlite'; + return dirname(__FILE__).'/../../../config/test.sqlite'; } }
\ No newline at end of file |
