From b67a804e19e90b1c1dc1a5c6c72df7b5c131afd1 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 3 Aug 2012 16:13:23 +0100 Subject: [PATCH 01/38] Removed old test/index.php --- test/index.php | 84 -------------------------------------------------- 1 file changed, 84 deletions(-) delete mode 100644 test/index.php diff --git a/test/index.php b/test/index.php deleted file mode 100644 index 0ca23ac0..00000000 --- a/test/index.php +++ /dev/null @@ -1,84 +0,0 @@ - Date: Tue, 14 Aug 2012 15:44:25 +0100 Subject: [PATCH 02/38] Initial update with some PSR-* changes --- src/Oauth2/Resource/Server.php | 206 +++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) diff --git a/src/Oauth2/Resource/Server.php b/src/Oauth2/Resource/Server.php index 15d62fa1..bd6a8984 100644 --- a/src/Oauth2/Resource/Server.php +++ b/src/Oauth2/Resource/Server.php @@ -2,7 +2,213 @@ namespace Oauth2\Resource; +class OAuthResourceServerException extends \Exception +{ + +} + class Server { + /** + * The access token. + * @access private + */ + private $_accessToken = NULL; + + /** + * The scopes the access token has access to. + * @access private + */ + private $_scopes = array(); + + /** + * The type of owner of the access token. + * @access private + */ + private $_type = NULL; + + /** + * The ID of the owner of the access token. + * @access private + */ + private $_typeId = NULL; + + /** + * Server configuration + * @var array + */ + private $config = array( + 'token_key' => 'oauth_token' + ); + + /** + * Constructor + * + * @access public + * @return void + */ + public function __construct($options = null) + { + if ($options !== null) { + $this->config = array_merge($this->config, $options); + } + } + + /** + * Magic method to test if access token represents a particular owner type + * @param [type] $method [description] + * @param [type] $arguements [description] + * @return [type] [description] + */ + public function __call($method, $arguements) + { + if (substr($method, 0, 2) === 'is') + { + if ($this->_type === strtolower(substr($method, 2))) + { + return $this->_typeId; + } + + return false; + } + } + + /** + * Register a database abstrator class + * + * @access public + * @param object $db A class that implements OAuth2ServerDatabase + * @return void + */ + public function registerDbAbstractor($db) + { + $this->db = $db; + } + /** + * Init function + * + * @access public + * @return void + */ + public function init() + { + $accessToken = null; + + // Try and get the access token via an access_token or oauth_token parameter + switch ($server['REQUEST_METHOD']) + { + case 'POST': + $accessToken = isset($_POST[$this->config['token_key']]) ? $_POST[$this->config['token_key']] : null; + break; + + default: + $accessToken = isset($_GET[$this->config['token_key']]) ? $_GET[$this->config['token_key']] : null; + break; + } + + // Try and get an access token from the auth header + $headers = getallheaders(); + if (isset($headers['Authorization'])) + { + $rawToken = trim(str_replace('Bearer', '', $headers['Authorization'])); + if ( ! empty($rawToken)) + { + $accessToken = base64_decode($rawToken); + } + } + + if ($accessToken) + { + $sessionQuery = $this->ci->db->get_where('oauth_sessions', array('access_token' => $accessToken, 'stage' => 'granted')); + + if ($session_query->num_rows() === 1) + { + $session = $session_query->row(); + $this->_accessToken = $session->access_token; + $this->_type = $session->type; + $this->_typeId = $session->type_id; + + $scopes_query = $this->ci->db->get_where('oauth_session_scopes', array('access_token' => $accessToken)); + if ($scopes_query->num_rows() > 0) + { + foreach ($scopes_query->result() as $scope) + { + $this->_scopes[] = $scope->scope; + } + } + } + + else + { + $this->ci->output->set_status_header(403); + $this->ci->output->set_output('Invalid access token'); + } + } + + else + { + $this->ci->output->set_status_header(403); + $this->ci->output->set_output('Missing access token'); + } + } + + /** + * Test if the access token has a specific scope + * + * @param mixed $scopes Scope(s) to check + * + * @access public + * @return string|bool + */ + public function hasScope($scopes) + { + if (is_string($scopes)) + { + if (in_array($scopes, $this->_scopes)) + { + return true; + } + + return false; + } + + elseif (is_array($scopes)) + { + foreach ($scopes as $scope) + { + if ( ! in_array($scope, $this->_scopes)) + { + return false; + } + } + + return true; + } + + return false; + } + + /** + * Call database methods from the abstractor + * + * @return mixed The query result + */ + private function dbcall() + { + if ($this->db === null) { + throw new OAuthResourceServerException('No registered database abstractor'); + } + + if ( ! $this->db instanceof Database) { + throw new OAuthResourceServerException('Registered database abstractor is not an instance of Oauth2\Resource\Database'); + } + + $args = func_get_args(); + $method = $args[0]; + unset($args[0]); + $params = array_values($args); + + return call_user_func_array(array($this->db, $method), $args); + } } \ No newline at end of file From 77ce18df56dc5896bad64cf26fc14fbc27e20d73 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 14 Aug 2012 15:46:58 +0100 Subject: [PATCH 03/38] Added the resource server database interface --- src/Oauth2/Resource/Database.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Oauth2/Resource/Database.php b/src/Oauth2/Resource/Database.php index c39bb471..a6ff8a2a 100644 --- a/src/Oauth2/Resource/Database.php +++ b/src/Oauth2/Resource/Database.php @@ -4,4 +4,7 @@ namespace Oauth2\Resource; interface Database { + public function validateAccessToken($accessToken); + + public function sessionScopes($sessionId); } \ No newline at end of file From e859f435a17ad6db7cb9fb8823417510f7d29a16 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 14 Aug 2012 16:28:40 +0100 Subject: [PATCH 04/38] Added docblocks for the database interface --- src/Oauth2/Resource/Database.php | 51 +++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/Oauth2/Resource/Database.php b/src/Oauth2/Resource/Database.php index a6ff8a2a..ac91bfa9 100644 --- a/src/Oauth2/Resource/Database.php +++ b/src/Oauth2/Resource/Database.php @@ -4,7 +4,56 @@ namespace Oauth2\Resource; interface Database { + /** + * Validate an access token and return the session details. + * + * Database query: + * + * + * SELECT id, owner_type, owner_id FROM oauth_sessions WHERE access_token = + * $accessToken AND stage = 'granted' AND + * access_token_expires > UNIX_TIMESTAMP(now()) + * + * + * Response: + * + * + * Array + * ( + * [id] => (int) The session ID + * [owner_type] => (string) The session owner type + * [owner_id] => (string) The session owner's ID + * ) + * + * + * @param string $accessToken The access token + * @return array|bool Return an array on success or false on failure + */ public function validateAccessToken($accessToken); - + + /** + * Returns the scopes that the session is authorised with. + * + * Database query: + * + * + * SELECT scope FROM oauth_session_scopes WHERE access_token = + * '291dca1c74900f5f252de351e0105aa3fc91b90b' + * + * + * Response: + * + * + * Array + * ( + * [0] => (string) A scope + * [1] => (string) Another scope + * ... + * ) + * + * + * @param int $sessionId The session ID + * @return array A list of scopes + */ public function sessionScopes($sessionId); } \ No newline at end of file From 519d20f0a51b09fd009d579fb54b1696bee19ae8 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 14 Aug 2012 16:34:43 +0100 Subject: [PATCH 05/38] Changed indent to spaces --- src/Oauth2/Resource/Database.php | 80 ++++++++++++++++---------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/src/Oauth2/Resource/Database.php b/src/Oauth2/Resource/Database.php index ac91bfa9..9c5d1b44 100644 --- a/src/Oauth2/Resource/Database.php +++ b/src/Oauth2/Resource/Database.php @@ -4,16 +4,16 @@ namespace Oauth2\Resource; interface Database { - /** - * Validate an access token and return the session details. - * - * Database query: - * - * - * SELECT id, owner_type, owner_id FROM oauth_sessions WHERE access_token = - * $accessToken AND stage = 'granted' AND - * access_token_expires > UNIX_TIMESTAMP(now()) - * + /** + * Validate an access token and return the session details. + * + * Database query: + * + * + * SELECT id, owner_type, owner_id FROM oauth_sessions WHERE access_token = + * $accessToken AND stage = 'granted' AND + * access_token_expires > UNIX_TIMESTAMP(now()) + * * * Response: * @@ -25,35 +25,35 @@ interface Database * [owner_id] => (string) The session owner's ID * ) * - * - * @param string $accessToken The access token - * @return array|bool Return an array on success or false on failure - */ - public function validateAccessToken($accessToken); + * + * @param string $accessToken The access token + * @return array|bool Return an array on success or false on failure + */ + public function validateAccessToken($accessToken); - /** - * Returns the scopes that the session is authorised with. - * - * Database query: - * - * - * SELECT scope FROM oauth_session_scopes WHERE access_token = - * '291dca1c74900f5f252de351e0105aa3fc91b90b' - * - * - * Response: - * - * - * Array - * ( - * [0] => (string) A scope - * [1] => (string) Another scope - * ... - * ) - * - * - * @param int $sessionId The session ID - * @return array A list of scopes - */ - public function sessionScopes($sessionId); + /** + * Returns the scopes that the session is authorised with. + * + * Database query: + * + * + * SELECT scope FROM oauth_session_scopes WHERE access_token = + * '291dca1c74900f5f252de351e0105aa3fc91b90b' + * + * + * Response: + * + * + * Array + * ( + * [0] => (string) A scope + * [1] => (string) Another scope + * ... + * ) + * + * + * @param int $sessionId The session ID + * @return array A list of scopes + */ + public function sessionScopes($sessionId); } \ No newline at end of file From ed3238b862b16e5d3b83a236581cd651530ccdd9 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 20 Aug 2012 14:19:33 +0100 Subject: [PATCH 06/38] Fixed constance letter casing --- src/Oauth2/Resource/Server.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Oauth2/Resource/Server.php b/src/Oauth2/Resource/Server.php index bd6a8984..89c2e0c6 100644 --- a/src/Oauth2/Resource/Server.php +++ b/src/Oauth2/Resource/Server.php @@ -13,7 +13,7 @@ class Server * The access token. * @access private */ - private $_accessToken = NULL; + private $_accessToken = null; /** * The scopes the access token has access to. @@ -25,13 +25,13 @@ class Server * The type of owner of the access token. * @access private */ - private $_type = NULL; + private $_type = null; /** * The ID of the owner of the access token. * @access private */ - private $_typeId = NULL; + private $_typeId = null; /** * Server configuration From 6fdb6177bcdc9cfd81a43217ebc07608f5b0010c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 20 Aug 2012 15:09:33 +0100 Subject: [PATCH 07/38] Lots of fixes --- src/Oauth2/Resource/Server.php | 100 ++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/src/Oauth2/Resource/Server.php b/src/Oauth2/Resource/Server.php index 89c2e0c6..b9c6ca42 100644 --- a/src/Oauth2/Resource/Server.php +++ b/src/Oauth2/Resource/Server.php @@ -9,6 +9,12 @@ class OAuthResourceServerException extends \Exception class Server { + /** + * Reference to the database abstractor + * @var object + */ + private $_db = null; + /** * The access token. * @access private @@ -37,10 +43,22 @@ class Server * Server configuration * @var array */ - private $config = array( + private $_config = array( 'token_key' => 'oauth_token' ); + /** + * Error codes. + * + * To provide i8ln errors just overwrite the keys + * + * @var array + */ + public $errors = array( + 'missing_access_token' => 'An access token was not presented with the request', + 'invalid_access_token' => 'The access token is not registered with the resource server' + ); + /** * Constructor * @@ -56,21 +74,22 @@ class Server /** * Magic method to test if access token represents a particular owner type - * @param [type] $method [description] - * @param [type] $arguements [description] - * @return [type] [description] + * @param string $method The method name + * @param mixed $arguements The method arguements + * @return bool If method is valid, and access token is owned by the requested party then true, */ - public function __call($method, $arguements) + public function __call($method, $arguements = null) { - if (substr($method, 0, 2) === 'is') - { - if ($this->_type === strtolower(substr($method, 2))) - { + if (substr($method, 0, 2) === 'is') { + + if ($this->_type === strtolower(substr($method, 2))) { return $this->_typeId; } return false; } + + trigger_error('Call to undefined function ' . $method . '()'); } /** @@ -82,7 +101,7 @@ class Server */ public function registerDbAbstractor($db) { - $this->db = $db; + $this->_db = $db; } /** @@ -99,18 +118,18 @@ class Server switch ($server['REQUEST_METHOD']) { case 'POST': - $accessToken = isset($_POST[$this->config['token_key']]) ? $_POST[$this->config['token_key']] : null; + $accessToken = isset($_POST[$this->_config['token_key']]) ? $_POST[$this->_config['token_key']] : null; break; default: - $accessToken = isset($_GET[$this->config['token_key']]) ? $_GET[$this->config['token_key']] : null; + $accessToken = isset($_GET[$this->_config['token_key']]) ? $_GET[$this->_config['token_key']] : null; break; } // Try and get an access token from the auth header $headers = getallheaders(); - if (isset($headers['Authorization'])) - { + if (isset($headers['Authorization'])) { + $rawToken = trim(str_replace('Bearer', '', $headers['Authorization'])); if ( ! empty($rawToken)) { @@ -118,38 +137,29 @@ class Server } } - if ($accessToken) - { - $sessionQuery = $this->ci->db->get_where('oauth_sessions', array('access_token' => $accessToken, 'stage' => 'granted')); - - if ($session_query->num_rows() === 1) + if ($accessToken) { + + $result = $this->_dbCall('validateAccessToken', array($accessToken)); + + if ($result === false) { - $session = $session_query->row(); - $this->_accessToken = $session->access_token; - $this->_type = $session->type; - $this->_typeId = $session->type_id; - - $scopes_query = $this->ci->db->get_where('oauth_session_scopes', array('access_token' => $accessToken)); - if ($scopes_query->num_rows() > 0) - { - foreach ($scopes_query->result() as $scope) - { - $this->_scopes[] = $scope->scope; - } - } + throw new OAuthResourceServerException($this->errors['invalid_access_token']); } - + else { - $this->ci->output->set_status_header(403); - $this->ci->output->set_output('Invalid access token'); + $this->_accessToken = $accessToken; + $this->_type = $result['owner_type']; + $this->_typeId = $result['owner_id']; + + // Get the scopes + $this->_scopes = $this->_dbCall('sessionScopes', array($result['id'])); } - } - - else - { - $this->ci->output->set_status_header(403); - $this->ci->output->set_output('Missing access token'); + + } else { + + throw new OAuthResourceServerException($this->errors['missing_access_token']); + } } @@ -194,13 +204,13 @@ class Server * * @return mixed The query result */ - private function dbcall() + private function _dbCall() { - if ($this->db === null) { + if ($this->_db === null) { throw new OAuthResourceServerException('No registered database abstractor'); } - if ( ! $this->db instanceof Database) { + if ( ! $this->_db instanceof Database) { throw new OAuthResourceServerException('Registered database abstractor is not an instance of Oauth2\Resource\Database'); } @@ -209,6 +219,6 @@ class Server unset($args[0]); $params = array_values($args); - return call_user_func_array(array($this->db, $method), $args); + return call_user_func_array(array($this->_db, $method), $args); } } \ No newline at end of file From 326e96cc1787a724015d3f65750d923e80af964d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 20 Aug 2012 15:49:57 +0100 Subject: [PATCH 08/38] Bug fix in dbcall --- src/Oauth2/Authentication/Server.php | 2 +- src/Oauth2/Resource/Server.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Oauth2/Authentication/Server.php b/src/Oauth2/Authentication/Server.php index 1e6ee1f5..733b51e3 100644 --- a/src/Oauth2/Authentication/Server.php +++ b/src/Oauth2/Authentication/Server.php @@ -513,6 +513,6 @@ class Server unset($args[0]); $params = array_values($args); - return call_user_func_array(array($this->db, $method), $args); + return call_user_func_array(array($this->db, $method), $params); } } diff --git a/src/Oauth2/Resource/Server.php b/src/Oauth2/Resource/Server.php index b9c6ca42..ab4626c3 100644 --- a/src/Oauth2/Resource/Server.php +++ b/src/Oauth2/Resource/Server.php @@ -219,6 +219,6 @@ class Server unset($args[0]); $params = array_values($args); - return call_user_func_array(array($this->_db, $method), $args); + return call_user_func_array(array($this->_db, $method), $params); } } \ No newline at end of file From 78424ce100dfe7c07c6d9c9951f642154ebbbce3 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 23 Aug 2012 12:21:59 +0100 Subject: [PATCH 09/38] Added resource server test suite --- build/phpunit.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build/phpunit.xml b/build/phpunit.xml index 4181c278..3a5b9f99 100644 --- a/build/phpunit.xml +++ b/build/phpunit.xml @@ -8,9 +8,12 @@ stopOnIncomplete="false" stopOnSkipped="false"> - + ../tests/authentication + + ../tests/resource + @@ -19,11 +22,8 @@ - + - + \ No newline at end of file From 66ee8df5b178b19fae1fc287463e415fec5faf78 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 23 Aug 2012 12:22:16 +0100 Subject: [PATCH 10/38] Added database mock for resource tests --- tests/resource/database_mock.php | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/resource/database_mock.php diff --git a/tests/resource/database_mock.php b/tests/resource/database_mock.php new file mode 100644 index 00000000..15f9dc28 --- /dev/null +++ b/tests/resource/database_mock.php @@ -0,0 +1,29 @@ + array( + 'id' => 1, + 'owner_type' => 'user', + 'owner_id' => 123 + )); + + private $sessionScopes = array( + 1 => array( + 'foo', + 'bar' + ) + ); + + public function validateAccessToken($accessToken) + { + return (isset($this->accessTokens[$accessToken])) ? $this->accessTokens[$accessToken] : false; + } + + public function sessionScopes($sessionId) + { + return (isset($this->sessionScopes[$sessionId])) ? $this->sessionScopes[$sessionId] : array(); + } +} \ No newline at end of file From 81a7322933001ee45d4525f301dabf5787a894c9 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 23 Aug 2012 12:22:39 +0100 Subject: [PATCH 11/38] Started resource server unit tests TODO: authentication header test --- tests/resource/server_test.php | 77 ++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 tests/resource/server_test.php diff --git a/tests/resource/server_test.php b/tests/resource/server_test.php new file mode 100644 index 00000000..1d91536e --- /dev/null +++ b/tests/resource/server_test.php @@ -0,0 +1,77 @@ +server = new Oauth2\Resource\Server(); + $this->db = new ResourceDB(); + + $this->server->registerDbAbstractor($this->db); + } + + function test_init_POST() + { + $_POST['oauth_token'] = 'test12345'; + + $this->server->init(); + + $this->assertEquals($this->server->_accessToken, $_POST['oauth_token']); + $this->assertEquals($this->server->_type, 'user'); + $this->assertEquals($this->server->_typeId, 123); + $this->assertEquals($this->server->_scopes, array('foo', 'bar')); + } + + function test_init_GET() + { + $_GET['oauth_token'] = 'test12345'; + + $this->server->init(); + + $this->assertEquals($this->server->_accessToken, $_GET['oauth_token']); + $this->assertEquals($this->server->_type, 'user'); + $this->assertEquals($this->server->_typeId, 123); + $this->assertEquals($this->server->_scopes, array('foo', 'bar')); + } + + function test_init_header() + { + // Test with authorisation header + } + + /** + * @exception OAuthResourceServerException + */ + function test_init_wrongToken() + { + $_POST['access_token'] = 'test12345'; + + $this->server->init(); + } + + function test_hasScope() + { + $_POST['oauth_token'] = 'test12345'; + + $this->server->init(); + + $this->assertEquals(true, $this->server->hasScope('foo')); + $this->assertEquals(true, $this->server->hasScope('bar')); + $this->assertEquals(true, $this->server->hasScope(array('foo', 'bar'))); + + $this->assertEquals(false, $this->server->hasScope('foobar')); + $this->assertEquals(false, $this->server->hasScope(array('foobar'))); + } + + function test___call() + { + $_POST['oauth_token'] = 'test12345'; + + $this->server->init(); + + $this->assertEquals(123, $this->server->isUser()); + $this->assertEquals(false, $this->server->isMachine()); + } + +} \ No newline at end of file From f53f6ca6097e08ae48df5ed20cad1903c8d57952 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 24 Aug 2012 12:19:31 +0100 Subject: [PATCH 12/38] Added .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..94d6d75a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +/composer.lock \ No newline at end of file From 2c3e8427027661f0c542eb589839b26bea9bdd85 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 24 Aug 2012 12:21:11 +0100 Subject: [PATCH 13/38] Updated .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 94d6d75a..de1a9ba2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /vendor/ -/composer.lock \ No newline at end of file +/composer.lock +/docs/build/ \ No newline at end of file From 829735aeebf5e08d6586f487e0da6ea46ebe3ea3 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 24 Aug 2012 12:23:04 +0100 Subject: [PATCH 14/38] Update .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index de1a9ba2..308d8954 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /vendor/ /composer.lock -/docs/build/ \ No newline at end of file +/docs/build/ +/build/logs/ \ No newline at end of file From b987c71820dd0227ee04a3caa0dd3ba91abdf932 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 24 Aug 2012 12:23:16 +0100 Subject: [PATCH 15/38] Renamed test classes --- tests/authentication/server_test.php | 2 +- tests/resource/server_test.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/authentication/server_test.php b/tests/authentication/server_test.php index b479bfb4..87842d03 100644 --- a/tests/authentication/server_test.php +++ b/tests/authentication/server_test.php @@ -1,6 +1,6 @@ Date: Fri, 24 Aug 2012 12:24:55 +0100 Subject: [PATCH 16/38] Corrected namespace --- tests/resource/database_mock.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/resource/database_mock.php b/tests/resource/database_mock.php index 15f9dc28..bf050561 100644 --- a/tests/resource/database_mock.php +++ b/tests/resource/database_mock.php @@ -1,6 +1,6 @@ Date: Fri, 24 Aug 2012 12:25:31 +0100 Subject: [PATCH 17/38] Wrapped getallheaders() method in function_exists (function isn't available on command line) --- src/Oauth2/Resource/Server.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Oauth2/Resource/Server.php b/src/Oauth2/Resource/Server.php index ab4626c3..46982a86 100644 --- a/src/Oauth2/Resource/Server.php +++ b/src/Oauth2/Resource/Server.php @@ -127,13 +127,15 @@ class Server } // Try and get an access token from the auth header - $headers = getallheaders(); - if (isset($headers['Authorization'])) { + if (function_exists('getallheaders')) { + $headers = getallheaders(); + if (isset($headers['Authorization'])) { - $rawToken = trim(str_replace('Bearer', '', $headers['Authorization'])); - if ( ! empty($rawToken)) - { - $accessToken = base64_decode($rawToken); + $rawToken = trim(str_replace('Bearer', '', $headers['Authorization'])); + if ( ! empty($rawToken)) + { + $accessToken = base64_decode($rawToken); + } } } From 9e0115732447e3b6a9232afa9015608e89081d48 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 24 Aug 2012 12:26:13 +0100 Subject: [PATCH 18/38] Updated .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 308d8954..044880fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /vendor/ /composer.lock /docs/build/ -/build/logs/ \ No newline at end of file +/build/logs/ +/build/coverage/ \ No newline at end of file From 00562858f9d3d878c14638a0ba35fc609c50f7c1 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 14:23:26 +0100 Subject: [PATCH 19/38] Excluded Composer autoload --- build/phpunit.xml | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/build/phpunit.xml b/build/phpunit.xml index 3a5b9f99..e74535da 100644 --- a/build/phpunit.xml +++ b/build/phpunit.xml @@ -1,12 +1,5 @@ - + ../tests/authentication @@ -15,15 +8,16 @@ ../tests/resource - + PEAR_INSTALL_DIR PHP_LIBDIR + ../vendor/composer - + - - - + + + \ No newline at end of file From 3e7b471e757383d9120aed0d6b9e92f1ad9ec14d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 14:23:50 +0100 Subject: [PATCH 20/38] Lots of beautiful tests --- tests/resource/server_test.php | 58 ++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/tests/resource/server_test.php b/tests/resource/server_test.php index 2414cc90..07dca58f 100644 --- a/tests/resource/server_test.php +++ b/tests/resource/server_test.php @@ -13,14 +13,29 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase { function test_init_POST() { + $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['oauth_token'] = 'test12345'; $this->server->init(); - $this->assertEquals($this->server->_accessToken, $_POST['oauth_token']); - $this->assertEquals($this->server->_type, 'user'); - $this->assertEquals($this->server->_typeId, 123); - $this->assertEquals($this->server->_scopes, array('foo', 'bar')); + $reflector = new ReflectionClass($this->server); + + $_accessToken = $reflector->getProperty('_accessToken'); + $_accessToken->setAccessible(true); + + $_type = $reflector->getProperty('_type'); + $_type->setAccessible(true); + + $_typeId = $reflector->getProperty('_typeId'); + $_typeId->setAccessible(true); + + $_scopes = $reflector->getProperty('_scopes'); + $_scopes->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')); } function test_init_GET() @@ -29,23 +44,44 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase { $this->server->init(); - $this->assertEquals($this->server->_accessToken, $_GET['oauth_token']); - $this->assertEquals($this->server->_type, 'user'); - $this->assertEquals($this->server->_typeId, 123); - $this->assertEquals($this->server->_scopes, array('foo', 'bar')); + $reflector = new ReflectionClass($this->server); + + $_accessToken = $reflector->getProperty('_accessToken'); + $_accessToken->setAccessible(true); + + $_type = $reflector->getProperty('_type'); + $_type->setAccessible(true); + + $_typeId = $reflector->getProperty('_typeId'); + $_typeId->setAccessible(true); + + $_scopes = $reflector->getProperty('_scopes'); + $_scopes->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')); } function test_init_header() { // Test with authorisation header + //$this->markTestIncomplete('Authorisation header test has not been implemented yet.'); } /** - * @exception OAuthResourceServerException + * @expectedException \Oauth2\Resource\OAuthResourceServerException */ + function test_init_missingToken() + { + $this->server->init(); + } + function test_init_wrongToken() { - $_POST['access_token'] = 'test12345'; + $_POST['oauth_token'] = 'test12345'; + $_SERVER['REQUEST_METHOD'] = 'POST'; $this->server->init(); } @@ -53,6 +89,7 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase { function test_hasScope() { $_POST['oauth_token'] = 'test12345'; + $_SERVER['REQUEST_METHOD'] = 'POST'; $this->server->init(); @@ -67,6 +104,7 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase { function test___call() { $_POST['oauth_token'] = 'test12345'; + $_SERVER['REQUEST_METHOD'] = 'POST'; $this->server->init(); From 3ab511f2f72e2518658b964091fde8cbfb252c60 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 14:24:32 +0100 Subject: [PATCH 21/38] Spacing fix --- tests/resource/database_mock.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/resource/database_mock.php b/tests/resource/database_mock.php index bf050561..52c698d8 100644 --- a/tests/resource/database_mock.php +++ b/tests/resource/database_mock.php @@ -4,11 +4,13 @@ use Oauth2\Resource\Database; class ResourceDB implements Database { - private $accessTokens = array('test12345' => array( - 'id' => 1, - 'owner_type' => 'user', - 'owner_id' => 123 - )); + private $accessTokens = array( + 'test12345' => array( + 'id' => 1, + 'owner_type' => 'user', + 'owner_id' => 123 + ) + ); private $sessionScopes = array( 1 => array( From 95931abd6b6d06c093e86e4b11c0c39322bf0cc6 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 14:24:43 +0100 Subject: [PATCH 22/38] Spelling fix --- src/Oauth2/Resource/Server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Oauth2/Resource/Server.php b/src/Oauth2/Resource/Server.php index 46982a86..f8514d94 100644 --- a/src/Oauth2/Resource/Server.php +++ b/src/Oauth2/Resource/Server.php @@ -115,7 +115,7 @@ class Server $accessToken = null; // Try and get the access token via an access_token or oauth_token parameter - switch ($server['REQUEST_METHOD']) + switch ($_SERVER['REQUEST_METHOD']) { case 'POST': $accessToken = isset($_POST[$this->_config['token_key']]) ? $_POST[$this->_config['token_key']] : null; From e191566260e12a16dc6a6a9847003bfd144d48cf Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 14:25:18 +0100 Subject: [PATCH 23/38] Fixed errors with handling database calls --- src/Oauth2/Resource/Server.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Oauth2/Resource/Server.php b/src/Oauth2/Resource/Server.php index f8514d94..41431058 100644 --- a/src/Oauth2/Resource/Server.php +++ b/src/Oauth2/Resource/Server.php @@ -141,7 +141,7 @@ class Server if ($accessToken) { - $result = $this->_dbCall('validateAccessToken', array($accessToken)); + $result = $this->_dbCall('validateAccessToken', $accessToken); if ($result === false) { @@ -155,7 +155,7 @@ class Server $this->_typeId = $result['owner_id']; // Get the scopes - $this->_scopes = $this->_dbCall('sessionScopes', array($result['id'])); + $this->_scopes = $this->_dbCall('sessionScopes', $result['id']); } } else { From 3642b8432ee1ab6b3b8cb85fa93f8bdbec7f803c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 14:25:24 +0100 Subject: [PATCH 24/38] PHPCS fixes --- src/Oauth2/Resource/Server.php | 41 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/Oauth2/Resource/Server.php b/src/Oauth2/Resource/Server.php index 41431058..0ec835a5 100644 --- a/src/Oauth2/Resource/Server.php +++ b/src/Oauth2/Resource/Server.php @@ -128,12 +128,14 @@ class Server // Try and get an access token from the auth header if (function_exists('getallheaders')) { + $headers = getallheaders(); + if (isset($headers['Authorization'])) { $rawToken = trim(str_replace('Bearer', '', $headers['Authorization'])); - if ( ! empty($rawToken)) - { + + if ( ! empty($rawToken)) { $accessToken = base64_decode($rawToken); } } @@ -143,13 +145,12 @@ class Server $result = $this->_dbCall('validateAccessToken', $accessToken); - if ($result === false) - { - throw new OAuthResourceServerException($this->errors['invalid_access_token']); - } + if ($result === false) { + + throw new OAuthResourceServerException($this->errors['invalid_access_token']); + + } else { - else - { $this->_accessToken = $accessToken; $this->_type = $result['owner_type']; $this->_typeId = $result['owner_id']; @@ -158,7 +159,7 @@ class Server $this->_scopes = $this->_dbCall('sessionScopes', $result['id']); } - } else { + } else { throw new OAuthResourceServerException($this->errors['missing_access_token']); @@ -175,24 +176,22 @@ class Server */ public function hasScope($scopes) { - if (is_string($scopes)) - { - if (in_array($scopes, $this->_scopes)) - { + if (is_string($scopes)) { + + if (in_array($scopes, $this->_scopes)) { return true; } return false; - } - - elseif (is_array($scopes)) - { - foreach ($scopes as $scope) - { - if ( ! in_array($scope, $this->_scopes)) - { + + } elseif (is_array($scopes)) { + + foreach ($scopes as $scope) { + + if ( ! in_array($scope, $this->_scopes)) { return false; } + } return true; From 337b2e0a928ad96497096261322884c745de19f1 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 14:32:06 +0100 Subject: [PATCH 25/38] Marked test_init_header as incomplete --- tests/resource/server_test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/resource/server_test.php b/tests/resource/server_test.php index 07dca58f..e66a05a6 100644 --- a/tests/resource/server_test.php +++ b/tests/resource/server_test.php @@ -67,7 +67,7 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase { function test_init_header() { // Test with authorisation header - //$this->markTestIncomplete('Authorisation header test has not been implemented yet.'); + $this->markTestIncomplete('Authorisation header test has not been implemented yet.'); } /** From 5da908841045999a152265982229683cfbb2d97a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 14:43:12 +0100 Subject: [PATCH 26/38] Assert that mock database objects are proper instances of their interfaces --- tests/authentication/server_test.php | 3 ++- tests/resource/server_test.php | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/authentication/server_test.php b/tests/authentication/server_test.php index 87842d03..211c03a1 100644 --- a/tests/authentication/server_test.php +++ b/tests/authentication/server_test.php @@ -5,9 +5,10 @@ class Authentication_Server_test extends PHPUnit_Framework_TestCase { function setUp() { $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); } diff --git a/tests/resource/server_test.php b/tests/resource/server_test.php index e66a05a6..456f686c 100644 --- a/tests/resource/server_test.php +++ b/tests/resource/server_test.php @@ -8,6 +8,7 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase { $this->server = new Oauth2\Resource\Server(); $this->db = new ResourceDB(); + $this->assertInstanceOf('Oauth2\Resource\Database', $this->db); $this->server->registerDbAbstractor($this->db); } From b7d73accdcc3dfac9605be91b615578421fd37cd Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 15:25:14 +0100 Subject: [PATCH 27/38] Removed old die statement --- src/Oauth2/Authentication/Server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Oauth2/Authentication/Server.php b/src/Oauth2/Authentication/Server.php index 733b51e3..9658cab5 100644 --- a/src/Oauth2/Authentication/Server.php +++ b/src/Oauth2/Authentication/Server.php @@ -197,7 +197,7 @@ class Server foreach ($scopes as $scope) { $scopeDetails = $this->dbcall('getScope', $scope); - //die(var_dump($scopeDetails)); + if ($scopeDetails === false) { throw new OAuthServerClientException(sprintf($this->errors['invalid_scope'], $scope), 4); From 7a4aece507ace9f7ce7a02f3e89bae35b7fe25cf Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 15:25:28 +0100 Subject: [PATCH 28/38] Stylistic fix --- src/Oauth2/Authentication/Server.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Oauth2/Authentication/Server.php b/src/Oauth2/Authentication/Server.php index 9658cab5..0c6f9476 100644 --- a/src/Oauth2/Authentication/Server.php +++ b/src/Oauth2/Authentication/Server.php @@ -413,8 +413,7 @@ class Server } // The authorization code - if ( ! isset($authParams['code']) && - ! isset($_POST['code'])) { + if ( ! isset($authParams['code']) && ! isset($_POST['code'])) { throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'code'), 0); From 7341d5ddc8b479a398f88785993affac8bedb6e4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 15:25:41 +0100 Subject: [PATCH 29/38] Moaaaare tests! --- tests/authentication/server_test.php | 236 +++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) diff --git a/tests/authentication/server_test.php b/tests/authentication/server_test.php index 211c03a1..6e79e24c 100644 --- a/tests/authentication/server_test.php +++ b/tests/authentication/server_test.php @@ -89,6 +89,66 @@ class Authentication_Server_test extends PHPUnit_Framework_TestCase { ), $this->oauth->checkClientAuthoriseParams($params)); } + /** + * @expectedException Oauth2\Authentication\OAuthServerClientException + * @expectedExceptionCode 0 + */ + function test_checkClientAuthoriseParams_missingClientId() + { + $this->oauth->checkClientAuthoriseParams(); + } + + /** + * @expectedException Oauth2\Authentication\OAuthServerClientException + * @expectedExceptionCode 0 + */ + function test_checkClientAuthoriseParams_missingRedirectUri() + { + $_GET['client_id'] = 'test'; + + $this->oauth->checkClientAuthoriseParams(); + } + + /** + * @expectedException Oauth2\Authentication\OAuthServerClientException + * @expectedExceptionCode 0 + */ + function test_checkClientAuthoriseParams_missingResponseType() + { + $_GET['client_id'] = 'test'; + $_GET['redirect_uri'] = 'http://example.com/test'; + + $this->oauth->checkClientAuthoriseParams(); + } + + /** + * @expectedException Oauth2\Authentication\OAuthServerClientException + * @expectedExceptionCode 0 + */ + function test_checkClientAuthoriseParams_missingScopes() + { + $_GET['client_id'] = 'test'; + $_GET['redirect_uri'] = 'http://example.com/test'; + $_GET['response_type'] = 'code'; + $_GET['scope'] = ' '; + + $this->oauth->checkClientAuthoriseParams(); + } + + /** + * @expectedException Oauth2\Authentication\OAuthServerClientException + * @expectedExceptionCode 4 + */ + function test_checkClientAuthoriseParams_invalidScopes() + { + $_GET['client_id'] = 'test'; + $_GET['redirect_uri'] = 'http://example.com/test'; + $_GET['response_type'] = 'code'; + $_GET['scope'] = 'blah'; + + $this->oauth->checkClientAuthoriseParams(); + } + function test_newAuthoriseRequest() { $result = $this->oauth->newAuthoriseRequest('user', '123', array( @@ -159,4 +219,180 @@ class Authentication_Server_test extends PHPUnit_Framework_TestCase { $this->assertArrayHasKey('expires_in', $result); } + 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' + )) + )); + + $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(3, $result); + $this->assertArrayHasKey('access_token', $result); + $this->assertArrayHasKey('token_type', $result); + $this->assertArrayHasKey('expires_in', $result); + } + + /** + * @expectedException Oauth2\Authentication\OAuthServerClientException + * @expectedExceptionCode 0 + */ + function test_issueAccessToken_missingGrantType() + { + $this->oauth->issueAccessToken(); + } + + /** + * @expectedException Oauth2\Authentication\OAuthServerClientException + * @expectedExceptionCode 7 + */ + function test_issueAccessToken_unsupportedGrantType() + { + $params['grant_type'] = 'blah'; + + $this->oauth->issueAccessToken($params); + } + + /** + * @expectedException Oauth2\Authentication\OAuthServerClientException + * @expectedExceptionCode 0 + */ + function test_completeAuthCodeGrant_missingClientId() + { + $reflector = new ReflectionClass($this->oauth); + $method = $reflector->getMethod('completeAuthCodeGrant'); + $method->setAccessible(true); + + $method->invoke($this->oauth); + } + + /** + * @expectedException Oauth2\Authentication\OAuthServerClientException + * @expectedExceptionCode 0 + */ + 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\OAuthServerClientException + * @expectedExceptionCode 0 + */ + 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\OAuthServerClientException + * @expectedExceptionCode 8 + */ + 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\OAuthServerClientException + * @expectedExceptionCode 0 + */ + 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\OAuthServerClientException + * @expectedExceptionCode 9 + */ + 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\OAuthServerException + * @expectedExceptionMessage No registered database abstractor + */ + 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\OAuthServerException + * @expectedExceptionMessage Registered database abstractor is not an instance of Oauth2\Authentication\Database + */ + 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); + } + } \ No newline at end of file From 8f20659f1d8eeb05640a7d690436f406b99ad6d8 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 15:25:59 +0100 Subject: [PATCH 30/38] Check for correct exception messages --- tests/resource/server_test.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/resource/server_test.php b/tests/resource/server_test.php index 456f686c..fdb35be4 100644 --- a/tests/resource/server_test.php +++ b/tests/resource/server_test.php @@ -72,16 +72,21 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase { } /** - * @expectedException \Oauth2\Resource\OAuthResourceServerException + * @expectedException \Oauth2\Resource\OAuthResourceServerException + * @expectedExceptionMessage An access token was not presented with the request */ function test_init_missingToken() { $this->server->init(); } + /** + * @expectedException \Oauth2\Resource\OAuthResourceServerException + * @expectedExceptionMessage The access token is not registered with the resource server + */ function test_init_wrongToken() { - $_POST['oauth_token'] = 'test12345'; + $_POST['oauth_token'] = 'blah'; $_SERVER['REQUEST_METHOD'] = 'POST'; $this->server->init(); From c89fe5bdf8563c688fce334d2cd177a6205a9442 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 15:43:17 +0100 Subject: [PATCH 31/38] Updated README --- README.md | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d2f4bc60..a1f48c37 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,43 @@ -# PHP OAuth server +# PHP OAuth Framework -The goal of this project is to develop a standards compliant [OAuth 2](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-v2/) server that supports a number of different authentication flows, and two extensions, [JSON web tokens](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-json-web-token/) and [SAML assertions](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-saml2-bearer/). +The goal of this project is to develop a standards compliant [OAuth 2](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-v2/) authentication server, resource server and client library with support for a major OAuth 2 providers. -The library will be a [composer](http://getcomposer.org/) package and will be framework agnostic. +## Package Installation -This code will be developed as part of the [Linkey](http://linkey.blogs.lincoln.ac.uk) project which has been funded by [JISC](http://jisc.ac.uk) under the access and identity management programme. \ No newline at end of file +The framework is provided as a Composer package which can be installed by adding the package to your composer.json file: + +```javascript +{ + "require": { + "lncd\Oauth2": "*" + } +} +``` + +## Package Integration + +Check out the [wiki](https://github.com/lncd/OAuth2/wiki) + +## Current Features + +### Authentication Server + +The authentication server is a flexible class that supports the standard authorization code grant. + +### Resource Server + +The resource server allows you to secure your API endpoints by checking for a valid OAuth access token in the request and ensuring the token has the correct permission to access resources. + + + + +## Future Goals + +### Authentication Server + +* Support for [JSON web tokens](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-json-web-token/). +* Support for [SAML assertions](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-saml2-bearer/). + +--- + +This code will be developed as part of the [Linkey](http://linkey.blogs.lincoln.ac.uk) project which has been funded by [JISC](http://jisc.ac.uk) under the Access and Identity Management programme. \ No newline at end of file From 8724a1efb07e60008a38d741358a5e2d064c5623 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 15:43:26 +0100 Subject: [PATCH 32/38] Updated composer.json with new version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index cff35e42..0ab791d7 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "lncd/Oauth2", "description": "OAuth 2.0 server - UNDER DEVELOPMENT - NOT READY FOR PRIMETIME", - "version": "0.0.1", + "version": "0.1", "homepage": "https://github.com/lncd/OAuth2", "license": "MIT", "require": { From c05880471c23d3c6c8d96b71cb5dafd5024e8d48 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 15:44:06 +0100 Subject: [PATCH 33/38] Updated composer.json --- composer.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 0ab791d7..fc8f52b0 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "lncd/Oauth2", - "description": "OAuth 2.0 server - UNDER DEVELOPMENT - NOT READY FOR PRIMETIME", + "description": "OAuth 2.0 Framework", "version": "0.1", "homepage": "https://github.com/lncd/OAuth2", "license": "MIT", @@ -19,7 +19,10 @@ "keywords": [ "oauth", "oauth2", - "server" + "server", + "authorization", + "authentication", + "resource" ], "authors": [ { From b485f15e835f20330a4e195ac75f673691b3a0e2 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 16:02:35 +0100 Subject: [PATCH 34/38] Fixed reference to renamed methods and properties --- tests/authentication/server_test.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/authentication/server_test.php b/tests/authentication/server_test.php index 6e79e24c..9d0ee045 100644 --- a/tests/authentication/server_test.php +++ b/tests/authentication/server_test.php @@ -369,10 +369,10 @@ class Authentication_Server_test extends PHPUnit_Framework_TestCase { function test_noRegisteredDatabaseAbstractor() { $reflector = new ReflectionClass($this->oauth); - $method = $reflector->getMethod('dbcall'); + $method = $reflector->getMethod('_dbCall'); $method->setAccessible(true); - $dbAbstractor = $reflector->getProperty('db'); + $dbAbstractor = $reflector->getProperty('_db'); $dbAbstractor->setAccessible(true); $dbAbstractor->setValue($this->oauth, null); @@ -389,7 +389,7 @@ class Authentication_Server_test extends PHPUnit_Framework_TestCase { $this->oauth->registerDbAbstractor($fake); $reflector = new ReflectionClass($this->oauth); - $method = $reflector->getMethod('dbcall'); + $method = $reflector->getMethod('_dbCall'); $method->setAccessible(true); $result = $method->invoke($this->oauth); From 4d4db99c06d0414f77a5b3af3489c65c66212f59 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 16:02:54 +0100 Subject: [PATCH 35/38] Underscored private variables and methods and updated references --- src/Oauth2/Authentication/Server.php | 52 ++++++++++++++-------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/Oauth2/Authentication/Server.php b/src/Oauth2/Authentication/Server.php index 0c6f9476..ef65d9f8 100644 --- a/src/Oauth2/Authentication/Server.php +++ b/src/Oauth2/Authentication/Server.php @@ -23,13 +23,13 @@ class Server * Reference to the database abstractor * @var object */ - private $db = null; + private $_db = null; /** * Server configuration * @var array */ - private $config = array( + private $_config = array( 'scope_delimeter' => ',', 'access_token_ttl' => null ); @@ -38,7 +38,7 @@ class Server * Supported response types * @var array */ - private $response_types = array( + private $_responseTypes = array( 'code' ); @@ -46,7 +46,7 @@ class Server * Supported grant types * @var array */ - private $grant_types = array( + private $_grantTypes = array( 'authorization_code' ); @@ -97,7 +97,7 @@ class Server public function __construct($options = null) { if ($options !== null) { - $this->options = array_merge($this->config, $options); + $this->options = array_merge($this->_config, $options); } } @@ -110,7 +110,7 @@ class Server */ public function registerDbAbstractor($db) { - $this->db = $db; + $this->_db = $db; } /** @@ -147,7 +147,7 @@ class Server } // Validate client ID and redirect URI - $clientDetails = $this->dbcall('validateClient', $params['client_id'], null, $params['redirect_uri']); + $clientDetails = $this->_dbCall('validateClient', $params['client_id'], null, $params['redirect_uri']); if ($clientDetails === false) { @@ -164,7 +164,7 @@ class Server $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->response_types)) { + if ( ! in_array($params['response_type'], $this->_responseTypes)) { throw new OAuthServerClientException($this->errors['unsupported_response_type'], 3); @@ -176,7 +176,7 @@ class Server $scopes = (isset($_GET['scope'])) ? $_GET['scope'] : $authParams['scope']; - $scopes = explode($this->config['scope_delimeter'], $scopes); + $scopes = explode($this->_config['scope_delimeter'], $scopes); // Remove any junk scopes for ($i = 0; $i < count($scopes); $i++) { @@ -196,7 +196,7 @@ class Server foreach ($scopes as $scope) { - $scopeDetails = $this->dbcall('getScope', $scope); + $scopeDetails = $this->_dbCall('getScope', $scope); if ($scopeDetails === false) { @@ -223,7 +223,7 @@ class Server public function newAuthoriseRequest($type, $typeId, $authoriseParams) { // Remove any old sessions the user might have - $this->dbcall('deleteSession', + $this->_dbCall('deleteSession', $authoriseParams['client_id'], $type, $typeId @@ -272,7 +272,7 @@ class Server // new authorisation code otherwise create a new session if ($accessToken !== null) { - $this->dbcall('updateSession', + $this->_dbCall('updateSession', $clientId, $type, $typeId, @@ -284,10 +284,10 @@ class Server } else { // Delete any existing sessions just to be sure - $this->dbcall('deleteSession', $clientId, $type, $typeId); + $this->_dbCall('deleteSession', $clientId, $type, $typeId); // Create a new session - $sessionId = $this->dbcall('newSession', + $sessionId = $this->_dbCall('newSession', $clientId, $redirectUri, $type, @@ -301,7 +301,7 @@ class Server // Add the scopes foreach ($scopes as $key => $scope) { - $this->dbcall('addSessionScope', $sessionId, $scope['scope']); + $this->_dbCall('addSessionScope', $sessionId, $scope['scope']); } @@ -332,7 +332,7 @@ class Server $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->grant_types)) { + if ( ! in_array($params['grant_type'], $this->_grantTypes)) { throw new OAuthServerClientException($this->errors['unsupported_grant_type'], 7); @@ -401,7 +401,7 @@ class Server } // Validate client ID and redirect URI - $clientDetails = $this->dbcall('validateClient', + $clientDetails = $this->_dbCall('validateClient', $params['client_id'], $params['client_secret'], $params['redirect_uri'] @@ -425,7 +425,7 @@ class Server // Verify the authorization code matches the client_id and the // request_uri - $session = $this->dbcall('validateAuthCode', + $session = $this->_dbCall('validateAuthCode', $params['client_id'], $params['redirect_uri'], $params['code'] @@ -442,9 +442,9 @@ class Server $accessToken = $this->generateCode(); - $accessTokenExpires = ($this->config['access_token_ttl'] === null) ? null : time() + $this->config['access_token_ttl']; + $accessTokenExpires = ($this->_config['access_token_ttl'] === null) ? null : time() + $this->_config['access_token_ttl']; - $this->dbcall('updateSession', + $this->_dbCall('updateSession', $session['id'], null, $accessToken, @@ -453,7 +453,7 @@ class Server ); // Update the session's scopes to reference the access token - $this->dbcall('updateSessionScopeAccessToken', + $this->_dbCall('updateSessionScopeAccessToken', $session['id'], $accessToken ); @@ -461,7 +461,7 @@ class Server return array( 'access_token' => $accessToken, 'token_type' => 'bearer', - 'expires_in' => $this->config['access_token_ttl'] + 'expires_in' => $this->_config['access_token_ttl'] ); } } @@ -497,13 +497,13 @@ class Server * * @return mixed The query result */ - private function dbcall() + private function _dbCall() { - if ($this->db === null) { + if ($this->_db === null) { throw new OAuthServerException('No registered database abstractor'); } - if ( ! $this->db instanceof Database) { + if ( ! $this->_db instanceof Database) { throw new OAuthServerException('Registered database abstractor is not an instance of Oauth2\Authentication\Database'); } @@ -512,6 +512,6 @@ class Server unset($args[0]); $params = array_values($args); - return call_user_func_array(array($this->db, $method), $params); + return call_user_func_array(array($this->_db, $method), $params); } } From db7eddb4ea311bee68620f94d6de1d23ec4d2b86 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 27 Aug 2012 16:05:20 +0100 Subject: [PATCH 36/38] Updated version number --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index fc8f52b0..353aa1d8 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "lncd/Oauth2", "description": "OAuth 2.0 Framework", - "version": "0.1", + "version": "0.2", "homepage": "https://github.com/lncd/OAuth2", "license": "MIT", "require": { From a1e5fdddda9f752482caa0ffb744c77f5ecd9ac0 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 28 Aug 2012 12:30:51 +0100 Subject: [PATCH 37/38] Bug fix --- src/Oauth2/Resource/Server.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Oauth2/Resource/Server.php b/src/Oauth2/Resource/Server.php index 0ec835a5..694219b0 100644 --- a/src/Oauth2/Resource/Server.php +++ b/src/Oauth2/Resource/Server.php @@ -114,6 +114,9 @@ class Server { $accessToken = null; + + $_SERVER['REQUEST_METHOD'] = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : null; + // Try and get the access token via an access_token or oauth_token parameter switch ($_SERVER['REQUEST_METHOD']) { From 88185320a8bd41514695cbdf1e6a6194cc1ca769 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Tue, 28 Aug 2012 12:30:58 +0100 Subject: [PATCH 38/38] Version bump --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 353aa1d8..28cc02b4 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "lncd/Oauth2", "description": "OAuth 2.0 Framework", - "version": "0.2", + "version": "0.2.1", "homepage": "https://github.com/lncd/OAuth2", "license": "MIT", "require": {