mirror of
https://github.com/elyby/oauth2-server.git
synced 2024-12-16 10:18:55 +05:30
Merge branch 'release/0.1'
This commit is contained in:
commit
d7ae0f316e
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/vendor/
|
||||
/composer.lock
|
||||
/docs/build/
|
||||
/build/logs/
|
||||
/build/coverage/
|
44
README.md
44
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.
|
||||
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.
|
142
build.xml
Normal file
142
build.xml
Normal file
@ -0,0 +1,142 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="PHP OAuth 2.0 Server" default="build">
|
||||
|
||||
<target name="build" depends="prepare,lint,phploc,pdepend,phpmd-ci,phpcs-ci,phpcpd,composer,phpunit,phpdox,phpcb"/>
|
||||
|
||||
<target name="build-parallel" depends="prepare,lint,tools-parallel,phpcb"/>
|
||||
|
||||
<target name="minimal" depends="prepare,lint,phploc,pdepend,phpcpd,composer,phpunit,phpdox,phpcb" />
|
||||
|
||||
<target name="tools-parallel" description="Run tools in parallel">
|
||||
<parallel threadCount="2">
|
||||
<sequential>
|
||||
<antcall target="pdepend"/>
|
||||
<antcall target="phpmd-ci"/>
|
||||
</sequential>
|
||||
<antcall target="phpcpd"/>
|
||||
<antcall target="phpcs-ci"/>
|
||||
<antcall target="phploc"/>
|
||||
<antcall target="phpdox"/>
|
||||
</parallel>
|
||||
</target>
|
||||
|
||||
<target name="clean" description="Cleanup build artifacts">
|
||||
<delete dir="${basedir}/build/api"/>
|
||||
<delete dir="${basedir}/build/code-browser"/>
|
||||
<delete dir="${basedir}/build/coverage"/>
|
||||
<delete dir="${basedir}/build/logs"/>
|
||||
<delete dir="${basedir}/build/pdepend"/>
|
||||
</target>
|
||||
|
||||
<target name="prepare" depends="clean" description="Prepare for build">
|
||||
<mkdir dir="${basedir}/build/api"/>
|
||||
<mkdir dir="${basedir}/build/code-browser"/>
|
||||
<mkdir dir="${basedir}/build/coverage"/>
|
||||
<mkdir dir="${basedir}/build/logs"/>
|
||||
<mkdir dir="${basedir}/build/pdepend"/>
|
||||
<mkdir dir="${basedir}/build/phpdox"/>
|
||||
</target>
|
||||
|
||||
<target name="lint">
|
||||
<apply executable="php" failonerror="true">
|
||||
<arg value="-l" />
|
||||
|
||||
<fileset dir="${basedir}/src">
|
||||
<include name="**/*.php" />
|
||||
<modified />
|
||||
</fileset>
|
||||
</apply>
|
||||
</target>
|
||||
|
||||
<target name="phploc" description="Measure project size using PHPLOC">
|
||||
<exec executable="phploc">
|
||||
<arg value="--log-csv" />
|
||||
<arg value="${basedir}/build/logs/phploc.csv" />
|
||||
<arg path="${basedir}/src" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="pdepend" description="Calculate software metrics using PHP_Depend">
|
||||
<exec executable="pdepend">
|
||||
<arg value="--jdepend-xml=${basedir}/build/logs/jdepend.xml" />
|
||||
<arg value="--jdepend-chart=${basedir}/build/pdepend/dependencies.svg" />
|
||||
<arg value="--overview-pyramid=${basedir}/build/pdepend/overview-pyramid.svg" />
|
||||
<arg path="${basedir}/src" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="phpmd" description="Perform project mess detection using PHPMD and print human readable output. Intended for usage on the command line before committing.">
|
||||
<exec executable="phpmd">
|
||||
<arg path="${basedir}/src" />
|
||||
<arg value="text" />
|
||||
<arg value="${basedir}/build/phpmd.xml" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="phpmd-ci" description="Perform project mess detection using PHPMD creating a log file for the continuous integration server">
|
||||
<exec executable="phpmd">
|
||||
<arg path="${basedir}/src" />
|
||||
<arg value="xml" />
|
||||
<arg value="${basedir}/build/phpmd.xml" />
|
||||
<arg value="--reportfile" />
|
||||
<arg value="${basedir}/build/logs/pmd.xml" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="phpcs" description="Find coding standard violations using PHP_CodeSniffer and print human readable output. Intended for usage on the command line before committing.">
|
||||
<exec executable="phpcs">
|
||||
<arg value="--standard=${basedir}/build/phpcs.xml" />
|
||||
<arg value="--extensions=php" />
|
||||
<arg value="--ignore=third_party/CIUnit" />
|
||||
<arg path="${basedir}/src" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="phpcs-ci" description="Find coding standard violations using PHP_CodeSniffer creating a log file for the continuous integration server">
|
||||
<exec executable="phpcs" output="/dev/null">
|
||||
<arg value="--report=checkstyle" />
|
||||
<arg value="--report-file=${basedir}/build/logs/checkstyle.xml" />
|
||||
<arg value="--standard=${basedir}/build/phpcs.xml" />
|
||||
<arg value="--extensions=php" />
|
||||
<arg value="--ignore=third_party/CIUnit" />
|
||||
<arg path="${basedir}/src" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="phpcpd" description="Find duplicate code using PHPCPD">
|
||||
<exec executable="phpcpd">
|
||||
<arg value="--log-pmd" />
|
||||
<arg value="${basedir}/build/logs/pmd-cpd.xml" />
|
||||
<arg path="${basedir}/src" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="composer" description="Install Composer requirements">
|
||||
<exec executable="composer.phar" failonerror="true">
|
||||
<arg value="install" />
|
||||
<arg value="--dev" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="phpunit" description="Run unit tests with PHPUnit">
|
||||
<exec executable="${basedir}/vendor/bin/phpunit" failonerror="true">
|
||||
<arg value="--configuration" />
|
||||
<arg value="${basedir}/build/phpunit.xml" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="phpdox" description="Generate API documentation using phpDox">
|
||||
<exec executable="phpdox"/>
|
||||
</target>
|
||||
|
||||
<target name="phpcb" description="Aggregate tool output with PHP_CodeBrowser">
|
||||
<exec executable="phpcb">
|
||||
<arg value="--log" />
|
||||
<arg path="${basedir}/build/logs" />
|
||||
<arg value="--source" />
|
||||
<arg path="${basedir}/src" />
|
||||
<arg value="--output" />
|
||||
<arg path="${basedir}/build/code-browser" />
|
||||
</exec>
|
||||
</target>
|
||||
</project>
|
8
build/phpcs.xml
Normal file
8
build/phpcs.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="PHP_CodeSniffer">
|
||||
|
||||
<description>PHP_CodeSniffer configuration</description>
|
||||
|
||||
<rule ref="PSR2"/>
|
||||
|
||||
</ruleset>
|
14
build/phpmd.xml
Normal file
14
build/phpmd.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<ruleset name="OAuth 2.0 Server"
|
||||
xmlns="http://pmd.sf.net/ruleset/1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
|
||||
http://pmd.sf.net/ruleset_xml_schema.xsd"
|
||||
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
|
||||
|
||||
<description>
|
||||
Ruleset for OAuth 2.0 server
|
||||
</description>
|
||||
|
||||
<!-- Import the entire unused code rule set -->
|
||||
<rule ref="rulesets/unusedcode.xml" />
|
||||
</ruleset>
|
23
build/phpunit.xml
Normal file
23
build/phpunit.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit colors="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnError="false" stopOnFailure="false" stopOnIncomplete="false" stopOnSkipped="false">
|
||||
<testsuites>
|
||||
<testsuite name="Authentication Server">
|
||||
<directory suffix="test.php">../tests/authentication</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Resource Server">
|
||||
<directory suffix="test.php">../tests/resource</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<blacklist>
|
||||
<directory suffix=".php">PEAR_INSTALL_DIR</directory>
|
||||
<directory suffix=".php">PHP_LIBDIR</directory>
|
||||
<directory suffix=".php">../vendor/composer</directory>
|
||||
</blacklist>
|
||||
</filter>
|
||||
<logging>
|
||||
<log type="coverage-html" target="coverage" title="lncd/OAuth" charset="UTF-8" yui="true" highlight="true" lowUpperBound="35" highLowerBound="70"/>
|
||||
<log type="coverage-clover" target="logs/clover.xml"/>
|
||||
<log type="junit" target="logs/junit.xml" logIncompleteSkipped="false"/>
|
||||
</logging>
|
||||
</phpunit>
|
40
composer.json
Normal file
40
composer.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "lncd/Oauth2",
|
||||
"description": "OAuth 2.0 Framework",
|
||||
"version": "0.1",
|
||||
"homepage": "https://github.com/lncd/OAuth2",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"EHER/PHPUnit": "*"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/lncd/OAuth2"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"oauth",
|
||||
"oauth2",
|
||||
"server",
|
||||
"authorization",
|
||||
"authentication",
|
||||
"resource"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Alex Bilbie",
|
||||
"email": "oauth2server@alexbilbie.com",
|
||||
"homepage": "http://www.httpster.org",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Oauth2": "src/"
|
||||
}
|
||||
}
|
||||
}
|
20
license.txt
Normal file
20
license.txt
Normal file
@ -0,0 +1,20 @@
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2012 University of Lincoln
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
320
src/Oauth2/Authentication/Database.php
Normal file
320
src/Oauth2/Authentication/Database.php
Normal file
@ -0,0 +1,320 @@
|
||||
<?php
|
||||
|
||||
namespace Oauth2\Authentication;
|
||||
|
||||
interface Database
|
||||
{
|
||||
/**
|
||||
* Validate a client
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* # Client ID + redirect URI
|
||||
* SELECT clients.id FROM clients LEFT JOIN client_endpoints ON
|
||||
* client_endpoints.client_id = clients.id WHERE clients.id = $clientId AND
|
||||
* client_endpoints.redirect_uri = $redirectUri
|
||||
*
|
||||
* # Client ID + client secret
|
||||
* SELECT clients.id FROM clients WHERE clients.id = $clientId AND
|
||||
* clients.secret = $clientSecret
|
||||
*
|
||||
* # Client ID + client secret + redirect URI
|
||||
* SELECT clients.id FROM clients LEFT JOIN client_endpoints ON
|
||||
* client_endpoints.client_id = clients.id WHERE clients.id = $clientId AND
|
||||
* clients.secret = $clientSecret AND client_endpoints.redirect_uri =
|
||||
* $redirectUri
|
||||
* </code>
|
||||
*
|
||||
* @param string $clientId The client's ID
|
||||
* @param string $clientSecret The client's secret (default = "null")
|
||||
* @param string $redirectUri The client's redirect URI (default = "null")
|
||||
* @return [type] [description]
|
||||
*/
|
||||
public function validateClient(
|
||||
$clientId,
|
||||
$clientSecret = null,
|
||||
$redirectUri = null
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a new OAuth session
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO oauth_sessions (client_id, redirect_uri, owner_type,
|
||||
* owner_id, auth_code, access_token, stage, first_requested, last_updated)
|
||||
* VALUES ($clientId, $redirectUri, $type, $typeId, $authCode,
|
||||
* $accessToken, $stage, UNIX_TIMESTAMP(NOW()), UNIX_TIMESTAMP(NOW()))
|
||||
* </code>
|
||||
*
|
||||
* @param string $clientId The client ID
|
||||
* @param string $redirectUri The redirect URI
|
||||
* @param string $type The session owner's type (default = "user")
|
||||
* @param string $typeId The session owner's ID (default = "null")
|
||||
* @param string $authCode The authorisation code (default = "null")
|
||||
* @param string $accessToken The access token (default = "null")
|
||||
* @param string $stage The stage of the session (default ="request")
|
||||
* @return [type] [description]
|
||||
*/
|
||||
public function newSession(
|
||||
$clientId,
|
||||
$redirectUri,
|
||||
$type = 'user',
|
||||
$typeId = null,
|
||||
$authCode = null,
|
||||
$accessToken = null,
|
||||
$accessTokenExpire = null,
|
||||
$stage = 'requested'
|
||||
);
|
||||
|
||||
/**
|
||||
* Update an OAuth session
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* UPDATE oauth_sessions SET auth_code = $authCode, access_token =
|
||||
* $accessToken, stage = $stage, last_updated = UNIX_TIMESTAMP(NOW()) WHERE
|
||||
* id = $sessionId
|
||||
* </code>
|
||||
*
|
||||
* @param string $sessionId The session ID
|
||||
* @param string $authCode The authorisation code (default = "null")
|
||||
* @param string $accessToken The access token (default = "null")
|
||||
* @param string $stage The stage of the session (default ="request")
|
||||
* @return void
|
||||
*/
|
||||
public function updateSession(
|
||||
$sessionId,
|
||||
$authCode = null,
|
||||
$accessToken = null,
|
||||
$accessTokenExpire = null,
|
||||
$stage = 'requested'
|
||||
);
|
||||
|
||||
/**
|
||||
* Delete an OAuth session
|
||||
*
|
||||
* <code>
|
||||
* DELETE FROM oauth_sessions WHERE client_id = $clientId AND owner_type =
|
||||
* $type AND owner_id = $typeId
|
||||
* </code>
|
||||
*
|
||||
* @param string $clientId The client ID
|
||||
* @param string $type The session owner's type
|
||||
* @param string $typeId The session owner's ID
|
||||
* @return [type] [description]
|
||||
*/
|
||||
public function deleteSession(
|
||||
$clientId,
|
||||
$type,
|
||||
$typeId
|
||||
);
|
||||
|
||||
/**
|
||||
* Validate that an authorisation code is valid
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT id FROM oauth_sessions WHERE client_id = $clientID AND
|
||||
* redirect_uri = $redirectUri AND auth_code = $authCode
|
||||
* </code>
|
||||
*
|
||||
* Response:
|
||||
*
|
||||
* <code>
|
||||
* Array
|
||||
* (
|
||||
* [id] => (int) The session ID
|
||||
* [client_id] => (string) The client ID
|
||||
* [redirect_uri] => (string) The redirect URI
|
||||
* [owner_type] => (string) The session owner type
|
||||
* [owner_id] => (string) The session owner's ID
|
||||
* [auth_code] => (string) The authorisation code
|
||||
* [stage] => (string) The session's stage
|
||||
* [first_requested] => (int) Unix timestamp of the time the session was
|
||||
* first generated
|
||||
* [last_updated] => (int) Unix timestamp of the time the session was
|
||||
* last updated
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $clientId The client ID
|
||||
* @param string $redirectUri The redirect URI
|
||||
* @param string $authCode The authorisation code
|
||||
* @return int|bool Returns the session ID if the auth code
|
||||
* is valid otherwise returns false
|
||||
*/
|
||||
public function validateAuthCode(
|
||||
$clientId,
|
||||
$redirectUri,
|
||||
$authCode
|
||||
);
|
||||
|
||||
/**
|
||||
* Return the session ID for a given session owner and client combination
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT id FROM oauth_sessions WHERE client_id = $clientId
|
||||
* AND owner_type = $type AND owner_id = $typeId
|
||||
* </code>
|
||||
*
|
||||
* @param string $type The session owner's type
|
||||
* @param string $typeId The session owner's ID
|
||||
* @param string $clientId The client ID
|
||||
* @return string|null Return the session ID as an integer if
|
||||
* found otherwise returns false
|
||||
*/
|
||||
public function hasSession(
|
||||
$type,
|
||||
$typeId,
|
||||
$clientId
|
||||
);
|
||||
|
||||
/**
|
||||
* Return the access token for a given session
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT access_token FROM oauth_sessions WHERE id = $sessionId
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The OAuth session ID
|
||||
* @return string|null Returns the access token as a string if
|
||||
* found otherwise returns null
|
||||
*/
|
||||
public function getAccessToken($sessionId);
|
||||
|
||||
/**
|
||||
* Removes an authorisation code associated with a session
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* UPDATE oauth_sessions SET auth_code = NULL WHERE id = $sessionId
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The OAuth session ID
|
||||
* @return void
|
||||
*/
|
||||
public function removeAuthCode($sessionId);
|
||||
|
||||
/**
|
||||
* Sets a sessions access token
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* UPDATE oauth_sessions SET access_token = $accessToken WHERE id =
|
||||
* $sessionId
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The OAuth session ID
|
||||
* @param string $accessToken The access token
|
||||
* @return void
|
||||
*/
|
||||
public function setAccessToken(
|
||||
$sessionId,
|
||||
$accessToken
|
||||
);
|
||||
|
||||
/**
|
||||
* Associates a session with a scope
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO oauth_session_scopes (session_id, scope) VALUE ($sessionId,
|
||||
* $scope)
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The session ID
|
||||
* @param string $scope The scope
|
||||
* @return void
|
||||
*/
|
||||
public function addSessionScope(
|
||||
$sessionId,
|
||||
$scope
|
||||
);
|
||||
|
||||
/**
|
||||
* Return information about a scope
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT * FROM scopes WHERE scope = $scope
|
||||
* </code>
|
||||
*
|
||||
* Response:
|
||||
*
|
||||
* <code>
|
||||
* Array
|
||||
* (
|
||||
* [id] => (int) The scope's ID
|
||||
* [scope] => (string) The scope itself
|
||||
* [name] => (string) The scope's name
|
||||
* [description] => (string) The scope's description
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $scope The scope
|
||||
* @return array
|
||||
*/
|
||||
public function getScope($scope);
|
||||
|
||||
/**
|
||||
* Associate a session's scopes with an access token
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* UPDATE oauth_session_scopes SET access_token = $accessToken WHERE
|
||||
* session_id = $sessionId
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The session ID
|
||||
* @param string $accessToken The access token
|
||||
* @return void
|
||||
*/
|
||||
public function updateSessionScopeAccessToken(
|
||||
$sessionId,
|
||||
$accessToken
|
||||
);
|
||||
|
||||
/**
|
||||
* Return the scopes associated with an access token
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT scopes.scope, scopes.name, scopes.description FROM
|
||||
* oauth_session_scopes JOIN scopes ON oauth_session_scopes.scope =
|
||||
* scopes.scope WHERE access_token = $accessToken
|
||||
* </code>
|
||||
*
|
||||
* Response:
|
||||
*
|
||||
* <code>
|
||||
* Array
|
||||
* (
|
||||
* [0] => Array
|
||||
* (
|
||||
* [scope] => (string) The scope
|
||||
* [name] => (string) The scope's name
|
||||
* [description] => (string) The scope's description
|
||||
* )
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $accessToken The access token
|
||||
* @return array
|
||||
*/
|
||||
public function accessTokenScopes($accessToken);
|
||||
}
|
517
src/Oauth2/Authentication/Server.php
Normal file
517
src/Oauth2/Authentication/Server.php
Normal file
@ -0,0 +1,517 @@
|
||||
<?php
|
||||
|
||||
namespace Oauth2\Authentication;
|
||||
|
||||
class OAuthServerClientException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class OAuthServerUserException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class OAuthServerException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class Server
|
||||
{
|
||||
/**
|
||||
* Reference to the database abstractor
|
||||
* @var object
|
||||
*/
|
||||
private $db = null;
|
||||
|
||||
/**
|
||||
* Server configuration
|
||||
* @var array
|
||||
*/
|
||||
private $config = array(
|
||||
'scope_delimeter' => ',',
|
||||
'access_token_ttl' => null
|
||||
);
|
||||
|
||||
/**
|
||||
* Supported response types
|
||||
* @var array
|
||||
*/
|
||||
private $response_types = array(
|
||||
'code'
|
||||
);
|
||||
|
||||
/**
|
||||
* Supported grant types
|
||||
* @var array
|
||||
*/
|
||||
private $grant_types = array(
|
||||
'authorization_code'
|
||||
);
|
||||
|
||||
/**
|
||||
* Exception error codes
|
||||
* @var array
|
||||
*/
|
||||
public $exceptionCodes = array(
|
||||
0 => 'invalid_request',
|
||||
1 => 'unauthorized_client',
|
||||
2 => 'access_denied',
|
||||
3 => 'unsupported_response_type',
|
||||
4 => 'invalid_scope',
|
||||
5 => 'server_error',
|
||||
6 => 'temporarily_unavailable',
|
||||
7 => 'unsupported_grant_type',
|
||||
8 => 'invalid_client',
|
||||
9 => 'invalid_grant'
|
||||
);
|
||||
|
||||
/**
|
||||
* Error codes.
|
||||
*
|
||||
* To provide i8ln errors just overwrite the keys
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $errors = array(
|
||||
'invalid_request' => 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "%s" parameter.',
|
||||
'unauthorized_client' => 'The client is not authorized to request an access token using this method.',
|
||||
'access_denied' => 'The resource owner or authorization server denied the request.',
|
||||
'unsupported_response_type' => 'The authorization server does not support obtaining an access token using this method.',
|
||||
'invalid_scope' => 'The requested scope is invalid, unknown, or malformed. Check the "%s" scope.',
|
||||
'server_error' => 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.',
|
||||
'temporarily_unavailable' => 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.',
|
||||
'unsupported_grant_type' => 'The authorization grant type is not supported by the authorization server',
|
||||
'invalid_client' => 'Client authentication failed',
|
||||
'invalid_grant' => 'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. Check the "%s" parameter.'
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @access public
|
||||
* @param array $options Optional list of options to overwrite the defaults
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($options = null)
|
||||
{
|
||||
if ($options !== null) {
|
||||
$this->options = array_merge($this->config, $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a database abstrator class
|
||||
*
|
||||
* @access public
|
||||
* @param object $db A class that implements OAuth2ServerDatabase
|
||||
* @return void
|
||||
*/
|
||||
public function registerDbAbstractor($db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check client authorise parameters
|
||||
*
|
||||
* @access public
|
||||
* @param array $authParams Optional array of parsed $_GET keys
|
||||
* @return array Authorise request parameters
|
||||
*/
|
||||
public function checkClientAuthoriseParams($authParams = null)
|
||||
{
|
||||
$params = array();
|
||||
|
||||
// Client ID
|
||||
if ( ! isset($authParams['client_id']) && ! isset($_GET['client_id'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'client_id'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$params['client_id'] = (isset($authParams['client_id'])) ? $authParams['client_id'] : $_GET['client_id'];
|
||||
|
||||
}
|
||||
|
||||
// Redirect URI
|
||||
if ( ! isset($authParams['redirect_uri']) && ! isset($_GET['redirect_uri'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'redirect_uri'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$params['redirect_uri'] = (isset($authParams['redirect_uri'])) ? $authParams['redirect_uri'] : $_GET['redirect_uri'];
|
||||
|
||||
}
|
||||
|
||||
// Validate client ID and redirect URI
|
||||
$clientDetails = $this->dbcall('validateClient', $params['client_id'], null, $params['redirect_uri']);
|
||||
|
||||
if ($clientDetails === false) {
|
||||
|
||||
throw new OAuthServerClientException($this->errors['invalid_client'], 8);
|
||||
}
|
||||
|
||||
// Response type
|
||||
if ( ! isset($authParams['response_type']) && ! isset($_GET['response_type'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'response_type'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$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)) {
|
||||
|
||||
throw new OAuthServerClientException($this->errors['unsupported_response_type'], 3);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Get and validate scopes
|
||||
if (isset($authParams['scope']) || isset($_GET['scope'])) {
|
||||
|
||||
$scopes = (isset($_GET['scope'])) ? $_GET['scope'] : $authParams['scope'];
|
||||
|
||||
$scopes = explode($this->config['scope_delimeter'], $scopes);
|
||||
|
||||
// Remove any junk scopes
|
||||
for ($i = 0; $i < count($scopes); $i++) {
|
||||
$scopes[$i] = trim($scopes[$i]);
|
||||
|
||||
if ($scopes[$i] === '') {
|
||||
unset($scopes[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($scopes) === 0) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'scope'), 0);
|
||||
}
|
||||
|
||||
$params['scopes'] = array();
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
|
||||
$scopeDetails = $this->dbcall('getScope', $scope);
|
||||
|
||||
if ($scopeDetails === false) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_scope'], $scope), 4);
|
||||
|
||||
}
|
||||
|
||||
$params['scopes'][] = $scopeDetails;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a new authorise request
|
||||
*
|
||||
* @param string $type The session owner's type
|
||||
* @param string $typeId The session owner's ID
|
||||
* @param array $authoriseParams The authorise request $_GET parameters
|
||||
* @return string An authorisation code
|
||||
*/
|
||||
public function newAuthoriseRequest($type, $typeId, $authoriseParams)
|
||||
{
|
||||
// Remove any old sessions the user might have
|
||||
$this->dbcall('deleteSession',
|
||||
$authoriseParams['client_id'],
|
||||
$type,
|
||||
$typeId
|
||||
);
|
||||
|
||||
// Create the new auth code
|
||||
$authCode = $this->newAuthCode(
|
||||
$authoriseParams['client_id'],
|
||||
'user',
|
||||
$typeId,
|
||||
$authoriseParams['redirect_uri'],
|
||||
$authoriseParams['scopes']
|
||||
);
|
||||
|
||||
return $authCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique code
|
||||
*
|
||||
* Generate a unique code for an authorisation code, or token
|
||||
*
|
||||
* @return string A unique code
|
||||
*/
|
||||
private function generateCode()
|
||||
{
|
||||
return sha1(uniqid(microtime()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new authorisation code
|
||||
*
|
||||
* @param string $clientId The client ID
|
||||
* @param string $type The type of the owner of the session
|
||||
* @param string $typeId The session owner's ID
|
||||
* @param string $redirectUri The redirect URI
|
||||
* @param array $scopes The requested scopes
|
||||
* @param string $accessToken The access token (default = null)
|
||||
* @return string An authorisation code
|
||||
*/
|
||||
private function newAuthCode($clientId, $type, $typeId, $redirectUri, $scopes = array(), $accessToken = null)
|
||||
{
|
||||
$authCode = $this->generateCode();
|
||||
|
||||
// If an access token exists then update the existing session with the
|
||||
// new authorisation code otherwise create a new session
|
||||
if ($accessToken !== null) {
|
||||
|
||||
$this->dbcall('updateSession',
|
||||
$clientId,
|
||||
$type,
|
||||
$typeId,
|
||||
$authCode,
|
||||
$accessToken,
|
||||
'request'
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
// Delete any existing sessions just to be sure
|
||||
$this->dbcall('deleteSession', $clientId, $type, $typeId);
|
||||
|
||||
// Create a new session
|
||||
$sessionId = $this->dbcall('newSession',
|
||||
$clientId,
|
||||
$redirectUri,
|
||||
$type,
|
||||
$typeId,
|
||||
$authCode,
|
||||
null,
|
||||
null,
|
||||
'request'
|
||||
);
|
||||
|
||||
// Add the scopes
|
||||
foreach ($scopes as $key => $scope) {
|
||||
|
||||
$this->dbcall('addSessionScope', $sessionId, $scope['scope']);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $authCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an access token
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param array $authParams Optional array of parsed $_POST keys
|
||||
*
|
||||
* @return array Authorise request parameters
|
||||
*/
|
||||
public function issueAccessToken($authParams = null)
|
||||
{
|
||||
$params = array();
|
||||
|
||||
if ( ! isset($authParams['grant_type']) && ! isset($_POST['grant_type'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'grant_type'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$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)) {
|
||||
|
||||
throw new OAuthServerClientException($this->errors['unsupported_grant_type'], 7);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
switch ($params['grant_type'])
|
||||
{
|
||||
|
||||
case 'authorization_code': // Authorization code grant
|
||||
return $this->completeAuthCodeGrant($authParams, $params);
|
||||
break;
|
||||
|
||||
case 'refresh_token': // Refresh token
|
||||
case 'password': // Resource owner password credentials grant
|
||||
case 'client_credentials': // Client credentials grant
|
||||
default: // Unsupported
|
||||
throw new OAuthServerException($this->errors['server_error'] . 'Tried to process an unsuppported grant type.', 5);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the authorisation code grant
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param array $authParams Array of parsed $_POST keys
|
||||
* @param array $params Generated parameters from issueAccessToken()
|
||||
*
|
||||
* @return array Authorise request parameters
|
||||
*/
|
||||
private function completeAuthCodeGrant($authParams = array(), $params = array())
|
||||
{
|
||||
// Client ID
|
||||
if ( ! isset($authParams['client_id']) && ! isset($_POST['client_id'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'client_id'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$params['client_id'] = (isset($authParams['client_id'])) ? $authParams['client_id'] : $_POST['client_id'];
|
||||
|
||||
}
|
||||
|
||||
// Client secret
|
||||
if ( ! isset($authParams['client_secret']) && ! isset($_POST['client_secret'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'client_secret'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$params['client_secret'] = (isset($authParams['client_secret'])) ? $authParams['client_secret'] : $_POST['client_secret'];
|
||||
|
||||
}
|
||||
|
||||
// Redirect URI
|
||||
if ( ! isset($authParams['redirect_uri']) && ! isset($_POST['redirect_uri'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'redirect_uri'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$params['redirect_uri'] = (isset($authParams['redirect_uri'])) ? $authParams['redirect_uri'] : $_POST['redirect_uri'];
|
||||
|
||||
}
|
||||
|
||||
// Validate client ID and redirect URI
|
||||
$clientDetails = $this->dbcall('validateClient',
|
||||
$params['client_id'],
|
||||
$params['client_secret'],
|
||||
$params['redirect_uri']
|
||||
);
|
||||
|
||||
if ($clientDetails === false) {
|
||||
|
||||
throw new OAuthServerClientException($this->errors['invalid_client'], 8);
|
||||
}
|
||||
|
||||
// The authorization code
|
||||
if ( ! isset($authParams['code']) && ! isset($_POST['code'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'code'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$params['code'] = (isset($authParams['code'])) ? $authParams['code'] : $_POST['code'];
|
||||
|
||||
}
|
||||
|
||||
// Verify the authorization code matches the client_id and the
|
||||
// request_uri
|
||||
$session = $this->dbcall('validateAuthCode',
|
||||
$params['client_id'],
|
||||
$params['redirect_uri'],
|
||||
$params['code']
|
||||
);
|
||||
|
||||
if ( ! $session) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_grant'], 'code'), 9);
|
||||
|
||||
} else {
|
||||
|
||||
// A session ID was returned so update it with an access token,
|
||||
// remove the authorisation code, change the stage to 'granted'
|
||||
|
||||
$accessToken = $this->generateCode();
|
||||
|
||||
$accessTokenExpires = ($this->config['access_token_ttl'] === null) ? null : time() + $this->config['access_token_ttl'];
|
||||
|
||||
$this->dbcall('updateSession',
|
||||
$session['id'],
|
||||
null,
|
||||
$accessToken,
|
||||
$accessTokenExpires,
|
||||
'granted'
|
||||
);
|
||||
|
||||
// Update the session's scopes to reference the access token
|
||||
$this->dbcall('updateSessionScopeAccessToken',
|
||||
$session['id'],
|
||||
$accessToken
|
||||
);
|
||||
|
||||
return array(
|
||||
'access_token' => $accessToken,
|
||||
'token_type' => 'bearer',
|
||||
'expires_in' => $this->config['access_token_ttl']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the redirect uri with appended params
|
||||
*
|
||||
* @param string $redirectUri The redirect URI
|
||||
* @param array $params The parameters to be appended to the URL
|
||||
* @param string $query_delimeter The query string delimiter (default: ?)
|
||||
*
|
||||
* @return string The updated redirect URI
|
||||
*/
|
||||
public function redirectUri($redirectUri, $params = array(), $queryDelimeter = '?')
|
||||
{
|
||||
|
||||
if (strstr($redirectUri, $queryDelimeter)) {
|
||||
|
||||
$redirectUri = $redirectUri . '&' . http_build_query($params);
|
||||
|
||||
} else {
|
||||
|
||||
$redirectUri = $redirectUri . $queryDelimeter . http_build_query($params);
|
||||
|
||||
}
|
||||
|
||||
return $redirectUri;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Call database methods from the abstractor
|
||||
*
|
||||
* @return mixed The query result
|
||||
*/
|
||||
private function dbcall()
|
||||
{
|
||||
if ($this->db === null) {
|
||||
throw new OAuthServerException('No registered database abstractor');
|
||||
}
|
||||
|
||||
if ( ! $this->db instanceof Database) {
|
||||
throw new OAuthServerException('Registered database abstractor is not an instance of Oauth2\Authentication\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);
|
||||
}
|
||||
}
|
59
src/Oauth2/Resource/Database.php
Normal file
59
src/Oauth2/Resource/Database.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Oauth2\Resource;
|
||||
|
||||
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);
|
||||
}
|
225
src/Oauth2/Resource/Server.php
Normal file
225
src/Oauth2/Resource/Server.php
Normal file
@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
namespace Oauth2\Resource;
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
}
|
59
src/sql/database.sql
Normal file
59
src/sql/database.sql
Normal file
@ -0,0 +1,59 @@
|
||||
-- Create syntax for TABLE 'clients'
|
||||
CREATE TABLE `clients` (
|
||||
`id` varchar(40) NOT NULL DEFAULT '',
|
||||
`secret` varchar(40) NOT NULL DEFAULT '',
|
||||
`name` varchar(255) NOT NULL DEFAULT '',
|
||||
`auto_approve` tinyint(1) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- Create syntax for TABLE 'client_endpoints'
|
||||
CREATE TABLE `client_endpoints` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`client_id` varchar(40) NOT NULL DEFAULT '',
|
||||
`redirect_uri` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `client_id` (`client_id`),
|
||||
CONSTRAINT `client_endpoints_ibfk_1` FOREIGN KEY (`client_id`) REFERENCES `clients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- Create syntax for TABLE 'oauth_sessions'
|
||||
CREATE TABLE `oauth_sessions` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`client_id` varchar(32) NOT NULL DEFAULT '',
|
||||
`redirect_uri` varchar(250) NOT NULL DEFAULT '',
|
||||
`owner_type` enum('user','client') NOT NULL DEFAULT 'user',
|
||||
`owner_id` varchar(255) DEFAULT NULL,
|
||||
`auth_code` varchar(40) DEFAULT '',
|
||||
`access_token` varchar(40) DEFAULT '',
|
||||
`access_token_expires` int(10) DEFAULT NULL,
|
||||
`stage` enum('requested','granted') NOT NULL DEFAULT 'requested',
|
||||
`first_requested` int(10) unsigned NOT NULL,
|
||||
`last_updated` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `client_id` (`client_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- Create syntax for TABLE 'scopes'
|
||||
CREATE TABLE `scopes` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`scope` varchar(255) NOT NULL DEFAULT '',
|
||||
`name` varchar(255) NOT NULL DEFAULT '',
|
||||
`description` varchar(255) DEFAULT '',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `scope` (`scope`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- Create syntax for TABLE 'oauth_session_scopes'
|
||||
CREATE TABLE `oauth_session_scopes` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`session_id` int(11) unsigned NOT NULL,
|
||||
`access_token` varchar(40) NOT NULL DEFAULT '',
|
||||
`scope` varchar(255) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `session_id` (`session_id`),
|
||||
KEY `access_token` (`access_token`),
|
||||
KEY `scope` (`scope`),
|
||||
CONSTRAINT `oauth_session_scopes_ibfk_3` FOREIGN KEY (`scope`) REFERENCES `scopes` (`scope`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT `oauth_session_scopes_ibfk_4` FOREIGN KEY (`session_id`) REFERENCES `oauth_sessions` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
0
src/sql/index.html
Normal file
0
src/sql/index.html
Normal file
1
test
Executable file
1
test
Executable file
@ -0,0 +1 @@
|
||||
vendor/bin/phpunit --coverage-text --configuration build/phpunit.xml
|
191
tests/authentication/database_mock.php
Normal file
191
tests/authentication/database_mock.php
Normal file
@ -0,0 +1,191 @@
|
||||
<?php
|
||||
|
||||
use Oauth2\Authentication\Database;
|
||||
|
||||
class OAuthdb implements Database
|
||||
{
|
||||
private $sessions = array();
|
||||
private $sessions_client_type_id = array();
|
||||
private $sessions_code = array();
|
||||
private $session_scopes = array();
|
||||
|
||||
private $clients = array(0 => array(
|
||||
'client_id' => 'test',
|
||||
'client_secret' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'name' => 'Test Client'
|
||||
));
|
||||
|
||||
private $scopes = array('test' => array(
|
||||
'id' => 1,
|
||||
'scope' => 'test',
|
||||
'name' => 'test',
|
||||
'description' => 'test'
|
||||
));
|
||||
|
||||
public function validateClient(
|
||||
$clientId,
|
||||
$clientSecret = null,
|
||||
$redirectUri = null
|
||||
)
|
||||
{
|
||||
if ($clientId !== $this->clients[0]['client_id'])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($clientSecret !== null && $clientSecret !== $this->clients[0]['client_secret'])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($redirectUri !== null && $redirectUri !== $this->clients[0]['redirect_uri'])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->clients[0];
|
||||
}
|
||||
|
||||
public function newSession(
|
||||
$clientId,
|
||||
$redirectUri,
|
||||
$type = 'user',
|
||||
$typeId = null,
|
||||
$authCode = null,
|
||||
$accessToken = null,
|
||||
$accessTokenExpire = null,
|
||||
$stage = 'requested'
|
||||
)
|
||||
{
|
||||
$id = count($this->sessions);
|
||||
|
||||
$this->sessions[$id] = array(
|
||||
'id' => $id,
|
||||
'client_id' => $clientId,
|
||||
'redirect_uri' => $redirectUri,
|
||||
'owner_type' => $type,
|
||||
'owner_id' => $typeId,
|
||||
'auth_code' => $authCode,
|
||||
'access_token' => $accessToken,
|
||||
'access_token_expire' => $accessTokenExpire,
|
||||
'stage' => $stage
|
||||
);
|
||||
|
||||
$this->sessions_client_type_id[$clientId . ':' . $type . ':' . $typeId] = $id;
|
||||
$this->sessions_code[$clientId . ':' . $redirectUri . ':' . $authCode] = $id;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function updateSession(
|
||||
$sessionId,
|
||||
$authCode = null,
|
||||
$accessToken = null,
|
||||
$accessTokenExpire = null,
|
||||
$stage = 'requested'
|
||||
)
|
||||
{
|
||||
$this->sessions[$sessionId]['auth_code'] = $authCode;
|
||||
$this->sessions[$sessionId]['access_token'] = $accessToken;
|
||||
$this->sessions[$sessionId]['access_token_expire'] = $accessTokenExpire;
|
||||
$this->sessions[$sessionId]['stage'] = $stage;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function deleteSession(
|
||||
$clientId,
|
||||
$type,
|
||||
$typeId
|
||||
)
|
||||
{
|
||||
$key = $clientId . ':' . $type . ':' . $typeId;
|
||||
if (isset($this->sessions_client_type_id[$key]))
|
||||
{
|
||||
unset($this->sessions[$this->sessions_client_type_id[$key]]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function validateAuthCode(
|
||||
$clientId,
|
||||
$redirectUri,
|
||||
$authCode
|
||||
)
|
||||
{
|
||||
$key = $clientId . ':' . $redirectUri . ':' . $authCode;
|
||||
|
||||
if (isset($this->sessions_code[$key]))
|
||||
{
|
||||
return $this->sessions[$this->sessions_code[$key]];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasSession(
|
||||
$type,
|
||||
$typeId,
|
||||
$clientId
|
||||
)
|
||||
{
|
||||
die('not implemented hasSession');
|
||||
}
|
||||
|
||||
public function getAccessToken($sessionId)
|
||||
{
|
||||
die('not implemented getAccessToken');
|
||||
}
|
||||
|
||||
public function removeAuthCode($sessionId)
|
||||
{
|
||||
die('not implemented removeAuthCode');
|
||||
}
|
||||
|
||||
public function setAccessToken(
|
||||
$sessionId,
|
||||
$accessToken
|
||||
)
|
||||
{
|
||||
die('not implemented setAccessToken');
|
||||
}
|
||||
|
||||
public function addSessionScope(
|
||||
$sessionId,
|
||||
$scope
|
||||
)
|
||||
{
|
||||
if ( ! isset($this->session_scopes[$sessionId]))
|
||||
{
|
||||
$this->session_scopes[$sessionId] = array();
|
||||
}
|
||||
|
||||
$this->session_scopes[$sessionId][] = $scope;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getScope($scope)
|
||||
{
|
||||
if ( ! isset($this->scopes[$scope]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->scopes[$scope];
|
||||
}
|
||||
|
||||
public function updateSessionScopeAccessToken(
|
||||
$sessionId,
|
||||
$accessToken
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function accessTokenScopes($accessToken)
|
||||
{
|
||||
die('not implemented accessTokenScopes');
|
||||
}
|
||||
}
|
398
tests/authentication/server_test.php
Normal file
398
tests/authentication/server_test.php
Normal file
@ -0,0 +1,398 @@
|
||||
<?php
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
function test_generateCode()
|
||||
{
|
||||
$reflector = new ReflectionClass($this->oauth);
|
||||
$method = $reflector->getMethod('generateCode');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invoke($this->oauth);
|
||||
$result2 = $method->invoke($this->oauth);
|
||||
|
||||
$this->assertEquals(40, strlen($result));
|
||||
$this->assertNotEquals($result, $result2);
|
||||
}
|
||||
|
||||
function test_redirectUri()
|
||||
{
|
||||
$result1 = $this->oauth->redirectUri('http://example.com/foo');
|
||||
$result2 = $this->oauth->redirectUri('http://example.com/foo', array('foo' => 'bar'));
|
||||
$result3 = $this->oauth->redirectUri('http://example.com/foo', array('foo' => 'bar'), '#');
|
||||
|
||||
$this->assertEquals('http://example.com/foo?', $result1);
|
||||
$this->assertEquals('http://example.com/foo?foo=bar', $result2);
|
||||
$this->assertEquals('http://example.com/foo#foo=bar', $result3);
|
||||
}
|
||||
|
||||
function test_checkClientAuthoriseParams_GET()
|
||||
{
|
||||
$_GET['client_id'] = 'test';
|
||||
$_GET['redirect_uri'] = 'http://example.com/test';
|
||||
$_GET['response_type'] = 'code';
|
||||
$_GET['scope'] = 'test';
|
||||
|
||||
$expect = array(
|
||||
'client_id' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'response_type' => 'code',
|
||||
'scopes' => array(
|
||||
0 => array(
|
||||
'id' => 1,
|
||||
'scope' => 'test',
|
||||
'name' => 'test',
|
||||
'description' => 'test'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$result = $this->oauth->checkClientAuthoriseParams();
|
||||
|
||||
$this->assertEquals($expect, $result);
|
||||
}
|
||||
|
||||
function test_checkClientAuthoriseParams_PassedParams()
|
||||
{
|
||||
unset($_GET['client_id']);
|
||||
unset($_GET['redirect_uri']);
|
||||
unset($_GET['response_type']);
|
||||
unset($_GET['scope']);
|
||||
|
||||
$params = array(
|
||||
'client_id' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'response_type' => 'code',
|
||||
'scope' => 'test'
|
||||
);
|
||||
|
||||
$this->assertEquals(array(
|
||||
'client_id' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'response_type' => 'code',
|
||||
'scopes' => array(0 => array(
|
||||
'id' => 1,
|
||||
'scope' => 'test',
|
||||
'name' => 'test',
|
||||
'description' => 'test'
|
||||
))
|
||||
), $this->oauth->checkClientAuthoriseParams($params));
|
||||
}
|
||||
|
||||
/**
|
||||
* @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(
|
||||
'client_id' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'scopes' => array(array(
|
||||
'id' => 1,
|
||||
'scope' => 'test',
|
||||
'name' => 'test',
|
||||
'description' => 'test'
|
||||
))
|
||||
));
|
||||
|
||||
$this->assertEquals(40, strlen($result));
|
||||
}
|
||||
|
||||
function test_newAuthoriseRequest_isUnique()
|
||||
{
|
||||
$result1 = $this->oauth->newAuthoriseRequest('user', '123', array(
|
||||
'client_id' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'scopes' => array(array(
|
||||
'id' => 1,
|
||||
'scope' => 'test',
|
||||
'name' => 'test',
|
||||
'description' => 'test'
|
||||
))
|
||||
));
|
||||
|
||||
$result2 = $this->oauth->newAuthoriseRequest('user', '123', array(
|
||||
'client_id' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'scopes' => array(array(
|
||||
'id' => 1,
|
||||
'scope' => 'test',
|
||||
'name' => 'test',
|
||||
'description' => 'test'
|
||||
))
|
||||
));
|
||||
|
||||
$this->assertNotEquals($result1, $result2);
|
||||
}
|
||||
|
||||
function test_issueAccessToken_POST()
|
||||
{
|
||||
$auth_code = $this->oauth->newAuthoriseRequest('user', '123', array(
|
||||
'client_id' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'scopes' => array(array(
|
||||
'id' => 1,
|
||||
'scope' => 'test',
|
||||
'name' => 'test',
|
||||
'description' => 'test'
|
||||
))
|
||||
));
|
||||
|
||||
$_POST['client_id'] = 'test';
|
||||
$_POST['client_secret'] = 'test';
|
||||
$_POST['redirect_uri'] = 'http://example.com/test';
|
||||
$_POST['grant_type'] = 'authorization_code';
|
||||
$_POST['code'] = $auth_code;
|
||||
|
||||
$result = $this->oauth->issueAccessToken();
|
||||
|
||||
$this->assertCount(3, $result);
|
||||
$this->assertArrayHasKey('access_token', $result);
|
||||
$this->assertArrayHasKey('token_type', $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);
|
||||
}
|
||||
|
||||
}
|
31
tests/resource/database_mock.php
Normal file
31
tests/resource/database_mock.php
Normal 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();
|
||||
}
|
||||
}
|
121
tests/resource/server_test.php
Normal file
121
tests/resource/server_test.php
Normal 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());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user