Merge branch 'refs/heads/develop' into feature/clients

Conflicts:
	src/Oauth2/Authentication/Server.php
This commit is contained in:
Alex Bilbie 2012-09-04 12:09:13 +01:00
commit da329b6b37
10 changed files with 753 additions and 55 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/vendor/
/composer.lock
/docs/build/
/build/logs/
/build/coverage/

View File

@ -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. 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.

View File

@ -1,29 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<phpunit <phpunit colors="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnError="false" stopOnFailure="false" stopOnIncomplete="false" stopOnSkipped="false">
colors="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false">
<testsuites> <testsuites>
<testsuite name="Test Suite"> <testsuite name="Authentication Server">
<directory suffix="test.php">../tests/authentication</directory> <directory suffix="test.php">../tests/authentication</directory>
</testsuite> </testsuite>
<testsuite name="Resource Server">
<directory suffix="test.php">../tests/resource</directory>
</testsuite>
</testsuites> </testsuites>
<filters> <filter>
<blacklist> <blacklist>
<directory suffix=".php">PEAR_INSTALL_DIR</directory> <directory suffix=".php">PEAR_INSTALL_DIR</directory>
<directory suffix=".php">PHP_LIBDIR</directory> <directory suffix=".php">PHP_LIBDIR</directory>
<directory suffix=".php">../vendor/composer</directory>
</blacklist> </blacklist>
</filters> </filter>
<logging> <logging>
<log type="coverage-html" target="coverage" title="lncd/OAuth" <log type="coverage-html" target="coverage" title="lncd/OAuth" charset="UTF-8" yui="true" highlight="true" lowUpperBound="35" highLowerBound="70"/>
charset="UTF-8" yui="true" highlight="true" <log type="coverage-clover" target="logs/clover.xml"/>
lowUpperBound="35" highLowerBound="70"/> <log type="junit" target="logs/junit.xml" logIncompleteSkipped="false"/>
<log type="coverage-clover" target="logs/clover.xml"/>
<log type="junit" target="logs/junit.xml"
logIncompleteSkipped="false"/>
</logging> </logging>
</phpunit> </phpunit>

View File

