mirror of
https://github.com/elyby/oauth2-server.git
synced 2024-12-23 05:29:52 +05:30
Merge branch 'refs/heads/feature/resource' into develop
This commit is contained in:
commit
e8962f543d
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/vendor/
|
||||||
|
/composer.lock
|
||||||
|
/docs/build/
|
@ -8,9 +8,12 @@
|
|||||||
stopOnIncomplete="false"
|
stopOnIncomplete="false"
|
||||||
stopOnSkipped="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>
|
<filters>
|
||||||
<blacklist>
|
<blacklist>
|
||||||
@ -19,11 +22,8 @@
|
|||||||
</blacklist>
|
</blacklist>
|
||||||
</filters>
|
</filters>
|
||||||
<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"
|
|
||||||
lowUpperBound="35" highLowerBound="70"/>
|
|
||||||
<log type="coverage-clover" target="logs/clover.xml"/>
|
<log type="coverage-clover" target="logs/clover.xml"/>
|
||||||
<log type="junit" target="logs/junit.xml"
|
<log type="junit" target="logs/junit.xml" logIncompleteSkipped="false"/>
|
||||||
logIncompleteSkipped="false"/>
|
|
||||||
</logging>
|
</logging>
|
||||||
</phpunit>
|
</phpunit>
|
@ -513,6 +513,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
@ -2,7 +2,223 @@
|
|||||||
|
|
||||||
namespace Oauth2\Resource;
|
namespace Oauth2\Resource;
|
||||||
|
|
||||||
class Server
|
class OAuthResourceServerException extends \Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
|
||||||
|
$result = $this->_dbCall('validateAccessToken', array($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', array($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);
|
||||||
|
}
|
||||||
|
}
|
29
tests/resource/database_mock.php
Normal file
29
tests/resource/database_mock.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Oauth2\Resource\Server;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
77
tests/resource/server_test.php
Normal file
77
tests/resource/server_test.php
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Server_test extends PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
|
function setUp()
|
||||||
|
{
|
||||||
|
require_once('database_mock.php');
|
||||||
|
$this->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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user