diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..133c78b8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,7 @@ +language: php + +php: + - 5.3 + - 5.4 + +script: phpunit --coverage-text --configuration build/phpunit.xml \ No newline at end of file diff --git a/README.md b/README.md index eb16e602..ff47bfce 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ The framework is provided as a Composer package which can be installed by adding ```javascript { - "require": { - "lncd\Oauth2": "*" + "require": { + "lncd\Oauth2": "*" } } ``` @@ -22,7 +22,12 @@ Check out the [wiki](https://github.com/lncd/OAuth2/wiki) ### Authentication Server -The authentication server is a flexible class that supports the standard authorization code grant. +The authentication server is a flexible class that supports the following grants: + +* authentication code +* refresh token +* client credentials +* password (user credentials) ### Resource Server diff --git a/build/phpunit.xml b/build/phpunit.xml index e74535da..18e40915 100644 --- a/build/phpunit.xml +++ b/build/phpunit.xml @@ -13,6 +13,7 @@ PEAR_INSTALL_DIR PHP_LIBDIR ../vendor/composer + ../tests diff --git a/composer.json b/composer.json index f2a89158..e87e8077 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "lncd/oauth2", "description": "OAuth 2.0 Framework", - "version": "0.3.5", + "version": "0.4", "homepage": "https://github.com/lncd/OAuth2", "license": "MIT", "require": { diff --git a/sql/database.sql b/sql/database.sql index 8c01870c..b260d9f0 100644 --- a/sql/database.sql +++ b/sql/database.sql @@ -21,11 +21,12 @@ CREATE TABLE `client_endpoints` ( CREATE TABLE `oauth_sessions` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `client_id` varchar(40) NOT NULL DEFAULT '', - `redirect_uri` varchar(250) NOT NULL DEFAULT '', + `redirect_uri` varchar(250) DEFAULT '', `owner_type` enum('user','client') NOT NULL DEFAULT 'user', `owner_id` varchar(255) DEFAULT NULL, `auth_code` varchar(40) DEFAULT '', `access_token` varchar(40) DEFAULT '', + `refresh_token` varchar(40) NOT NULL, `access_token_expires` int(10) DEFAULT NULL, `stage` enum('requested','granted') NOT NULL DEFAULT 'requested', `first_requested` int(10) unsigned NOT NULL, @@ -56,4 +57,4 @@ CREATE TABLE `oauth_session_scopes` ( KEY `scope` (`scope`), CONSTRAINT `oauth_session_scopes_ibfk_3` FOREIGN KEY (`scope`) REFERENCES `scopes` (`scope`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `oauth_session_scopes_ibfk_4` FOREIGN KEY (`session_id`) REFERENCES `oauth_sessions` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; \ No newline at end of file +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/src/Oauth2/Authentication/Database.php b/src/Oauth2/Authentication/Database.php index b46a05ec..b9de679b 100644 --- a/src/Oauth2/Authentication/Database.php +++ b/src/Oauth2/Authentication/Database.php @@ -56,18 +56,19 @@ interface Database * * * INSERT INTO oauth_sessions (client_id, redirect_uri, owner_type, - * owner_id, auth_code, access_token, stage, first_requested, last_updated) - * VALUES ($clientId, $redirectUri, $type, $typeId, $authCode, - * $accessToken, $stage, UNIX_TIMESTAMP(NOW()), UNIX_TIMESTAMP(NOW())) + * owner_id, auth_code, access_token, refresh_token, stage, first_requested, + * last_updated) VALUES ($clientId, $redirectUri, $type, $typeId, $authCode, + * $accessToken, $stage, UNIX_TIMESTAMP(NOW()), UNIX_TIMESTAMP(NOW())) * * - * @param string $clientId The client ID - * @param string $redirectUri The redirect URI - * @param string $type The session owner's type (default = "user") - * @param string $typeId The session owner's ID (default = "null") - * @param string $authCode The authorisation code (default = "null") - * @param string $accessToken The access token (default = "null") - * @param string $stage The stage of the session (default ="request") + * @param string $clientId The client ID + * @param string $redirectUri The redirect URI + * @param string $type The session owner's type (default = "user") + * @param string $typeId The session owner's ID (default = "null") + * @param string $authCode The authorisation code (default = "null") + * @param string $accessToken The access token (default = "null") + * @param string $refreshToken The refresh token (default = "null") + * @param string $stage The stage of the session (default ="request") * @return int The session ID */ public function newSession( @@ -77,6 +78,7 @@ interface Database $typeId = null, $authCode = null, $accessToken = null, + $refreshToken = null, $accessTokenExpire = null, $stage = 'requested' ); @@ -92,16 +94,18 @@ interface Database * id = $sessionId * * - * @param string $sessionId The session ID - * @param string $authCode The authorisation code (default = "null") - * @param string $accessToken The access token (default = "null") - * @param string $stage The stage of the session (default ="request") + * @param string $sessionId The session ID + * @param string $authCode The authorisation code (default = "null") + * @param string $accessToken The access token (default = "null") + * @param string $refreshToken The refresh token (default = "null") + * @param string $stage The stage of the session (default ="request") * @return void */ public function updateSession( $sessionId, $authCode = null, $accessToken = null, + $refreshToken = null, $accessTokenExpire = null, $stage = 'requested' ); @@ -125,6 +129,27 @@ interface Database $typeId ); + public function validateRefreshToken($refreshToken, $clientId); + + /** + * Update the refresh token + * + * Database query: + * + * + * UPDATE oauth_sessions SET access_token = $newAccessToken, refresh_token = + * $newRefreshToken, access_toke_expires = $accessTokenExpires, last_updated = UNIX_TIMESTAMP(NOW()) WHERE + * id = $sessionId + * + * + * @param string $sessionId The session ID + * @param string $newAccessToken The new access token for this session + * @param string $newRefreshToken The new refresh token for the session + * @param int $accessTokenExpires The UNIX timestamp of when the new token expires + * @return void + */ + public function updateRefreshToken($sessionId, $newAccessToken, $newRefreshToken, $accessTokenExpires); + /** * Validate that an authorisation code is valid * diff --git a/src/Oauth2/Authentication/Server.php b/src/Oauth2/Authentication/Server.php index 3e295626..82a2800a 100644 --- a/src/Oauth2/Authentication/Server.php +++ b/src/Oauth2/Authentication/Server.php @@ -30,15 +30,15 @@ class Server * @var array */ private $_config = array( - 'scope_delimeter' => ',', - 'access_token_ttl' => null + 'scope_delimeter' => ',', + 'access_token_ttl' => 3600 ); /** * Supported response types * @var array */ - private $_responseTypes = array( + private $_responseTypes = array( 'code' ); @@ -46,8 +46,15 @@ class Server * Supported grant types * @var array */ - private $_grantTypes = array( - 'authorization_code' + private $_grantTypes = array( + 'authorization_code' => false, + 'client_credentials' => false, + 'password' => false, + 'refresh_token' => false, + ); + + private $_grantTypeCallbacks = array( + 'password' => null ); /** @@ -75,16 +82,18 @@ class Server * @var array */ public $errors = array( - 'invalid_request' => '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.', - 'unauthorized_client' => 'The client is not authorized to request an access token using this method.', - 'access_denied' => 'The resource owner or authorization server denied the request.', + 'invalid_request' => '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.', + 'unauthorized_client' => 'The client is not authorized to request an access token using this method.', + 'access_denied' => 'The resource owner or authorization server denied the request.', 'unsupported_response_type' => 'The authorization server does not support obtaining an access token using this method.', - 'invalid_scope' => 'The requested scope is invalid, unknown, or malformed. Check the "%s" scope.', - 'server_error' => 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.', + 'invalid_scope' => 'The requested scope is invalid, unknown, or malformed. Check the "%s" scope.', + 'server_error' => 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.', 'temporarily_unavailable' => 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.', - 'unsupported_grant_type' => 'The authorization grant type is not supported by the authorization server', - 'invalid_client' => 'Client authentication failed', - 'invalid_grant' => '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.' + 'unsupported_grant_type' => 'The authorization grant type "%s" is not supported by the authorization server', + 'invalid_client' => 'Client authentication failed', + 'invalid_grant' => '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.', + 'invalid_credentials' => 'The user credentials were incorrect.', + 'invalid_refresh' => 'The refresh token is invalid.', ); /** @@ -97,7 +106,7 @@ class Server public function __construct($options = null) { if ($options !== null) { - $this->options = array_merge($this->_config, $options); + $this->_config = array_merge($this->_config, $options); } } @@ -113,6 +122,27 @@ class Server $this->_db = $db; } + /** + * Enable a grant type + * + * @access public + * @return void + */ + public function enableGrantType($type, $callback = null) + { + if (isset($this->_grantTypes[$type])) { + $this->_grantTypes[$type] = true; + } + + if (in_array($type, array_keys($this->_grantTypeCallbacks))) { + if (is_null($callback) || ! is_callable($callback)) { + throw new ServerException('No registered callback function for grant type `'.$type.'`'); + } + + $this->_grantTypeCallbacks[$type] = $callback; + } + } + /** * Check client authorise parameters * @@ -126,30 +156,22 @@ class Server // Client ID if ( ! isset($authParams['client_id']) && ! isset($_GET['client_id'])) { - throw new ClientException(sprintf($this->errors['invalid_request'], 'client_id'), 0); - - } else { - - $params['client_id'] = (isset($authParams['client_id'])) ? - $authParams['client_id'] : - $_GET['client_id']; - } + $params['client_id'] = (isset($authParams['client_id'])) ? + $authParams['client_id'] : + $_GET['client_id']; + // Redirect URI if ( ! isset($authParams['redirect_uri']) && ! isset($_GET['redirect_uri'])) { - throw new ClientException(sprintf($this->errors['invalid_request'], 'redirect_uri'), 0); - - } else { - - $params['redirect_uri'] = (isset($authParams['redirect_uri'])) ? - $authParams['redirect_uri'] : - $_GET['redirect_uri']; - } + $params['redirect_uri'] = (isset($authParams['redirect_uri'])) ? + $authParams['redirect_uri'] : + $_GET['redirect_uri']; + // Validate client ID and redirect URI $clientDetails = $this->_dbCall( 'validateClient', @@ -159,7 +181,6 @@ class Server ); if ($clientDetails === false) { - throw new ClientException($this->errors['invalid_client'], 8); } @@ -167,29 +188,24 @@ class Server // Response type if ( ! isset($authParams['response_type']) && ! isset($_GET['response_type'])) { - throw new ClientException(sprintf($this->errors['invalid_request'], 'response_type'), 0); + } - } else { + $params['response_type'] = (isset($authParams['response_type'])) ? + $authParams['response_type'] : + $_GET['response_type']; - $params['response_type'] = (isset($authParams['response_type'])) ? - $authParams['response_type'] : - $_GET['response_type']; - - // Ensure response type is one that is recognised - if ( ! in_array($params['response_type'], $this->_responseTypes)) { - - throw new ClientException($this->errors['unsupported_response_type'], 3); - - } + // Ensure response type is one that is recognised + if ( ! in_array($params['response_type'], $this->_responseTypes)) { + throw new ClientException($this->errors['unsupported_response_type'], 3); } // Get and validate scopes if (isset($authParams['scope']) || isset($_GET['scope'])) { $scopes = (isset($_GET['scope'])) ? - $_GET['scope'] : - $authParams['scope']; + $_GET['scope'] : + $authParams['scope']; $scopes = explode($this->_config['scope_delimeter'], $scopes); @@ -204,7 +220,6 @@ class Server } if (count($scopes) === 0) { - throw new ClientException(sprintf($this->errors['invalid_request'], 'scope'), 0); } @@ -218,9 +233,7 @@ class Server ); if ($scopeDetails === false) { - throw new ClientException(sprintf($this->errors['invalid_scope'], $scope), 4); - } $params['scopes'][] = $scopeDetails; @@ -250,7 +263,7 @@ class Server ); // Create the new auth code - $authCode = $this->newAuthCode( + $authCode = $this->_newAuthCode( $authoriseParams['client_id'], 'user', $typeId, @@ -268,7 +281,7 @@ class Server * * @return string A unique code */ - private function generateCode() + private function _generateCode() { return sha1(uniqid(microtime())); } @@ -284,53 +297,35 @@ class Server * @param string $accessToken The access token (default = null) * @return string An authorisation code */ - private function newAuthCode($clientId, $type, $typeId, $redirectUri, $scopes = array(), $accessToken = null) + private function _newAuthCode($clientId, $type, $typeId, $redirectUri, $scopes = array()) { - $authCode = $this->generateCode(); + $authCode = $this->_generateCode(); - // If an access token exists then update the existing session with the - // new authorisation code otherwise create a new session - if ($accessToken !== null) { + // Delete any existing sessions just to be sure + $this->_dbCall('deleteSession', $clientId, $type, $typeId); + + // Create a new session + $sessionId = $this->_dbCall( + 'newSession', + $clientId, + $redirectUri, + $type, + $typeId, + $authCode, + null, + null, + 'requested' + ); + + // Add the scopes + foreach ($scopes as $key => $scope) { $this->_dbCall( - 'updateSession', - $clientId, - $type, - $typeId, - $authCode, - $accessToken, - 'requested' + 'addSessionScope', + $sessionId, + $scope['scope'] ); - } else { - - // Delete any existing sessions just to be sure - $this->_dbCall('deleteSession', $clientId, $type, $typeId); - - // Create a new session - $sessionId = $this->_dbCall( - 'newSession', - $clientId, - $redirectUri, - $type, - $typeId, - $authCode, - null, - null, - 'requested' - ); - - // Add the scopes - foreach ($scopes as $key => $scope) { - - $this->_dbCall( - 'addSessionScope', - $sessionId, - $scope['scope'] - ); - - } - } return $authCode; @@ -347,40 +342,43 @@ class Server */ public function issueAccessToken($authParams = null) { - $params = array(); - if ( ! isset($authParams['grant_type']) && ! isset($_POST['grant_type'])) { - throw new ClientException(sprintf($this->errors['invalid_request'], 'grant_type'), 0); + } - } else { + $params['grant_type'] = (isset($authParams['grant_type'])) ? + $authParams['grant_type'] : + $_POST['grant_type']; - $params['grant_type'] = (isset($authParams['grant_type'])) ? - $authParams['grant_type'] : - $_POST['grant_type']; - - // Ensure grant type is one that is recognised - if ( ! in_array($params['grant_type'], $this->_grantTypes)) { - - throw new ClientException($this->errors['unsupported_grant_type'], 7); - - } + // Ensure grant type is one that is recognised and is enabled + if ( ! in_array($params['grant_type'], array_keys($this->_grantTypes)) || $this->_grantTypes[$params['grant_type']] !== true) { + throw new ClientException(sprintf($this->errors['unsupported_grant_type'], $params['grant_type']), 7); } switch ($params['grant_type']) { - case 'authorization_code': // Authorization code grant - return $this->completeAuthCodeGrant($authParams, $params); + return $this->_completeAuthCodeGrant($authParams, $params); break; - case 'refresh_token': // Refresh token - case 'password': // Resource owner password credentials grant case 'client_credentials': // Client credentials grant + return $this->_completeClientCredentialsGrant($authParams, $params); + break; + + case 'password': // Resource owner password credentials grant + return $this->_completeUserCredentialsGrant($authParams, $params); + break; + + case 'refresh_token': // Refresh token grant + return $this->_completeRefreshTokenGrant($authParams, $params); + break; + + // @codeCoverageIgnoreStart default: // Unsupported throw new ServerException($this->errors['server_error'] . 'Tried to process an unsuppported grant type.', 5); break; } + // @codeCoverageIgnoreEnd } /** @@ -393,47 +391,35 @@ class Server * * @return array Authorise request parameters */ - private function completeAuthCodeGrant($authParams = array(), $params = array()) + private function _completeAuthCodeGrant($authParams = array(), $params = array()) { // Client ID if ( ! isset($authParams['client_id']) && ! isset($_POST['client_id'])) { - throw new ClientException(sprintf($this->errors['invalid_request'], 'client_id'), 0); - - } else { - - $params['client_id'] = (isset($authParams['client_id'])) ? - $authParams['client_id'] : - $_POST['client_id']; - } + $params['client_id'] = (isset($authParams['client_id'])) ? + $authParams['client_id'] : + $_POST['client_id']; + // Client secret if ( ! isset($authParams['client_secret']) && ! isset($_POST['client_secret'])) { - throw new ClientException(sprintf($this->errors['invalid_request'], 'client_secret'), 0); - - } else { - - $params['client_secret'] = (isset($authParams['client_secret'])) ? - $authParams['client_secret'] : - $_POST['client_secret']; - } + $params['client_secret'] = (isset($authParams['client_secret'])) ? + $authParams['client_secret'] : + $_POST['client_secret']; + // Redirect URI if ( ! isset($authParams['redirect_uri']) && ! isset($_POST['redirect_uri'])) { - throw new ClientException(sprintf($this->errors['invalid_request'], 'redirect_uri'), 0); - - } else { - - $params['redirect_uri'] = (isset($authParams['redirect_uri'])) ? - $authParams['redirect_uri'] : - $_POST['redirect_uri']; - } + $params['redirect_uri'] = (isset($authParams['redirect_uri'])) ? + $authParams['redirect_uri'] : + $_POST['redirect_uri']; + // Validate client ID and redirect URI $clientDetails = $this->_dbCall( 'validateClient', @@ -443,25 +429,19 @@ class Server ); if ($clientDetails === false) { - throw new ClientException($this->errors['invalid_client'], 8); } // The authorization code if ( ! isset($authParams['code']) && ! isset($_POST['code'])) { - throw new ClientException(sprintf($this->errors['invalid_request'], 'code'), 0); - - } else { - - $params['code'] = (isset($authParams['code'])) ? - $authParams['code'] : - $_POST['code']; - } - // Verify the authorization code matches the client_id and the - // request_uri + $params['code'] = (isset($authParams['code'])) ? + $authParams['code'] : + $_POST['code']; + + // Verify the authorization code matches the client_id and the request_uri $session = $this->_dbCall( 'validateAuthCode', $params['client_id'], @@ -470,42 +450,306 @@ class Server ); if ( ! $session) { - throw new ClientException(sprintf($this->errors['invalid_grant'], 'code'), 9); - - } else { - - // A session ID was returned so update it with an access token, - // remove the authorisation code, change the stage to 'granted' - - $accessToken = $this->generateCode(); - - $accessTokenExpires = ($this->_config['access_token_ttl'] === null) ? - null : - time() + $this->_config['access_token_ttl']; - - $this->_dbCall( - 'updateSession', - $session['id'], - null, - $accessToken, - $accessTokenExpires, - 'granted' - ); - - // Update the session's scopes to reference the access token - $this->_dbCall( - 'updateSessionScopeAccessToken', - $session['id'], - $accessToken - ); - - return array( - 'access_token' => $accessToken, - 'token_type' => 'bearer', - 'expires_in' => $this->_config['access_token_ttl'] - ); } + + // A session ID was returned so update it with an access token, + // remove the authorisation code, change the stage to 'granted' + + $accessToken = $this->_generateCode(); + $refreshToken = ($this->_grantTypes['refresh_token']) ? + $this->_generateCode() : + null; + + $accessTokenExpires = time() + $this->_config['access_token_ttl']; + $accessTokenExpiresIn = $this->_config['access_token_ttl']; + + $this->_dbCall( + 'updateSession', + $session['id'], + null, + $accessToken, + $refreshToken, + $accessTokenExpires, + 'granted' + ); + + // Update the session's scopes to reference the access token + $this->_dbCall( + 'updateSessionScopeAccessToken', + $session['id'], + $accessToken, + $refreshToken + ); + + $response = array( + 'access_token' => $accessToken, + 'token_type' => 'bearer', + 'expires' => $accessTokenExpires, + 'expires_in' => $accessTokenExpiresIn + ); + + if ($this->_grantTypes['refresh_token']) { + $response['refresh_token'] = $refreshToken; + } + + return $response; + } + + /** + * Complete the resource owner password credentials grant + * + * @access private + * @param array $authParams Array of parsed $_POST keys + * @param array $params Generated parameters from issueAccessToken() + * @return array Authorise request parameters + */ + private function _completeClientCredentialsGrant($authParams = array(), $params = array()) + { + // Client ID + if ( ! isset($authParams['client_id']) && ! isset($_POST['client_id'])) { + // @codeCoverageIgnoreStart + throw new ClientException(sprintf($this->errors['invalid_request'], 'client_id'), 0); + // @codeCoverageIgnoreEnd + } + + $params['client_id'] = (isset($authParams['client_id'])) ? + $authParams['client_id'] : + $_POST['client_id']; + + // Client secret + if ( ! isset($authParams['client_secret']) && ! isset($_POST['client_secret'])) { + // @codeCoverageIgnoreStart + throw new ClientException(sprintf($this->errors['invalid_request'], 'client_secret'), 0); + // @codeCoverageIgnoreEnd + } + + $params['client_secret'] = (isset($authParams['client_secret'])) ? + $authParams['client_secret'] : + $_POST['client_secret']; + + // Validate client ID and client secret + $clientDetails = $this->_dbCall( + 'validateClient', + $params['client_id'], + $params['client_secret'], + null + ); + + if ($clientDetails === false) { + // @codeCoverageIgnoreStart + throw new ClientException($this->errors['invalid_client'], 8); + // @codeCoverageIgnoreEnd + } + + // Generate an access token + $accessToken = $this->_generateCode(); + $refreshToken = ($this->_grantTypes['refresh_token']) ? + $this->_generateCode() : + null; + + $accessTokenExpires = time() + $this->_config['access_token_ttl']; + $accessTokenExpiresIn = $this->_config['access_token_ttl']; + + // Delete any existing sessions just to be sure + $this->_dbCall('deleteSession', $params['client_id'], 'client', $params['client_id']); + + // Create a new session + $this->_dbCall('newSession', $params['client_id'], null, 'client', $params['client_id'], null, $accessToken, $refreshToken, $accessTokenExpires, 'granted'); + + $response = array( + 'access_token' => $accessToken, + 'token_type' => 'bearer', + 'expires' => $accessTokenExpires, + 'expires_in' => $accessTokenExpiresIn + ); + + if ($this->_grantTypes['refresh_token']) { + $response['refresh_token'] = $refreshToken; + } + + return $response; + } + + /** + * Complete the resource owner password credentials grant + * + * @access private + * @param array $authParams Array of parsed $_POST keys + * @param array $params Generated parameters from issueAccessToken() + * @return array Authorise request parameters + */ + private function _completeUserCredentialsGrant($authParams = array(), $params = array()) + { + // Client ID + if ( ! isset($authParams['client_id']) && ! isset($_POST['client_id'])) { + // @codeCoverageIgnoreStart + throw new ClientException(sprintf($this->errors['invalid_request'], 'client_id'), 0); + // @codeCoverageIgnoreEnd + } + + $params['client_id'] = (isset($authParams['client_id'])) ? + $authParams['client_id'] : + $_POST['client_id']; + + // Client secret + if ( ! isset($authParams['client_secret']) && ! isset($_POST['client_secret'])) { + // @codeCoverageIgnoreStart + throw new ClientException(sprintf($this->errors['invalid_request'], 'client_secret'), 0); + // @codeCoverageIgnoreEnd + } + + $params['client_secret'] = (isset($authParams['client_secret'])) ? + $authParams['client_secret'] : + $_POST['client_secret']; + + // Validate client ID and client secret + $clientDetails = $this->_dbCall( + 'validateClient', + $params['client_id'], + $params['client_secret'], + null + ); + + if ($clientDetails === false) { + // @codeCoverageIgnoreStart + throw new ClientException($this->errors['invalid_client'], 8); + // @codeCoverageIgnoreEnd + } + + // User's username + if ( ! isset($authParams['username']) && ! isset($_POST['username'])) { + throw new ClientException(sprintf($this->errors['invalid_request'], 'username'), 0); + } + + $params['username'] = (isset($authParams['username'])) ? + $authParams['username'] : + $_POST['username']; + + // User's password + if ( ! isset($authParams['password']) && ! isset($_POST['password'])) { + throw new ClientException(sprintf($this->errors['invalid_request'], 'password'), 0); + } + + $params['password'] = (isset($authParams['password'])) ? + $authParams['password'] : + $_POST['password']; + + // Check if user's username and password are correct + $userId = call_user_func($this->_grantTypeCallbacks['password'], $params['username'], $params['password']); + + if ($userId === false) { + throw new \Oauth2\Authentication\ClientException($this->errors['invalid_credentials'], 0); + } + + // Generate an access token + $accessToken = $this->_generateCode(); + $refreshToken = ($this->_grantTypes['refresh_token']) ? + $this->_generateCode() : + null; + + $accessTokenExpires = time() + $this->_config['access_token_ttl']; + $accessTokenExpiresIn = $this->_config['access_token_ttl']; + + // Delete any existing sessions just to be sure + $this->_dbCall('deleteSession', $params['client_id'], 'user', $userId); + + // Create a new session + $this->_dbCall('newSession', $params['client_id'], null, 'user', $userId, null, $accessToken, $refreshToken, $accessTokenExpires, 'granted'); + + $response = array( + 'access_token' => $accessToken, + 'token_type' => 'bearer', + 'expires' => $accessTokenExpires, + 'expires_in' => $accessTokenExpiresIn + ); + + if ($this->_grantTypes['refresh_token']) { + $response['refresh_token'] = $refreshToken; + } + + return $response; + } + + /** + * Complete the refresh token grant + * + * @access private + * @param array $authParams Array of parsed $_POST keys + * @param array $params Generated parameters from issueAccessToken() + * @return array Authorise request parameters + */ + private function _completeRefreshTokenGrant($authParams = array(), $params = array()) + { + // Client ID + if ( ! isset($authParams['client_id']) && ! isset($_POST['client_id'])) { + // @codeCoverageIgnoreStart + throw new ClientException(sprintf($this->errors['invalid_request'], 'client_id'), 0); + // @codeCoverageIgnoreEnd + } + + $params['client_id'] = (isset($authParams['client_id'])) ? + $authParams['client_id'] : + $_POST['client_id']; + + // Client secret + if ( ! isset($authParams['client_secret']) && ! isset($_POST['client_secret'])) { + // @codeCoverageIgnoreStart + throw new ClientException(sprintf($this->errors['invalid_request'], 'client_secret'), 0); + // @codeCoverageIgnoreEnd + } + + $params['client_secret'] = (isset($authParams['client_secret'])) ? + $authParams['client_secret'] : + $_POST['client_secret']; + + // Validate client ID and client secret + $clientDetails = $this->_dbCall( + 'validateClient', + $params['client_id'], + $params['client_secret'], + null + ); + + if ($clientDetails === false) { + // @codeCoverageIgnoreStart + throw new ClientException($this->errors['invalid_client'], 8); + // @codeCoverageIgnoreEnd + } + + // Refresh token + if ( ! isset($authParams['refresh_token']) && ! isset($_POST['refresh_token'])) { + throw new ClientException(sprintf($this->errors['invalid_request'], 'refresh_token'), 0); + } + + $params['refresh_token'] = (isset($authParams['refresh_token'])) ? + $authParams['refresh_token'] : + $_POST['refresh_token']; + + // Validate refresh token + $sessionId = $this->_dbCall('validateRefreshToken', $params['refresh_token'], $params['client_id']); + + if ($sessionId === false) { + throw new \Oauth2\Authentication\ClientException($this->errors['invalid_refresh'], 0); + } + + // Generate new tokens + $accessToken = $this->_generateCode(); + $refreshToken = $this->_generateCode(); + + $accessTokenExpires = time() + $this->_config['access_token_ttl']; + $accessTokenExpiresIn = $this->_config['access_token_ttl']; + + // Update the tokens + $this->_dbCall('updateRefreshToken', $sessionId, $accessToken, $refreshToken, $accessTokenExpires); + + return array( + 'access_token' => $accessToken, + 'refresh_token' => $refreshToken, + 'token_type' => 'bearer', + 'expires' => $accessTokenExpires, + 'expires_in' => $accessTokenExpiresIn + ); } /** @@ -519,19 +763,7 @@ class Server */ public function redirectUri($redirectUri, $params = array(), $queryDelimeter = '?') { - - if (strstr($redirectUri, $queryDelimeter)) { - - $redirectUri = $redirectUri . '&' . http_build_query($params); - - } else { - - $redirectUri = $redirectUri . $queryDelimeter . http_build_query($params); - - } - - return $redirectUri; - + return (strstr($redirectUri, $queryDelimeter)) ? $redirectUri . '&' . http_build_query($params) : $redirectUri . $queryDelimeter . http_build_query($params); } /** diff --git a/tests/authentication/database_mock.php b/tests/authentication/database_mock.php index f13c1537..594d2665 100644 --- a/tests/authentication/database_mock.php +++ b/tests/authentication/database_mock.php @@ -4,151 +4,165 @@ use Oauth2\Authentication\Database; class OAuthdb implements Database { - private $sessions = array(); - private $sessions_client_type_id = array(); - private $sessions_code = array(); - private $session_scopes = array(); + private $sessions = array(); + private $sessions_client_type_id = array(); + private $sessions_code = array(); + private $session_scopes = array(); - private $clients = array(0 => array( - 'client_id' => 'test', - 'client_secret' => 'test', - 'redirect_uri' => 'http://example.com/test', - 'name' => 'Test Client' - )); + private $clients = array(0 => array( + 'client_id' => 'test', + 'client_secret' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'name' => 'Test Client' + )); - private $scopes = array('test' => array( - 'id' => 1, - 'scope' => 'test', - 'name' => 'test', - 'description' => 'test' - )); + private $scopes = array('test' => array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + )); - public function validateClient($clientId, $clientSecret = null, $redirectUri = null) - { - if ($clientId !== $this->clients[0]['client_id']) - { - return false; - } + public function validateClient($clientId, $clientSecret = null, $redirectUri = null) + { + if ($clientId !== $this->clients[0]['client_id']) { + return false; + } - if ($clientSecret !== null && $clientSecret !== $this->clients[0]['client_secret']) - { - return false; - } + if ($clientSecret !== null && $clientSecret !== $this->clients[0]['client_secret']) { + return false; + } - if ($redirectUri !== null && $redirectUri !== $this->clients[0]['redirect_uri']) - { - return false; - } + if ($redirectUri !== null && $redirectUri !== $this->clients[0]['redirect_uri']) { + return false; + } - return $this->clients[0]; - } + return $this->clients[0]; + } - public function newSession($clientId, $redirectUri, $type = 'user', $typeId = null, $authCode = null, $accessToken = null, $accessTokenExpire = null, $stage = 'requested') - { - $id = count($this->sessions); + public function newSession($clientId, $redirectUri, $type = 'user', $typeId = null, $authCode = null, $accessToken = null, $refreshToken = null, $accessTokenExpire = null, $stage = 'requested') + { + $id = count($this->sessions); - $this->sessions[$id] = array( - 'id' => $id, - 'client_id' => $clientId, - 'redirect_uri' => $redirectUri, - 'owner_type' => $type, - 'owner_id' => $typeId, - 'auth_code' => $authCode, - 'access_token' => $accessToken, - 'access_token_expire' => $accessTokenExpire, - 'stage' => $stage - ); + $this->sessions[$id] = array( + 'id' => $id, + 'client_id' => $clientId, + 'redirect_uri' => $redirectUri, + 'owner_type' => $type, + 'owner_id' => $typeId, + 'auth_code' => $authCode, + 'access_token' => $accessToken, + 'refresh_token' => $refreshToken, + 'access_token_expire' => $accessTokenExpire, + 'stage' => $stage + ); - $this->sessions_client_type_id[$clientId . ':' . $type . ':' . $typeId] = $id; - $this->sessions_code[$clientId . ':' . $redirectUri . ':' . $authCode] = $id; + $this->sessions_client_type_id[$clientId . ':' . $type . ':' . $typeId] = $id; + $this->sessions_code[$clientId . ':' . $redirectUri . ':' . $authCode] = $id; - return $id; - } + return $id; + } - public function updateSession($sessionId, $authCode = null, $accessToken = null, $accessTokenExpire = null, $stage = 'requested') - { - $this->sessions[$sessionId]['auth_code'] = $authCode; - $this->sessions[$sessionId]['access_token'] = $accessToken; - $this->sessions[$sessionId]['access_token_expire'] = $accessTokenExpire; - $this->sessions[$sessionId]['stage'] = $stage; + public function updateSession($sessionId, $authCode = null, $accessToken = null, $refreshToken = null, $accessTokenExpire = null, $stage = 'requested') + { + $this->sessions[$sessionId]['auth_code'] = $authCode; + $this->sessions[$sessionId]['access_token'] = $accessToken; + $this->sessions[$sessionId]['refresh_token'] = $refreshToken; + $this->sessions[$sessionId]['access_token_expire'] = $accessTokenExpire; + $this->sessions[$sessionId]['stage'] = $stage; - return true; - } + return true; + } - public function deleteSession($clientId, $type, $typeId) - { - $key = $clientId . ':' . $type . ':' . $typeId; - if (isset($this->sessions_client_type_id[$key])) - { - unset($this->sessions[$this->sessions_client_type_id[$key]]); - } - return true; - } + public function deleteSession($clientId, $type, $typeId) + { + $key = $clientId . ':' . $type . ':' . $typeId; + if (isset($this->sessions_client_type_id[$key])) { + unset($this->sessions[$this->sessions_client_type_id[$key]]); + } + return true; + } - public function validateAuthCode($clientId, $redirectUri, $authCode) - { - $key = $clientId . ':' . $redirectUri . ':' . $authCode; + public function refreshToken($currentRefreshToken, $newAccessToken, $newRefreshToken, $accessTokenExpires) + { + die('not implemented refreshToken'); + } - if (isset($this->sessions_code[$key])) - { - return $this->sessions[$this->sessions_code[$key]]; - } + public function validateAuthCode($clientId, $redirectUri, $authCode) + { + $key = $clientId . ':' . $redirectUri . ':' . $authCode; - return false; - } + if (isset($this->sessions_code[$key])) { + return $this->sessions[$this->sessions_code[$key]]; + } - public function hasSession($type, $typeId, $clientId) - { - die('not implemented hasSession'); - } + return false; + } - public function getAccessToken($sessionId) - { - die('not implemented getAccessToken'); - } + public function hasSession($type, $typeId, $clientId) + { + die('not implemented hasSession'); + } - public function removeAuthCode($sessionId) - { - die('not implemented removeAuthCode'); - } + public function getAccessToken($sessionId) + { + die('not implemented getAccessToken'); + } - public function setAccessToken( - $sessionId, - $accessToken - ) - { - die('not implemented setAccessToken'); - } + public function removeAuthCode($sessionId) + { + die('not implemented removeAuthCode'); + } - public function addSessionScope($sessionId, $scope) - { - if ( ! isset($this->session_scopes[$sessionId])) - { - $this->session_scopes[$sessionId] = array(); - } + public function setAccessToken($sessionId, $accessToken) + { + die('not implemented setAccessToken'); + } - $this->session_scopes[$sessionId][] = $scope; + public function addSessionScope($sessionId, $scope) + { + if ( ! isset($this->session_scopes[$sessionId])) { + $this->session_scopes[$sessionId] = array(); + } - return true; - } + $this->session_scopes[$sessionId][] = $scope; - public function getScope($scope) - { - if ( ! isset($this->scopes[$scope])) - { - return false; - } + return true; + } - return $this->scopes[$scope]; - } + public function getScope($scope) + { + if ( ! isset($this->scopes[$scope])) { + return false; + } - public function updateSessionScopeAccessToken($sessionId, $accessToken) - { - return true; - } + return $this->scopes[$scope]; + } - public function accessTokenScopes($accessToken) - { - die('not implemented accessTokenScopes'); - } + public function updateSessionScopeAccessToken($sessionId, $accessToken) + { + return true; + } + + public function accessTokenScopes($accessToken) + { + die('not implemented accessTokenScopes'); + } + + public function validateRefreshToken($refreshToken, $clientId) + { + if ($refreshToken !== $this->sessions[0]['refresh_token']) + { + return false; + } + + return true; + } + + public function updateRefreshToken($sessionId, $newAccessToken, $newRefreshToken, $accessTokenExpires) + { + $this->sessions[$sessionId]['access_token'] = $newAccessToken; + $this->sessions[$sessionId]['refresh_token'] = $newRefreshToken; + $this->sessions[$sessionId]['access_token_expire'] = $accessTokenExpires; + } } \ No newline at end of file diff --git a/tests/authentication/server_test.php b/tests/authentication/server_test.php index 7af8651e..ef677c7e 100644 --- a/tests/authentication/server_test.php +++ b/tests/authentication/server_test.php @@ -1,398 +1,915 @@ oauth = new Oauth2\Authentication\Server(); + $this->oauth = new Oauth2\Authentication\Server(); - require_once('database_mock.php'); - $this->oauthdb = new OAuthdb(); - $this->assertInstanceOf('Oauth2\Authentication\Database', $this->oauthdb); - $this->oauth->registerDbAbstractor($this->oauthdb); - } + require_once 'database_mock.php'; + $this->oauthdb = new OAuthdb(); + $this->assertInstanceOf('Oauth2\Authentication\Database', $this->oauthdb); + $this->oauth->registerDbAbstractor($this->oauthdb); + } - function test_generateCode() - { - $reflector = new ReflectionClass($this->oauth); - $method = $reflector->getMethod('generateCode'); - $method->setAccessible(true); + public function test_setupWithOptions() + { + $o = new Oauth2\Authentication\Server(array( + 'access_token_ttl' => 86400 + )); - $result = $method->invoke($this->oauth); - $result2 = $method->invoke($this->oauth); + $reflector = new ReflectionClass($o); + $param = $reflector->getProperty('_config'); + $param->setAccessible(true); + $array = $param->getValue($o); - $this->assertEquals(40, strlen($result)); - $this->assertNotEquals($result, $result2); - } + $this->assertEquals(86400, $array['access_token_ttl']); + } - function test_redirectUri() - { - $result1 = $this->oauth->redirectUri('http://example.com/foo'); - $result2 = $this->oauth->redirectUri('http://example.com/foo', array('foo' => 'bar')); - $result3 = $this->oauth->redirectUri('http://example.com/foo', array('foo' => 'bar'), '#'); + public function test_generateCode() + { + $reflector = new ReflectionClass($this->oauth); + $method = $reflector->getMethod('_generateCode'); + $method->setAccessible(true); - $this->assertEquals('http://example.com/foo?', $result1); - $this->assertEquals('http://example.com/foo?foo=bar', $result2); - $this->assertEquals('http://example.com/foo#foo=bar', $result3); - } + $result = $method->invoke($this->oauth); + $result2 = $method->invoke($this->oauth); - function test_checkClientAuthoriseParams_GET() - { - $_GET['client_id'] = 'test'; - $_GET['redirect_uri'] = 'http://example.com/test'; - $_GET['response_type'] = 'code'; - $_GET['scope'] = 'test'; - - $expect = array( - 'client_id' => 'test', - 'redirect_uri' => 'http://example.com/test', - 'response_type' => 'code', - 'scopes' => array( - 0 => array( - 'id' => 1, - 'scope' => 'test', - 'name' => 'test', - 'description' => 'test' - ) - ) - ); + $this->assertEquals(40, strlen($result)); + $this->assertNotEquals($result, $result2); + } - $result = $this->oauth->checkClientAuthoriseParams(); + public function test_redirectUri() + { + $result1 = $this->oauth->redirectUri('http://example.com/foo'); + $result2 = $this->oauth->redirectUri('http://example.com/foo', array('foo' => 'bar')); + $result3 = $this->oauth->redirectUri('http://example.com/foo', array('foo' => 'bar'), '#'); - $this->assertEquals($expect, $result); - } + $this->assertEquals('http://example.com/foo?', $result1); + $this->assertEquals('http://example.com/foo?foo=bar', $result2); + $this->assertEquals('http://example.com/foo#foo=bar', $result3); + } - function test_checkClientAuthoriseParams_PassedParams() - { - unset($_GET['client_id']); - unset($_GET['redirect_uri']); - unset($_GET['response_type']); - unset($_GET['scope']); + public function test_checkClientAuthoriseParams_GET() + { + $_GET['client_id'] = 'test'; + $_GET['redirect_uri'] = 'http://example.com/test'; + $_GET['response_type'] = 'code'; + $_GET['scope'] = 'test'; - $params = array( - 'client_id' => 'test', - 'redirect_uri' => 'http://example.com/test', - 'response_type' => 'code', - 'scope' => 'test' - ); + $expect = array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'client_details' => array( + 'client_id' => 'test', + 'client_secret' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'name' => 'Test Client' + ), + 'response_type' => 'code', + 'scopes' => array( + 0 => array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + ) + ) + ); - $this->assertEquals(array( - 'client_id' => 'test', - 'redirect_uri' => 'http://example.com/test', - 'response_type' => 'code', - 'scopes' => array(0 => array( - 'id' => 1, - 'scope' => 'test', - 'name' => 'test', - 'description' => 'test' - )) - ), $this->oauth->checkClientAuthoriseParams($params)); - } + $result = $this->oauth->checkClientAuthoriseParams(); - /** - * @expectedException Oauth2\Authentication\ClientException - * @expectedExceptionCode 0 - */ - function test_checkClientAuthoriseParams_missingClientId() - { - $this->oauth->checkClientAuthoriseParams(); - } + $this->assertEquals($expect, $result); + } - /** - * @expectedException Oauth2\Authentication\ClientException - * @expectedExceptionCode 0 - */ - function test_checkClientAuthoriseParams_missingRedirectUri() - { - $_GET['client_id'] = 'test'; + public function test_checkClientAuthoriseParams_PassedParams() + { + unset($_GET['client_id']); + unset($_GET['redirect_uri']); + unset($_GET['response_type']); + unset($_GET['scope']); - $this->oauth->checkClientAuthoriseParams(); - } + $params = array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'response_type' => 'code', + 'scope' => 'test' + ); - /** - * @expectedException Oauth2\Authentication\ClientException - * @expectedExceptionCode 0 - */ - function test_checkClientAuthoriseParams_missingResponseType() - { - $_GET['client_id'] = 'test'; - $_GET['redirect_uri'] = 'http://example.com/test'; + $this->assertEquals(array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'client_details' => array( + 'client_id' => 'test', + 'client_secret' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'name' => 'Test Client' + ), + 'response_type' => 'code', + 'scopes' => array(0 => array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + )) + ), $this->oauth->checkClientAuthoriseParams($params)); + } - $this->oauth->checkClientAuthoriseParams(); - } + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 0 + */ + public function test_checkClientAuthoriseParams_missingClientId() + { + $this->oauth->checkClientAuthoriseParams(); + } - /** - * @expectedException Oauth2\Authentication\ClientException - * @expectedExceptionCode 0 - */ - function test_checkClientAuthoriseParams_missingScopes() - { - $_GET['client_id'] = 'test'; - $_GET['redirect_uri'] = 'http://example.com/test'; - $_GET['response_type'] = 'code'; - $_GET['scope'] = ' '; + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 0 + */ + public function test_checkClientAuthoriseParams_missingRedirectUri() + { + $_GET['client_id'] = 'test'; - $this->oauth->checkClientAuthoriseParams(); - } + $this->oauth->checkClientAuthoriseParams(); + } - /** - * @expectedException Oauth2\Authentication\ClientException - * @expectedExceptionCode 4 - */ - function test_checkClientAuthoriseParams_invalidScopes() - { - $_GET['client_id'] = 'test'; - $_GET['redirect_uri'] = 'http://example.com/test'; - $_GET['response_type'] = 'code'; - $_GET['scope'] = 'blah'; + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 0 + */ + public function test_checkClientAuthoriseParams_missingResponseType() + { + $_GET['client_id'] = 'test'; + $_GET['redirect_uri'] = 'http://example.com/test'; - $this->oauth->checkClientAuthoriseParams(); - } + $this->oauth->checkClientAuthoriseParams(); + } - function test_newAuthoriseRequest() - { - $result = $this->oauth->newAuthoriseRequest('user', '123', array( - 'client_id' => 'test', - 'redirect_uri' => 'http://example.com/test', - 'scopes' => array(array( - 'id' => 1, - 'scope' => 'test', - 'name' => 'test', - 'description' => 'test' - )) - )); + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 0 + */ + public function test_checkClientAuthoriseParams_missingScopes() + { + $_GET['client_id'] = 'test'; + $_GET['redirect_uri'] = 'http://example.com/test'; + $_GET['response_type'] = 'code'; + $_GET['scope'] = ' '; - $this->assertEquals(40, strlen($result)); - } + $this->oauth->checkClientAuthoriseParams(); + } - function test_newAuthoriseRequest_isUnique() - { - $result1 = $this->oauth->newAuthoriseRequest('user', '123', array( - 'client_id' => 'test', - 'redirect_uri' => 'http://example.com/test', - 'scopes' => array(array( - 'id' => 1, - 'scope' => 'test', - 'name' => 'test', - 'description' => 'test' - )) - )); + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 4 + */ + public function test_checkClientAuthoriseParams_invalidScopes() + { + $_GET['client_id'] = 'test'; + $_GET['redirect_uri'] = 'http://example.com/test'; + $_GET['response_type'] = 'code'; + $_GET['scope'] = 'blah'; - $result2 = $this->oauth->newAuthoriseRequest('user', '123', array( - 'client_id' => 'test', - 'redirect_uri' => 'http://example.com/test', - 'scopes' => array(array( - 'id' => 1, - 'scope' => 'test', - 'name' => 'test', - 'description' => 'test' - )) - )); + $this->oauth->checkClientAuthoriseParams(); + } - $this->assertNotEquals($result1, $result2); - } + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 8 + */ + public function test_checkClientAuthoriseParams_invalidClient() + { + $_GET['client_id'] = 'test'; + $_GET['redirect_uri'] = 'http://example.com/test2'; + $_GET['response_type'] = 'code'; + $_GET['scope'] = 'blah'; - function test_issueAccessToken_POST() - { - $auth_code = $this->oauth->newAuthoriseRequest('user', '123', array( - 'client_id' => 'test', - 'redirect_uri' => 'http://example.com/test', - 'scopes' => array(array( - 'id' => 1, - 'scope' => 'test', - 'name' => 'test', - 'description' => 'test' - )) - )); + $this->oauth->checkClientAuthoriseParams(); + } - $_POST['client_id'] = 'test'; - $_POST['client_secret'] = 'test'; - $_POST['redirect_uri'] = 'http://example.com/test'; - $_POST['grant_type'] = 'authorization_code'; - $_POST['code'] = $auth_code; + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 3 + */ + public function test_checkClientAuthoriseParams_invalidResponseType() + { + $_GET['client_id'] = 'test'; + $_GET['redirect_uri'] = 'http://example.com/test'; + $_GET['response_type'] = 'blah'; + $_GET['scope'] = 'blah'; - $result = $this->oauth->issueAccessToken(); + $this->oauth->checkClientAuthoriseParams(); + } - $this->assertCount(3, $result); - $this->assertArrayHasKey('access_token', $result); - $this->assertArrayHasKey('token_type', $result); - $this->assertArrayHasKey('expires_in', $result); - } + public function test_newAuthoriseRequest() + { + $result = $this->oauth->newAuthoriseRequest('user', '123', array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'scopes' => array(array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + )) + )); - function test_issueAccessToken_PassedParams() - { - $auth_code = $this->oauth->newAuthoriseRequest('user', '123', array( - 'client_id' => 'test', - 'redirect_uri' => 'http://example.com/test', - 'scopes' => array(array( - 'id' => 1, - 'scope' => 'test', - 'name' => 'test', - 'description' => 'test' - )) - )); + $this->assertEquals(40, strlen($result)); + } - $params['client_id'] = 'test'; - $params['client_secret'] = 'test'; - $params['redirect_uri'] = 'http://example.com/test'; - $params['grant_type'] = 'authorization_code'; - $params['code'] = $auth_code; + public function test_newAuthoriseRequest_isUnique() + { + $result1 = $this->oauth->newAuthoriseRequest('user', '123', array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'scopes' => array(array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + )) + )); - $result = $this->oauth->issueAccessToken($params); + $result2 = $this->oauth->newAuthoriseRequest('user', '123', array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'scopes' => array(array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + )) + )); - $this->assertCount(3, $result); - $this->assertArrayHasKey('access_token', $result); - $this->assertArrayHasKey('token_type', $result); - $this->assertArrayHasKey('expires_in', $result); - } + $this->assertNotEquals($result1, $result2); + } - /** - * @expectedException Oauth2\Authentication\ClientException - * @expectedExceptionCode 0 - */ - function test_issueAccessToken_missingGrantType() - { - $this->oauth->issueAccessToken(); - } + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 7 + */ + public function test_issueAccessTokenNoRegisteredGrant() + { + $auth_code = $this->oauth->newAuthoriseRequest('user', '123', array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'scopes' => array(array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + )) + )); - /** - * @expectedException Oauth2\Authentication\ClientException - * @expectedExceptionCode 7 - */ - function test_issueAccessToken_unsupportedGrantType() - { - $params['grant_type'] = 'blah'; + $_POST['client_id'] = 'test'; + $_POST['client_secret'] = 'test'; + $_POST['redirect_uri'] = 'http://example.com/test'; + $_POST['grant_type'] = 'authorization_code'; + $_POST['code'] = $auth_code; - $this->oauth->issueAccessToken($params); - } + $result = $this->oauth->issueAccessToken(); + } - /** - * @expectedException Oauth2\Authentication\ClientException - * @expectedExceptionCode 0 - */ - function test_completeAuthCodeGrant_missingClientId() - { - $reflector = new ReflectionClass($this->oauth); - $method = $reflector->getMethod('completeAuthCodeGrant'); - $method->setAccessible(true); + public function test_issueAccessToken_POST_authorization_code() + { + $auth_code = $this->oauth->newAuthoriseRequest('user', '123', array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'scopes' => array(array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + )) + )); - $method->invoke($this->oauth); - } + $_POST['client_id'] = 'test'; + $_POST['client_secret'] = 'test'; + $_POST['redirect_uri'] = 'http://example.com/test'; + $_POST['grant_type'] = 'authorization_code'; + $_POST['code'] = $auth_code; - /** - * @expectedException Oauth2\Authentication\ClientException - * @expectedExceptionCode 0 - */ - function test_completeAuthCodeGrant_missingClientSecret() - { - $reflector = new ReflectionClass($this->oauth); - $method = $reflector->getMethod('completeAuthCodeGrant'); - $method->setAccessible(true); + $this->oauth->enableGrantType('authorization_code'); + $result = $this->oauth->issueAccessToken(); - $authParams['client_id'] = 'test'; + $this->assertCount(4, $result); + $this->assertArrayHasKey('access_token', $result); + $this->assertArrayHasKey('token_type', $result); + $this->assertArrayHasKey('expires_in', $result); + $this->assertArrayHasKey('expires', $result); + } - $method->invoke($this->oauth, $authParams); - } + public function test_issueAccessToken_PassedParams_authorization_code() + { + $auth_code = $this->oauth->newAuthoriseRequest('user', '123', array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'scopes' => array(array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + )) + )); - /** - * @expectedException Oauth2\Authentication\ClientException - * @expectedExceptionCode 0 - */ - function test_completeAuthCodeGrant_missingRedirectUri() - { - $reflector = new ReflectionClass($this->oauth); - $method = $reflector->getMethod('completeAuthCodeGrant'); - $method->setAccessible(true); + $params['client_id'] = 'test'; + $params['client_secret'] = 'test'; + $params['redirect_uri'] = 'http://example.com/test'; + $params['grant_type'] = 'authorization_code'; + $params['code'] = $auth_code; - $authParams['client_id'] = 'test'; - $authParams['client_secret'] = 'test'; + $this->oauth->enableGrantType('authorization_code'); + $result = $this->oauth->issueAccessToken($params); - $method->invoke($this->oauth, $authParams); - } + $this->assertCount(4, $result); + $this->assertArrayHasKey('access_token', $result); + $this->assertArrayHasKey('token_type', $result); + $this->assertArrayHasKey('expires_in', $result); + $this->assertArrayHasKey('expires', $result); + } - /** - * @expectedException Oauth2\Authentication\ClientException - * @expectedExceptionCode 8 - */ - function test_completeAuthCodeGrant_invalidClient() - { - $reflector = new ReflectionClass($this->oauth); - $method = $reflector->getMethod('completeAuthCodeGrant'); - $method->setAccessible(true); + public function test_issueAccessToken_refresh_token() + { + $this->oauth->enableGrantType('authorization_code'); + $this->oauth->enableGrantType('refresh_token'); - $authParams['client_id'] = 'test'; - $authParams['client_secret'] = 'test123'; - $authParams['redirect_uri'] = 'http://example.com/test'; + $auth_code = $this->oauth->newAuthoriseRequest('user', '123', array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'scopes' => array(array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + )) + )); - $method->invoke($this->oauth, $authParams); - } + $params['client_id'] = 'test'; + $params['client_secret'] = 'test'; + $params['redirect_uri'] = 'http://example.com/test'; + $params['grant_type'] = 'authorization_code'; + $params['code'] = $auth_code; - /** - * @expectedException Oauth2\Authentication\ClientException - * @expectedExceptionCode 0 - */ - function test_completeAuthCodeGrant_missingCode() - { - $reflector = new ReflectionClass($this->oauth); - $method = $reflector->getMethod('completeAuthCodeGrant'); - $method->setAccessible(true); + $result = $this->oauth->issueAccessToken($params); - $authParams['client_id'] = 'test'; - $authParams['client_secret'] = 'test'; - $authParams['redirect_uri'] = 'http://example.com/test'; + $this->assertCount(5, $result); + $this->assertArrayHasKey('access_token', $result); + $this->assertArrayHasKey('token_type', $result); + $this->assertArrayHasKey('expires_in', $result); + $this->assertArrayHasKey('expires', $result); + $this->assertArrayHasKey('refresh_token', $result); - $method->invoke($this->oauth, $authParams); - } + // Wait for a few seconds for the access token to age + sleep(1); - /** - * @expectedException Oauth2\Authentication\ClientException - * @expectedExceptionCode 9 - */ - function test_completeAuthCodeGrant_invalidCode() - { - $reflector = new ReflectionClass($this->oauth); - $method = $reflector->getMethod('completeAuthCodeGrant'); - $method->setAccessible(true); + // Refresh the token + $params2['client_id'] = 'test'; + $params2['client_secret'] = 'test'; + $params2['redirect_uri'] = 'http://example.com/test'; + $params2['grant_type'] = 'refresh_token'; + $params2['refresh_token'] = $result['refresh_token']; - $authParams['client_id'] = 'test'; - $authParams['client_secret'] = 'test'; - $authParams['redirect_uri'] = 'http://example.com/test'; - $authParams['code'] = 'blah'; + $result2 = $this->oauth->issueAccessToken($params2); - $method->invoke($this->oauth, $authParams); - } + $this->assertCount(5, $result2); + $this->assertArrayHasKey('access_token', $result2); + $this->assertArrayHasKey('token_type', $result2); + $this->assertArrayHasKey('expires_in', $result2); + $this->assertArrayHasKey('expires', $result2); + $this->assertArrayHasKey('refresh_token', $result2); - /** - * @expectedException Oauth2\Authentication\ServerException - * @expectedExceptionMessage No registered database abstractor - */ - function test_noRegisteredDatabaseAbstractor() - { - $reflector = new ReflectionClass($this->oauth); - $method = $reflector->getMethod('_dbCall'); - $method->setAccessible(true); + $this->assertNotEquals($result['access_token'], $result2['access_token']); + $this->assertNotEquals($result['refresh_token'], $result2['refresh_token']); + $this->assertNotEquals($result['expires'], $result2['expires']); + $this->assertEquals($result['expires_in'], $result2['expires_in']); + $this->assertEquals($result['token_type'], $result2['token_type']); + } - $dbAbstractor = $reflector->getProperty('_db'); - $dbAbstractor->setAccessible(true); - $dbAbstractor->setValue($this->oauth, null); + public function test_issueAccessToken_client_credentials() + { + $this->oauth->enableGrantType('client_credentials'); - $result = $method->invoke($this->oauth); - } + $auth_code = $this->oauth->newAuthoriseRequest('user', '123', array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'scopes' => array(array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + )) + )); - /** - * @expectedException Oauth2\Authentication\ServerException - * @expectedExceptionMessage Registered database abstractor is not an instance of Oauth2\Authentication\Database - */ - function test_invalidRegisteredDatabaseAbstractor() - { - $fake = new stdClass; - $this->oauth->registerDbAbstractor($fake); + $params['client_id'] = 'test'; + $params['client_secret'] = 'test'; + $params['redirect_uri'] = 'http://example.com/test'; + $params['grant_type'] = 'client_credentials'; + $params['code'] = $auth_code; - $reflector = new ReflectionClass($this->oauth); - $method = $reflector->getMethod('_dbCall'); - $method->setAccessible(true); + $result = $this->oauth->issueAccessToken($params); - $result = $method->invoke($this->oauth); - } + $this->assertCount(4, $result); + $this->assertArrayHasKey('access_token', $result); + $this->assertArrayHasKey('token_type', $result); + $this->assertArrayHasKey('expires_in', $result); + $this->assertArrayHasKey('expires', $result); + } -} \ No newline at end of file + public function test_issueAccessToken_client_credentialsPOST() + { + $this->oauth->enableGrantType('client_credentials'); + + $auth_code = $this->oauth->newAuthoriseRequest('user', '123', array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'scopes' => array(array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + )) + )); + + $_POST['client_id'] = 'test'; + $_POST['client_secret'] = 'test'; + $_POST['redirect_uri'] = 'http://example.com/test'; + $_POST['grant_type'] = 'client_credentials'; + $_POST['code'] = $auth_code; + + $result = $this->oauth->issueAccessToken(); + + $this->assertCount(4, $result); + $this->assertArrayHasKey('access_token', $result); + $this->assertArrayHasKey('token_type', $result); + $this->assertArrayHasKey('expires_in', $result); + $this->assertArrayHasKey('expires', $result); + } + + public function test_issueAccessToken_client_credentials_withRefreshToken() + { + $this->oauth->enableGrantType('client_credentials'); + $this->oauth->enableGrantType('refresh_token'); + + $auth_code = $this->oauth->newAuthoriseRequest('user', '123', array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'scopes' => array(array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + )) + )); + + $params['client_id'] = 'test'; + $params['client_secret'] = 'test'; + $params['redirect_uri'] = 'http://example.com/test'; + $params['grant_type'] = 'client_credentials'; + $params['code'] = $auth_code; + + $result = $this->oauth->issueAccessToken($params); + + $this->assertCount(5, $result); + $this->assertArrayHasKey('access_token', $result); + $this->assertArrayHasKey('token_type', $result); + $this->assertArrayHasKey('expires_in', $result); + $this->assertArrayHasKey('expires', $result); + $this->assertArrayHasKey('refresh_token', $result); + } + + public function test_issueAccessToken_refresh_tokenPOST() + { + $this->oauth->enableGrantType('authorization_code'); + $this->oauth->enableGrantType('refresh_token'); + + $auth_code = $this->oauth->newAuthoriseRequest('user', '123', array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'scopes' => array(array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + )) + )); + + $_POST['client_id'] = 'test'; + $_POST['client_secret'] = 'test'; + $_POST['redirect_uri'] = 'http://example.com/test'; + $_POST['grant_type'] = 'authorization_code'; + $_POST['code'] = $auth_code; + + $result = $this->oauth->issueAccessToken(); + + $this->assertCount(5, $result); + $this->assertArrayHasKey('access_token', $result); + $this->assertArrayHasKey('token_type', $result); + $this->assertArrayHasKey('expires_in', $result); + $this->assertArrayHasKey('expires', $result); + $this->assertArrayHasKey('refresh_token', $result); + + // Wait for a few seconds for the access token to age + sleep(1); + + // Refresh the token + $_POST['client_id'] = 'test'; + $_POST['client_secret'] = 'test'; + $_POST['redirect_uri'] = 'http://example.com/test'; + $_POST['grant_type'] = 'refresh_token'; + $_POST['refresh_token'] = $result['refresh_token']; + + $result2 = $this->oauth->issueAccessToken(); + + $this->assertCount(5, $result2); + $this->assertArrayHasKey('access_token', $result2); + $this->assertArrayHasKey('token_type', $result2); + $this->assertArrayHasKey('expires_in', $result2); + $this->assertArrayHasKey('expires', $result2); + $this->assertArrayHasKey('refresh_token', $result2); + + $this->assertNotEquals($result['access_token'], $result2['access_token']); + $this->assertNotEquals($result['refresh_token'], $result2['refresh_token']); + $this->assertNotEquals($result['expires'], $result2['expires']); + $this->assertEquals($result['expires_in'], $result2['expires_in']); + $this->assertEquals($result['token_type'], $result2['token_type']); + } + + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 0 + */ + public function test_issueAccessToken_refresh_tokenMissingToken() + { + $this->oauth->enableGrantType('authorization_code'); + $this->oauth->enableGrantType('refresh_token'); + + $auth_code = $this->oauth->newAuthoriseRequest('user', '123', array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'scopes' => array(array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + )) + )); + + $_POST['client_id'] = 'test'; + $_POST['client_secret'] = 'test'; + $_POST['redirect_uri'] = 'http://example.com/test'; + $_POST['grant_type'] = 'authorization_code'; + $_POST['code'] = $auth_code; + + $result = $this->oauth->issueAccessToken(); + + $this->assertCount(5, $result); + $this->assertArrayHasKey('access_token', $result); + $this->assertArrayHasKey('token_type', $result); + $this->assertArrayHasKey('expires_in', $result); + $this->assertArrayHasKey('expires', $result); + $this->assertArrayHasKey('refresh_token', $result); + + // Wait for a few seconds for the access token to age + sleep(1); + + // Refresh the token + $_POST['client_id'] = 'test'; + $_POST['client_secret'] = 'test'; + $_POST['redirect_uri'] = 'http://example.com/test'; + $_POST['grant_type'] = 'refresh_token'; + + $result2 = $this->oauth->issueAccessToken(); + } + + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 0 + */ + public function test_issueAccessToken_invalid_refresh_token() + { + $this->oauth->enableGrantType('authorization_code'); + $this->oauth->enableGrantType('refresh_token'); + + $auth_code = $this->oauth->newAuthoriseRequest('user', '123', array( + 'client_id' => 'test', + 'redirect_uri' => 'http://example.com/test', + 'scopes' => array(array( + 'id' => 1, + 'scope' => 'test', + 'name' => 'test', + 'description' => 'test' + )) + )); + + $params['client_id'] = 'test'; + $params['client_secret'] = 'test'; + $params['redirect_uri'] = 'http://example.com/test'; + $params['grant_type'] = 'authorization_code'; + $params['code'] = $auth_code; + + $result = $this->oauth->issueAccessToken($params); + + $this->assertCount(5, $result); + $this->assertArrayHasKey('access_token', $result); + $this->assertArrayHasKey('token_type', $result); + $this->assertArrayHasKey('expires_in', $result); + $this->assertArrayHasKey('expires', $result); + $this->assertArrayHasKey('refresh_token', $result); + + // Wait for a few seconds for the access token to age + sleep(1); + + // Refresh the token + $params2['client_id'] = 'test'; + $params2['client_secret'] = 'test'; + $params2['redirect_uri'] = 'http://example.com/test'; + $params2['grant_type'] = 'refresh_token'; + $params2['refresh_token'] = 'blah'; + + $result2 = $this->oauth->issueAccessToken($params2); + } + + /** + * @expectedException Oauth2\Authentication\ServerException + * @expectedExceptionCode 0 + */ + public function test_issueAccessToken_password_grant_Missing_Callback() + { + $this->oauth->enableGrantType('password'); + } + + public function test_issueAccessToken_password_grant() + { + $this->oauth->enableGrantType('password', function(){ + return true; + }); + + $params['client_id'] = 'test'; + $params['client_secret'] = 'test'; + $params['grant_type'] = 'password'; + $params['username'] = 'alexbilbie'; + $params['password'] = 'helloworld'; + + $result = $this->oauth->issueAccessToken($params); + + $this->assertCount(4, $result); + $this->assertArrayHasKey('access_token', $result); + $this->assertArrayHasKey('token_type', $result); + $this->assertArrayHasKey('expires_in', $result); + $this->assertArrayHasKey('expires', $result); + } + + public function test_issueAccessToken_password_grantPOST() + { + $this->oauth->enableGrantType('password', function(){ + return true; + }); + + $_POST['client_id'] = 'test'; + $_POST['client_secret'] = 'test'; + $_POST['grant_type'] = 'password'; + $_POST['username'] = 'alexbilbie'; + $_POST['password'] = 'helloworld'; + + $result = $this->oauth->issueAccessToken(); + + $this->assertCount(4, $result); + $this->assertArrayHasKey('access_token', $result); + $this->assertArrayHasKey('token_type', $result); + $this->assertArrayHasKey('expires_in', $result); + $this->assertArrayHasKey('expires', $result); + } + + public function test_issueAccessToken_password_grant_withRefreshToken() + { + $this->oauth->enableGrantType('password', function(){ + return true; + }); + + $this->oauth->enableGrantType('refresh_token'); + + $params['client_id'] = 'test'; + $params['client_secret'] = 'test'; + $params['grant_type'] = 'password'; + $params['username'] = 'alexbilbie'; + $params['password'] = 'helloworld'; + + $result = $this->oauth->issueAccessToken($params); + + $this->assertCount(5, $result); + $this->assertArrayHasKey('access_token', $result); + $this->assertArrayHasKey('token_type', $result); + $this->assertArrayHasKey('expires_in', $result); + $this->assertArrayHasKey('expires', $result); + $this->assertArrayHasKey('refresh_token', $result); + } + + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 0 + */ + public function test_issueAccessToken_password_grant_wrongCreds() + { + $this->oauth->enableGrantType('password', function(){ + return false; + }); + + $params['client_id'] = 'test'; + $params['client_secret'] = 'test'; + $params['grant_type'] = 'password'; + $params['username'] = 'alexbilbie'; + $params['password'] = 'helloworld'; + + $result = $this->oauth->issueAccessToken($params); + } + + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 0 + */ + public function test_issueAccessToken_password_grant_missingUsername() + { + $this->oauth->enableGrantType('password', function(){ + return true; + }); + + $params['client_id'] = 'test'; + $params['client_secret'] = 'test'; + $params['grant_type'] = 'password'; + + $result = $this->oauth->issueAccessToken($params); + } + + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 0 + */ + public function test_issueAccessToken_password_grant_missingPassword() + { + $this->oauth->enableGrantType('password', function(){ + return true; + }); + + $params['client_id'] = 'test'; + $params['client_secret'] = 'test'; + $params['grant_type'] = 'password'; + $params['username'] = 'alexbilbie'; + + $result = $this->oauth->issueAccessToken($params); + } + + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 0 + */ + public function test_issueAccessToken_missingGrantType() + { + $this->oauth->issueAccessToken(); + } + + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 7 + */ + public function test_issueAccessToken_unsupportedGrantType() + { + $params['grant_type'] = 'blah'; + + $this->oauth->issueAccessToken($params); + } + + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 0 + */ + public function test_completeAuthCodeGrant_missingClientId() + { + $reflector = new ReflectionClass($this->oauth); + $method = $reflector->getMethod('_completeAuthCodeGrant'); + $method->setAccessible(true); + + $method->invoke($this->oauth); + } + + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 0 + */ + public function test_completeAuthCodeGrant_missingClientSecret() + { + $reflector = new ReflectionClass($this->oauth); + $method = $reflector->getMethod('_completeAuthCodeGrant'); + $method->setAccessible(true); + + $authParams['client_id'] = 'test'; + + $method->invoke($this->oauth, $authParams); + } + + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 0 + */ + public function test_completeAuthCodeGrant_missingRedirectUri() + { + $reflector = new ReflectionClass($this->oauth); + $method = $reflector->getMethod('_completeAuthCodeGrant'); + $method->setAccessible(true); + + $authParams['client_id'] = 'test'; + $authParams['client_secret'] = 'test'; + + $method->invoke($this->oauth, $authParams); + } + + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 8 + */ + public function test_completeAuthCodeGrant_invalidClient() + { + $reflector = new ReflectionClass($this->oauth); + $method = $reflector->getMethod('_completeAuthCodeGrant'); + $method->setAccessible(true); + + $authParams['client_id'] = 'test'; + $authParams['client_secret'] = 'test123'; + $authParams['redirect_uri'] = 'http://example.com/test'; + + $method->invoke($this->oauth, $authParams); + } + + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 0 + */ + public function test_completeAuthCodeGrant_missingCode() + { + $reflector = new ReflectionClass($this->oauth); + $method = $reflector->getMethod('_completeAuthCodeGrant'); + $method->setAccessible(true); + + $authParams['client_id'] = 'test'; + $authParams['client_secret'] = 'test'; + $authParams['redirect_uri'] = 'http://example.com/test'; + + $method->invoke($this->oauth, $authParams); + } + + /** + * @expectedException Oauth2\Authentication\ClientException + * @expectedExceptionCode 9 + */ + public function test_completeAuthCodeGrant_invalidCode() + { + $reflector = new ReflectionClass($this->oauth); + $method = $reflector->getMethod('_completeAuthCodeGrant'); + $method->setAccessible(true); + + $authParams['client_id'] = 'test'; + $authParams['client_secret'] = 'test'; + $authParams['redirect_uri'] = 'http://example.com/test'; + $authParams['code'] = 'blah'; + + $method->invoke($this->oauth, $authParams); + } + + /** + * @expectedException Oauth2\Authentication\ServerException + * @expectedExceptionMessage No registered database abstractor + */ + public function test_noRegisteredDatabaseAbstractor() + { + $reflector = new ReflectionClass($this->oauth); + $method = $reflector->getMethod('_dbCall'); + $method->setAccessible(true); + + $dbAbstractor = $reflector->getProperty('_db'); + $dbAbstractor->setAccessible(true); + $dbAbstractor->setValue($this->oauth, null); + + $result = $method->invoke($this->oauth); + } + + /** + * @expectedException Oauth2\Authentication\ServerException + * @expectedExceptionMessage Registered database abstractor is not an instance of Oauth2\Authentication\Database + */ + public function test_invalidRegisteredDatabaseAbstractor() + { + $fake = new stdClass; + $this->oauth->registerDbAbstractor($fake); + + $reflector = new ReflectionClass($this->oauth); + $method = $reflector->getMethod('_dbCall'); + $method->setAccessible(true); + + $result = $method->invoke($this->oauth); + } + +} diff --git a/tests/resource/server_test.php b/tests/resource/server_test.php index 7feb4389..707d73ee 100644 --- a/tests/resource/server_test.php +++ b/tests/resource/server_test.php @@ -2,120 +2,123 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase { - function setUp() - { - require_once('database_mock.php'); - $this->server = new Oauth2\Resource\Server(); - $this->db = new ResourceDB(); + function setUp() + { + require_once 'src/OAuth2/Resource/Server.php'; + require_once 'src/OAuth2/Resource/Database.php'; - $this->assertInstanceOf('Oauth2\Resource\Database', $this->db); - $this->server->registerDbAbstractor($this->db); - } + require_once('database_mock.php'); + $this->server = new Oauth2\Resource\Server(); + $this->db = new ResourceDB(); - function test_init_POST() - { - $_SERVER['REQUEST_METHOD'] = 'POST'; - $_POST['oauth_token'] = 'test12345'; + $this->assertInstanceOf('Oauth2\Resource\Database', $this->db); + $this->server->registerDbAbstractor($this->db); + } - $this->server->init(); + function test_init_POST() + { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST['oauth_token'] = 'test12345'; - $reflector = new ReflectionClass($this->server); + $this->server->init(); - $_accessToken = $reflector->getProperty('_accessToken'); - $_accessToken->setAccessible(true); + $reflector = new ReflectionClass($this->server); - $_type = $reflector->getProperty('_type'); - $_type->setAccessible(true); + $_accessToken = $reflector->getProperty('_accessToken'); + $_accessToken->setAccessible(true); - $_typeId = $reflector->getProperty('_typeId'); - $_typeId->setAccessible(true); + $_type = $reflector->getProperty('_type'); + $_type->setAccessible(true); - $_scopes = $reflector->getProperty('_scopes'); - $_scopes->setAccessible(true); + $_typeId = $reflector->getProperty('_typeId'); + $_typeId->setAccessible(true); - $this->assertEquals($_accessToken->getValue($this->server), $_POST['oauth_token']); - $this->assertEquals($_type->getValue($this->server), 'user'); - $this->assertEquals($_typeId->getValue($this->server), 123); - $this->assertEquals($_scopes->getValue($this->server), array('foo', 'bar')); - } + $_scopes = $reflector->getProperty('_scopes'); + $_scopes->setAccessible(true); - function test_init_GET() - { - $_GET['oauth_token'] = 'test12345'; + $this->assertEquals($_accessToken->getValue($this->server), $_POST['oauth_token']); + $this->assertEquals($_type->getValue($this->server), 'user'); + $this->assertEquals($_typeId->getValue($this->server), 123); + $this->assertEquals($_scopes->getValue($this->server), array('foo', 'bar')); + } - $this->server->init(); + function test_init_GET() + { + $_GET['oauth_token'] = 'test12345'; - $reflector = new ReflectionClass($this->server); + $this->server->init(); - $_accessToken = $reflector->getProperty('_accessToken'); - $_accessToken->setAccessible(true); + $reflector = new ReflectionClass($this->server); - $_type = $reflector->getProperty('_type'); - $_type->setAccessible(true); + $_accessToken = $reflector->getProperty('_accessToken'); + $_accessToken->setAccessible(true); - $_typeId = $reflector->getProperty('_typeId'); - $_typeId->setAccessible(true); + $_type = $reflector->getProperty('_type'); + $_type->setAccessible(true); - $_scopes = $reflector->getProperty('_scopes'); - $_scopes->setAccessible(true); + $_typeId = $reflector->getProperty('_typeId'); + $_typeId->setAccessible(true); - $this->assertEquals($_accessToken->getValue($this->server), $_GET['oauth_token']); - $this->assertEquals($_type->getValue($this->server), 'user'); - $this->assertEquals($_typeId->getValue($this->server), 123); - $this->assertEquals($_scopes->getValue($this->server), array('foo', 'bar')); - } + $_scopes = $reflector->getProperty('_scopes'); + $_scopes->setAccessible(true); - function test_init_header() - { - // Test with authorisation header - $this->markTestIncomplete('Authorisation header test has not been implemented yet.'); - } + $this->assertEquals($_accessToken->getValue($this->server), $_GET['oauth_token']); + $this->assertEquals($_type->getValue($this->server), 'user'); + $this->assertEquals($_typeId->getValue($this->server), 123); + $this->assertEquals($_scopes->getValue($this->server), array('foo', 'bar')); + } - /** - * @expectedException \Oauth2\Resource\ClientException - * @expectedExceptionMessage An access token was not presented with the request - */ - function test_init_missingToken() - { - $this->server->init(); - } + function test_init_header() + { + // Test with authorisation header + $this->markTestIncomplete('Authorisation header test has not been implemented yet.'); + } - /** - * @expectedException \Oauth2\Resource\ClientException - * @expectedExceptionMessage The access token is not registered with the resource server - */ - function test_init_wrongToken() - { - $_POST['oauth_token'] = 'blah'; - $_SERVER['REQUEST_METHOD'] = 'POST'; + /** + * @expectedException \Oauth2\Resource\ClientException + * @expectedExceptionMessage An access token was not presented with the request + */ + function test_init_missingToken() + { + $this->server->init(); + } - $this->server->init(); - } + /** + * @expectedException \Oauth2\Resource\ClientException + * @expectedExceptionMessage The access token is not registered with the resource server + */ + function test_init_wrongToken() + { + $_POST['oauth_token'] = 'blah'; + $_SERVER['REQUEST_METHOD'] = 'POST'; - function test_hasScope() - { - $_POST['oauth_token'] = 'test12345'; - $_SERVER['REQUEST_METHOD'] = 'POST'; + $this->server->init(); + } - $this->server->init(); + function test_hasScope() + { + $_POST['oauth_token'] = 'test12345'; + $_SERVER['REQUEST_METHOD'] = 'POST'; - $this->assertEquals(true, $this->server->hasScope('foo')); - $this->assertEquals(true, $this->server->hasScope('bar')); - $this->assertEquals(true, $this->server->hasScope(array('foo', 'bar'))); + $this->server->init(); - $this->assertEquals(false, $this->server->hasScope('foobar')); - $this->assertEquals(false, $this->server->hasScope(array('foobar'))); - } + $this->assertEquals(true, $this->server->hasScope('foo')); + $this->assertEquals(true, $this->server->hasScope('bar')); + $this->assertEquals(true, $this->server->hasScope(array('foo', 'bar'))); - function test___call() - { - $_POST['oauth_token'] = 'test12345'; - $_SERVER['REQUEST_METHOD'] = 'POST'; + $this->assertEquals(false, $this->server->hasScope('foobar')); + $this->assertEquals(false, $this->server->hasScope(array('foobar'))); + } - $this->server->init(); + function test___call() + { + $_POST['oauth_token'] = 'test12345'; + $_SERVER['REQUEST_METHOD'] = 'POST'; - $this->assertEquals(123, $this->server->isUser()); - $this->assertEquals(false, $this->server->isMachine()); - } + $this->server->init(); + + $this->assertEquals(123, $this->server->isUser()); + $this->assertEquals(false, $this->server->isMachine()); + } } \ No newline at end of file