@ -1,7 +1,7 @@
{ {
"name": "lncd/Oauth2", "name": "lncd/Oauth2",
"description": "OAuth 2.0 server - UNDER DEVELOPMENT - NOT READY FOR PRIMETIME", "description": "OAuth 2.0 Framework",
"version": "0.0.1", "version": "0.2.1",
"homepage": "https://github.com/lncd/OAuth2", "homepage": "https://github.com/lncd/OAuth2",
"license": "MIT", "license": "MIT",
"require": { "require": {
@ -19,7 +19,10 @@
"keywords": [ "keywords": [
"oauth", "oauth",
"oauth2", "oauth2",
"server" "server",
"authorization",
"authentication",
"resource"
], ],
"authors": [ "authors": [
{ {

View File

@ -23,13 +23,13 @@ class Server
* Reference to the database abstractor * Reference to the database abstractor
* @var object * @var object
*/ */
private $db = null; private $_db = null;
/** /**
* Server configuration * Server configuration
* @var array * @var array
*/ */
private $config = array( private $_config = array(
'scope_delimeter' => ',', 'scope_delimeter' => ',',
'access_token_ttl' => null 'access_token_ttl' => null
); );
@ -38,7 +38,7 @@ class Server
* Supported response types * Supported response types
* @var array * @var array
*/ */
private $response_types = array( private $_responseTypes = array(
'code' 'code'
); );
@ -46,7 +46,7 @@ class Server
* Supported grant types * Supported grant types
* @var array * @var array
*/ */
private $grant_types = array( private $_grantTypes = array(
'authorization_code' 'authorization_code'
); );
@ -97,7 +97,7 @@ class Server
public function __construct($options = null) public function __construct($options = null)
{ {
if ($options !== null) { if ($options !== null) {
$this->config = array_merge($this->config, $options); $this->options = array_merge($this->_config, $options);
} }
} }
@ -110,7 +110,7 @@ class Server
*/ */
public function registerDbAbstractor($db) public function registerDbAbstractor($db)
{ {
$this->db = $db; $this->_db = $db;
} }
/** /**
@ -147,7 +147,7 @@ class Server
} }
// Validate client ID and redirect URI // 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) { if ($clientDetails === false) {
@ -164,7 +164,7 @@ class Server
$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 // 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); throw new OAuthServerClientException($this->errors['unsupported_response_type'], 3);
@ -176,7 +176,7 @@ class Server
$scopes = (isset($_GET['scope'])) ? $_GET['scope'] : $authParams['scope']; $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 // Remove any junk scopes
for ($i = 0; $i < count($scopes); $i++) { for ($i = 0; $i < count($scopes); $i++) {
@ -196,8 +196,8 @@ class Server
foreach ($scopes as $scope) { foreach ($scopes as $scope) {
$scopeDetails = $this->dbcall('getScope', $scope); $scopeDetails = $this->_dbCall('getScope', $scope);
//die(var_dump($scopeDetails));
if ($scopeDetails === false) { if ($scopeDetails === false) {
throw new OAuthServerClientException(sprintf($this->errors['invalid_scope'], $scope), 4); throw new OAuthServerClientException(sprintf($this->errors['invalid_scope'], $scope), 4);
@ -223,7 +223,7 @@ class Server
public function newAuthoriseRequest($type, $typeId, $authoriseParams) public function newAuthoriseRequest($type, $typeId, $authoriseParams)
{ {
// Remove any old sessions the user might have // Remove any old sessions the user might have
$this->dbcall('deleteSession', $this->_dbCall('deleteSession',
$authoriseParams['client_id'], $authoriseParams['client_id'],
$type, $type,
$typeId $typeId
@ -272,7 +272,7 @@ class Server
// new authorisation code otherwise create a new session // new authorisation code otherwise create a new session
if ($accessToken !== null) { if ($accessToken !== null) {
$this->dbcall('updateSession', $this->_dbCall('updateSession',
$clientId, $clientId,
$type, $type,
$typeId, $typeId,
@ -284,10 +284,10 @@ class Server
} else { } else {
// Delete any existing sessions just to be sure // Delete any existing sessions just to be sure
$this->dbcall('deleteSession', $clientId, $type, $typeId); $this->_dbCall('deleteSession', $clientId, $type, $typeId);
// Create a new session // Create a new session
$sessionId = $this->dbcall('newSession', $sessionId = $this->_dbCall('newSession',
$clientId, $clientId,
$redirectUri, $redirectUri,
$type, $type,
@ -301,7 +301,7 @@ class Server
// Add the scopes // Add the scopes
foreach ($scopes as $key => $scope) { 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']; $params['grant_type'] = (isset($authParams['grant_type'])) ? $authParams['grant_type'] : $_POST['grant_type'];
// Ensure grant type is one that is recognised // 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); throw new OAuthServerClientException($this->errors['unsupported_grant_type'], 7);
@ -401,7 +401,7 @@ class Server
} }
// Validate client ID and redirect URI // Validate client ID and redirect URI
$clientDetails = $this->dbcall('validateClient', $clientDetails = $this->_dbCall('validateClient',
$params['client_id'], $params['client_id'],
$params['client_secret'], $params['client_secret'],
$params['redirect_uri'] $params['redirect_uri']
@ -413,8 +413,7 @@ class Server
} }
// The authorization code // The authorization code
if ( ! isset($authParams['code']) && if ( ! isset($authParams['code']) && ! isset($_POST['code'])) {
! isset($_POST['code'])) {
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'code'), 0); throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'code'), 0);
@ -426,7 +425,7 @@ class Server
// Verify the authorization code matches the client_id and the // Verify the authorization code matches the client_id and the
// request_uri // request_uri
$session = $this->dbcall('validateAuthCode', $session = $this->_dbCall('validateAuthCode',
$params['client_id'], $params['client_id'],
$params['redirect_uri'], $params['redirect_uri'],
$params['code'] $params['code']
@ -443,9 +442,9 @@ class Server
$accessToken = $this->generateCode(); $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'], $session['id'],
null, null,
$accessToken, $accessToken,
@ -454,7 +453,7 @@ class Server
); );
// Update the session's scopes to reference the access token // Update the session's scopes to reference the access token
$this->dbcall('updateSessionScopeAccessToken', $this->_dbCall('updateSessionScopeAccessToken',
$session['id'], $session['id'],
$accessToken $accessToken
); );
@ -462,7 +461,7 @@ class Server
return array( return array(
'access_token' => $accessToken, 'access_token' => $accessToken,
'token_type' => 'bearer', 'token_type' => 'bearer',
'expires_in' => $this->config['access_token_ttl'] 'expires_in' => $this->_config['access_token_ttl']
); );
} }
} }
@ -498,13 +497,13 @@ class Server
* *
* @return mixed The query result * @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'); 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'); throw new OAuthServerException('Registered database abstractor is not an instance of Oauth2\Authentication\Database');
} }
@ -513,6 +512,6 @@ class Server
unset($args[0]); unset($args[0]);
$params = array_values($args); $params = array_values($args);
return call_user_func_array(array($this->db, $method), $args); return call_user_func_array(array($this->_db, $method), $params);
} }
} }

View File

@ -4,4 +4,56 @@ namespace Oauth2\Resource;
interface Database interface Database
{ {
/**
* Validate an access token and return the session details.
*
* Database query:
*
* <code>
* SELECT id, owner_type, owner_id FROM oauth_sessions WHERE access_token =
* $accessToken AND stage = 'granted' AND
* access_token_expires > UNIX_TIMESTAMP(now())
* </code>
*
* Response:
*
* <code>
* Array
* (
* [id] => (int) The session ID
* [owner_type] => (string) The session owner type
* [owner_id] => (string) The session owner's ID
* )
* </code>
*
* @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:
*
* <code>
* SELECT scope FROM oauth_session_scopes WHERE access_token =
* '291dca1c74900f5f252de351e0105aa3fc91b90b'
* </code>
*
* Response:
*
* <code>
* Array
* (
* [0] => (string) A scope
* [1] => (string) Another scope
* ...
* )
* </code>
*
* @param int $sessionId The session ID
* @return array A list of scopes
*/
public function sessionScopes($sessionId);
} }

View File

@ -2,7 +2,227 @@
namespace Oauth2\Resource; namespace Oauth2\Resource;
class OAuthResourceServerException extends \Exception
{
}
class Server class Server
{ {
/**
* Reference to the database abstractor
* @var object
*/
private $_db = null;
/**
* 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'
);
/**
* 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
*
* @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 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 = null)
{
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 . '()');
}
/**
* 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;
$_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'])
{
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
if (function_exists('getallheaders')) {
$headers = getallheaders();
if (isset($headers['Authorization'])) {
$rawToken = trim(str_replace('Bearer', '', $headers['Authorization']));
if ( ! empty($rawToken)) {
$accessToken = base64_decode($rawToken);
}
}
}
if ($accessToken) {
$result = $this->_dbCall('validateAccessToken', $accessToken);
if ($result === false) {
throw new OAuthResourceServerException($this->errors['invalid_access_token']);
} else {
$this->_accessToken = $accessToken;
$this->_type = $result['owner_type'];
$this->_typeId = $result['owner_id'];
// Get the scopes
$this->_scopes = $this->_dbCall('sessionScopes', $result['id']);
}
} else {
throw new OAuthResourceServerException($this->errors['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), $params);
}
} }

View File

@ -1,13 +1,14 @@
<?php <?php
class Server_test extends PHPUnit_Framework_TestCase { class Authentication_Server_test extends PHPUnit_Framework_TestCase {
function setUp() function setUp()
{ {
$this->oauth = new Oauth2\Authentication\Server(); $this->oauth = new Oauth2\Authentication\Server();
require_once('database_mock.php'); require_once('database_mock.php');
$this->oauthdb = new OAuthdb(); $this->oauthdb = new OAuthdb();
$this->assertInstanceOf('Oauth2\Authentication\Database', $this->oauthdb);
$this->oauth->registerDbAbstractor($this->oauthdb); $this->oauth->registerDbAbstractor($this->oauthdb);
} }
@ -88,6 +89,66 @@ class Server_test extends PHPUnit_Framework_TestCase {
), $this->oauth->checkClientAuthoriseParams($params)); ), $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() function test_newAuthoriseRequest()
{ {
$result = $this->oauth->newAuthoriseRequest('user', '123', array( $result = $this->oauth->newAuthoriseRequest('user', '123', array(
@ -158,4 +219,180 @@ class Server_test extends PHPUnit_Framework_TestCase {
$this->assertArrayHasKey('expires_in', $result); $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);
}
} }

View File

@ -0,0 +1,31 @@
<?php
use Oauth2\Resource\Database;
class ResourceDB implements Database
{
private $accessTokens = array(
'test12345' => 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();
}
}

View File

@ -0,0 +1,121 @@
<?php
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();
$this->assertInstanceOf('Oauth2\Resource\Database', $this->db);
$this->server->registerDbAbstractor($this->db);
}
function test_init_POST()
{
$_SERVER['REQUEST_METHOD'] = 'POST';
$_POST['oauth_token'] = 'test12345';
$this->server->init();
$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()
{
$_GET['oauth_token'] = 'test12345';
$this->server->init();
$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.');
}
/**
* @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'] = 'blah';
$_SERVER['REQUEST_METHOD'] = 'POST';
$this->server->init();
}
function test_hasScope()
{
$_POST['oauth_token'] = 'test12345';
$_SERVER['REQUEST_METHOD'] = 'POST';
$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';
$_SERVER['REQUEST_METHOD'] = 'POST';
$this->server->init();
$this->assertEquals(123, $this->server->isUser());
$this->assertEquals(false, $this->server->isMachine());
}
}