Compare commits

...

40 Commits
3.1.2 ... 3.2.4

Author SHA1 Message Date
Alex Bilbie
13cd0cacdf Merge pull request #204 from ushahidi/missing-token-message
Add a new "missing_token" exception message to Resource server
2014-09-08 22:01:33 +01:00
Woody Gilk
f03e4a9e37 Add a new "missing_token" exception message to Resource server 2014-08-26 11:42:41 -05:00
Alex Bilbie
da92410ecb Merge pull request #196 from barryvdh/patch-1
Remove links to wiki
2014-08-13 08:29:34 +02:00
Alex Bilbie
23303905a8 Merge pull request #197 from GrahamCampbell/patch-1
Update composer.json
2014-08-10 11:15:18 +01:00
Graham Campbell
0b8e69f0d0 Update composer.json 2014-08-10 11:11:15 +01:00
Barry vd. Heuvel
a448f2167b Remove links to wiki
They don't work anymore. Not sure where they went?
2014-08-08 10:57:30 +02:00
Alex Bilbie
2f14f6b391 Version bump 2014-07-23 16:13:50 +01:00
Alex Bilbie
94369abd60 Merge branch 'release/3.2.2'
Conflicts:
	composer.json
2014-07-23 16:10:02 +01:00
Alex Bilbie
45edac4216 Version bump 2014-07-23 16:08:50 +01:00
Alex Bilbie
5bdfc9908a Updated changelog 2014-07-23 16:08:33 +01:00
Alex Bilbie
1890d71838 Merge branch 'develop' of github.com:thephpleague/oauth2-server into develop 2014-07-23 16:05:42 +01:00
Alex Bilbie
00d5fb5834 Merge pull request #188 from ushahidi/fix-http-headers-util-request
Fix Resource server Request HTTP header access
2014-07-23 15:58:24 +01:00
Robbie Mackay
49b776c495 In Resource::getExceptionHttpHeaders() use Request::BuildFromGlobals 2014-07-23 07:48:05 -07:00
Woody Gilk
31e03c2d36 Fix broken http header extraction in Util\Request 2014-07-23 07:47:29 -07:00
Alex Bilbie
6f85bcbbf1 Merge branch 'develop' of github.com:thephpleague/oauth2-server into develop 2014-07-22 11:45:54 +01:00
Phil Sturgeon
7771bc04ec Merge pull request #186 from ushahidi/resource-server-correct-http-error
Send HTTP 401 for invalid_token, rather than insufficient_scope
2014-07-15 15:39:28 +01:00
Woody Gilk
f34dd4a0cb 401 status is for invalid_token, not insufficient_scope 2014-07-11 11:59:18 -05:00
Alex Bilbie
4362f17fd6 Update composer.json 2014-07-11 16:21:40 +01:00
Alex Bilbie
6d81c1e57e Merge branch 'develop' 2014-07-11 15:27:19 +01:00
Alex Bilbie
1a88d3f4c5 Ignore build files 2014-07-11 15:21:32 +01:00
Alex Bilbie
4480aa3456 Merge pull request #178 from ushahidi/resource-server-errors
Resource server errors
2014-07-11 11:47:29 +01:00
Woody Gilk
44db2b295f Stop testing stdClass as an argument to hasScope, it is pointless 2014-07-10 17:02:50 -05:00
Woody Gilk
33f4f5b7ab Add $required parameter to hasScope(), triggers InsufficientScopeException 2014-07-10 17:02:16 -05:00
Woody Gilk
e61782975a Copy getExceptionType(), getExceptionMessage(), and getExceptionHttpHeaders() to Resource server 2014-07-10 17:02:16 -05:00
Woody Gilk
d7c1c50269 Throw MissingAccessTokenException in the Resource server when no token exists 2014-07-10 16:59:25 -05:00
Phil Sturgeon
4486b7120f Merge pull request #177 from ushahidi/notabs
Clean up mixed tabs and spaces in test files
2014-07-02 11:40:16 +01:00
Phil Sturgeon
687e794ce3 Merge pull request #182 from acairns/develop
Use utf8_unicode_ci as default collation
2014-07-02 11:39:59 +01:00
Andrew Cairns
c7dfc42d57 Use utf8_unicode_ci as default collation 2014-06-26 15:39:35 +01:00
Woody Gilk
cd767c07fa Replace all tabs with 4 spaces in test files 2014-05-31 16:30:32 -05:00
Alex Bilbie
8e164f4b99 Merge pull request #171 from acairns/develop
Fixing Bearer case for consistency
2014-05-22 09:31:47 +01:00
Andrew Cairns
400d4d8f1e Fixing Bearer case for consistency 2014-05-20 17:13:29 +01:00
Phil Sturgeon
5ffbe6ac37 Delete phpunit.xml 2014-05-13 14:01:13 +01:00
Alex Bilbie
ba5f2840fb Merge branch 'release/3.2' into develop 2014-04-06 22:04:27 +01:00
Alex Bilbie
e8aeaf0777 Merge branch 'release/3.2' 2014-04-06 22:04:19 +01:00
Alex Bilbie
fcc1388aeb Updated change log and version number 2014-04-06 22:04:12 +01:00
Alex Bilbie
d7ddfe6452 Updated docblock 2014-04-06 22:01:56 +01:00
Alex Bilbie
785d3bd21f Merge pull request #151 from giftcards/develop
add the ability to change the algorithm that is used to generate the token strings
2014-04-06 21:13:58 +01:00
Joseph Deray
cc1e78e1ff removed unused use statement 2014-03-11 12:42:26 -04:00
Joseph Deray
b12a1d84df added the ability to change the algorithm used to generate the token strings. added files missing in last commit 2014-03-11 12:41:21 -04:00
Joseph Deray
901aab9deb added the ability to change the algorithm used to generate the token strings 2014-03-11 12:39:09 -04:00
19 changed files with 525 additions and 230 deletions

3
.gitignore vendored
View File

@@ -2,4 +2,5 @@
/composer.lock
/tests/coverage
/docs
/testing
/testing
build/coverage

View File

@@ -1,5 +1,13 @@
# Changelog
## 3.2.2 (released 2014-07-23)
* Fix Resource server Request HTTP header access (Issue #188)
## 3.2 (released 2014-04-16)
* Added the ability to change the algorithm that is used to generate the token strings (Issue #151)
## 3.1.2 (released 2014-02-26)
* Support Authorization being an environment variable. [See more](http://fortrabbit.com/docs/essentials/quirks-and-constraints#authorization-header)

View File

@@ -42,27 +42,13 @@ The authorization server is a flexible class and the following core specificatio
* client credentials ([section 2.3.1](http://tools.ietf.org/html/rfc6749#section-2.3.1))
* password (user credentials) ([section 4.3](http://tools.ietf.org/html/rfc6749#section-4.3))
An [overview of the different OAuth 2.0 grants](https://github.com/thephpleague/oauth2-server/wiki/Which-OAuth-2.0-grant-should-I-use%3F) can be found in the [wiki].
### 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 scope(s) (i.e. permissions) to access resources.
### Custom grants
Custom grants can be created easily by implementing an interface. Check out the [custom grant guide](https://github.com/thephpleague/oauth2-server/wiki/Creating-custom-grants).
## Tutorials and Documentation
* **[Wiki]** - The wiki has lots of guides on how to use this library.
* **[Developing an OAuth-2.0 Authorization Server]** - A simple tutorial on how to use the authorization server.
* **[Securing your API with OAuth 2.0]** - A simple tutorial on how to use the resource server to secure an API server.
[Wiki]: https://github.com/thephpleague/oauth2-server/wiki
[Securing your API with OAuth 2.0]: https://github.com/thephpleague/oauth2-server/wiki/Securing-your-API-with-OAuth-2.0
[Developing an OAuth-2.0 Authorization Server]: https://github.com/thephpleague/oauth2-server/wiki/Developing-an-OAuth-2.0-authorization-server
Custom grants can be created easily by implementing an interface.
## Changelog

View File

@@ -1,13 +1,12 @@
{
"name": "league/oauth2-server",
"description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.",
"version": "3.1.2",
"license": "MIT",
"require": {
"php": ">=5.4.0"
},
"require-dev": {
"mockery/mockery": ">=0.7.2",
"mockery/mockery": "~0.8",
"league/phpunit-coverage-listener": "~1.0"
},
"repositories": [
@@ -44,7 +43,9 @@
"League\\OAuth2\\Server": "src/"
}
},
"suggest": {
"extra": {
"branch-alias": {
"dev-master": "3.2.x-dev"
}
}
}

View File

@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnError="false" stopOnFailure="false" stopOnIncomplete="false" stopOnSkipped="false" bootstrap="tests/Bootstrap.php">
<testsuites>
<testsuite name="Authorization Server">
<directory suffix="Test.php">tests/authorization</directory>
</testsuite>
<testsuite name="Resource Server">
<directory suffix="Test.php">tests/resource</directory>
</testsuite>
<testsuite name="Utility Methods">
<directory suffix="Test.php">tests/util</directory>
</testsuite>
</testsuites>
<filter>
<blacklist>
<directory suffix=".php">PEAR_INSTALL_DIR</directory>
<directory suffix=".php">PHP_LIBDIR</directory>
<directory suffix=".php">vendor</directory>
<directory suffix=".php">tests</directory>
<directory suffix=".php">testing</directory>
</blacklist>
</filter>
<logging>
<log type="coverage-text" target="php://stdout" title="lncd/OAuth" charset="UTF-8" yui="true" highlight="true" lowUpperBound="60" highLowerBound="99"/>
<log type="coverage-html" target="tests/coverage" title="lncd/OAuth" charset="UTF-8" yui="true" highlight="true" lowUpperBound="60" highLowerBound="99"/>
</logging>
</phpunit>

View File

@@ -5,7 +5,7 @@ CREATE TABLE `oauth_clients` (
`auto_approve` TINYINT(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `u_oacl_clse_clid` (`secret`,`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_client_endpoints` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
@@ -14,7 +14,7 @@ CREATE TABLE `oauth_client_endpoints` (
PRIMARY KEY (`id`),
KEY `i_oaclen_clid` (`client_id`),
CONSTRAINT `f_oaclen_clid` FOREIGN KEY (`client_id`) REFERENCES `oauth_clients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_sessions` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
@@ -24,7 +24,7 @@ CREATE TABLE `oauth_sessions` (
PRIMARY KEY (`id`),
KEY `i_uase_clid_owty_owid` (`client_id`,`owner_type`,`owner_id`),
CONSTRAINT `f_oase_clid` FOREIGN KEY (`client_id`) REFERENCES `oauth_clients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_session_access_tokens` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
@@ -35,7 +35,7 @@ CREATE TABLE `oauth_session_access_tokens` (
UNIQUE KEY `u_oaseacto_acto_seid` (`access_token`,`session_id`),
KEY `f_oaseto_seid` (`session_id`),
CONSTRAINT `f_oaseto_seid` FOREIGN KEY (`session_id`) REFERENCES `oauth_sessions` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_session_authcodes` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
@@ -45,14 +45,14 @@ CREATE TABLE `oauth_session_authcodes` (
PRIMARY KEY (`id`),
KEY `session_id` (`session_id`),
CONSTRAINT `oauth_session_authcodes_ibfk_1` FOREIGN KEY (`session_id`) REFERENCES `oauth_sessions` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_session_redirects` (
`session_id` int(10) unsigned NOT NULL,
`redirect_uri` varchar(255) NOT NULL,
PRIMARY KEY (`session_id`),
CONSTRAINT `f_oasere_seid` FOREIGN KEY (`session_id`) REFERENCES `oauth_sessions` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_session_refresh_tokens` (
`session_access_token_id` int(10) unsigned NOT NULL,
@@ -63,7 +63,7 @@ CREATE TABLE `oauth_session_refresh_tokens` (
KEY `client_id` (`client_id`),
CONSTRAINT `oauth_session_refresh_tokens_ibfk_1` FOREIGN KEY (`client_id`) REFERENCES `oauth_clients` (`id`) ON DELETE CASCADE,
CONSTRAINT `f_oasetore_setoid` FOREIGN KEY (`session_access_token_id`) REFERENCES `oauth_session_access_tokens` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_scopes` (
`id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
@@ -72,7 +72,7 @@ CREATE TABLE `oauth_scopes` (
`description` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u_oasc_sc` (`scope`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_session_token_scopes` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
@@ -83,7 +83,7 @@ CREATE TABLE `oauth_session_token_scopes` (
KEY `f_oasetosc_scid` (`scope_id`),
CONSTRAINT `f_oasetosc_scid` FOREIGN KEY (`scope_id`) REFERENCES `oauth_scopes` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
CONSTRAINT `f_oasetosc_setoid` FOREIGN KEY (`session_access_token_id`) REFERENCES `oauth_session_access_tokens` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
CREATE TABLE `oauth_session_authcode_scopes` (
`oauth_session_authcode_id` int(10) unsigned NOT NULL,
@@ -92,4 +92,4 @@ CREATE TABLE `oauth_session_authcode_scopes` (
KEY `scope_id` (`scope_id`),
CONSTRAINT `oauth_session_authcode_scopes_ibfk_2` FOREIGN KEY (`scope_id`) REFERENCES `oauth_scopes` (`id`) ON DELETE CASCADE,
CONSTRAINT `oauth_session_authcode_scopes_ibfk_1` FOREIGN KEY (`oauth_session_authcode_id`) REFERENCES `oauth_session_authcodes` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;

View File

@@ -0,0 +1,20 @@
<?php
/**
* OAuth 2.0 Insufficient Scope Exception
*
* @package php-loep/oauth2-server
* @author Woody Gilk <woody@shadowhand.me>
* @copyright Copyright (c) 2014 PHP League of Extraordinary Packages
* @license http://mit-license.org/
* @link http://github.com/php-loep/oauth2-server
*/
namespace League\OAuth2\Server\Exception;
/**
* InsufficientScope Exception
*/
class InsufficientScopeException extends OAuth2Exception
{
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* OAuth 2.0 Missing Access Token Exception
*
* @package php-loep/oauth2-server
* @author Woody Gilk <woody@shadowhand.me>
* @copyright Copyright (c) 2014 PHP League of Extraordinary Packages
* @license http://mit-license.org/
* @link http://github.com/php-loep/oauth2-server
*/
namespace League\OAuth2\Server\Exception;
/**
* MissingAccessToken Exception
*/
class MissingAccessTokenException extends OAuth2Exception
{
}

View File

@@ -192,7 +192,7 @@ class RefreshToken implements GrantTypeInterface {
$response = array(
'access_token' => $accessToken,
'token_type' => 'bearer',
'token_type' => 'Bearer',
'expires' => $accessTokenExpires,
'expires_in' => $accessTokenExpiresIn
);

View File

@@ -4,7 +4,8 @@
*
* @package php-loep/oauth2-server
* @author Alex Bilbie <hello@alexbilbie.com>
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
* @author Woody Gilk <woody@shadowhand.me>
* @copyright Copyright (c) 2013-2014 PHP League of Extraordinary Packages
* @license http://mit-license.org/
* @link http://github.com/php-loep/oauth2-server
*/
@@ -75,6 +76,120 @@ class Resource
*/
protected $clientId = null;
/**
* Exception error codes
* @var array
*/
protected static $exceptionCodes = array(
0 => 'invalid_request',
1 => 'invalid_token',
2 => 'insufficient_scope',
3 => 'missing_token',
);
/**
* Exception error messages
* @var array
*/
protected static $exceptionMessages = 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.',
'invalid_token' => 'The access token provided is expired, revoked, malformed, or invalid for other reasons.',
'insufficient_scope' => 'The request requires higher privileges than provided by the access token. Required scopes are: %s.',
'missing_token' => 'The request is missing an access token in either the Authorization header or the %s request parameter.',
);
/**
* Exception error HTTP status codes
* @var array
*
* RFC 6750, section 3.1:
* When a request fails, the resource server responds using the
* appropriate HTTP status code (typically, 400, 401, 403, or 405) and
* includes one of the following error codes in the response:
*/
protected static $exceptionHttpStatusCodes = array(
'invalid_request' => 400,
'invalid_token' => 401,
'insufficient_scope' => 403,
'missing_token' => 400,
);
/**
* Get an exception message
*
* @param string $error The error message key
* @return string The error message
*/
public static function getExceptionMessage($error = '')
{
return self::$exceptionMessages[$error];
}
/**
* Get an exception code
*
* @param integer $code The exception code
* @return string The exception code type
*/
public static function getExceptionType($code = 0)
{
return self::$exceptionCodes[$code];
}
/**
* Get all headers that have to be send with the error response
*
* @param string $error The error message key
* @return array Array with header values
*/
public static function getExceptionHttpHeaders($error)
{
$headers = array();
switch (self::$exceptionHttpStatusCodes[$error]) {
case 401:
$headers[] = 'HTTP/1.1 401 Unauthorized';
break;
case 403:
$headers[] = 'HTTP/1.1 403 Forbidden';
break;
case 400:
default:
$headers[] = 'HTTP/1.1 400 Bad Request';
}
// Add "WWW-Authenticate" header
//
// RFC 6749, section 5.2.:
// "If the client attempted to authenticate via the 'Authorization'
// request header field, the authorization server MUST
// respond with an HTTP 401 (Unauthorized) status code and
// include the "WWW-Authenticate" response header field
// matching the authentication scheme used by the client.
// @codeCoverageIgnoreStart
if ($error === 'invalid_token') {
$authScheme = null;
$request = Request::buildFromGlobals();
if ($request->server('PHP_AUTH_USER') !== null) {
$authScheme = 'Basic';
} else {
$authHeader = $request->header('Authorization');
if ($authHeader !== null) {
if (strpos($authHeader, 'Bearer') === 0) {
$authScheme = 'Bearer';
} elseif (strpos($authHeader, 'Basic') === 0) {
$authScheme = 'Basic';
}
}
}
if ($authScheme !== null) {
$headers[] = 'WWW-Authenticate: '.$authScheme.' realm=""';
}
}
// @codeCoverageIgnoreEnd
return $headers;
}
/**
* Sets up the Resource
*
@@ -186,7 +301,7 @@ class Resource
$result = $this->storages['session']->validateAccessToken($accessToken);
if (! $result) {
throw new Exception\InvalidAccessTokenException('Access token is not valid');
throw new Exception\InvalidAccessTokenException(self::$exceptionMessages['invalid_token'], 1);
}
$this->accessToken = $accessToken;
@@ -216,25 +331,26 @@ class Resource
* Checks if the presented access token has the given scope(s).
*
* @param array|string An array of scopes or a single scope as a string
* @param bool If scopes are required, missing scope will trigger an exception
* @throws Exception\InsufficientScopeException Thrown if the any of the given scopes are not in the session
* @return bool Returns bool if all scopes are found, false if any fail
*/
public function hasScope($scopes)
public function hasScope($scopes, $required = false)
{
if (is_string($scopes)) {
if (in_array($scopes, $this->sessionScopes)) {
return true;
}
return false;
} elseif (is_array($scopes)) {
foreach ($scopes as $scope) {
if (! in_array($scope, $this->sessionScopes)) {
return false;
}
}
return true;
if (!is_array($scopes)) {
$scopes = array($scopes);
}
return false;
$missing = array_diff($scopes, $this->sessionScopes);
if ($missing) {
if ($required) {
$missing = implode(', ', $missing);
throw new Exception\InsufficientScopeException(sprintf(self::$exceptionMessages['insufficient_scope'], $missing), 3);
}
return false;
}
return true;
}
/**
@@ -274,7 +390,7 @@ class Resource
}
if (empty($accessToken)) {
throw new Exception\InvalidAccessTokenException('Access token is missing');
throw new Exception\MissingAccessTokenException(sprintf(self::$exceptionMessages['missing_token'], $this->tokenKey), 3);
}
return $accessToken;

View File

@@ -0,0 +1,38 @@
<?php
/**
* OAuth 2.0 Secure key default algorithm
*
* @package php-loep/oauth2-server
* @author Alex Bilbie <hello@alexbilbie.com>
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
* @license http://mit-license.org/
* @link http://github.com/php-loep/oauth2-server
*/
namespace League\OAuth2\Server\Util\KeyAlgorithm;
class DefaultAlgorithm implements KeyAlgorithmInterface
{
/**
* @param int $len
* @return string
* @throws \Exception
*/
public function make($len = 40)
{
// We generate twice as many bytes here because we want to ensure we have
// enough after we base64 encode it to get the length we need because we
// take out the "/", "+", and "=" characters.
$bytes = openssl_random_pseudo_bytes($len * 2, $strong);
// We want to stop execution if the key fails because, well, that is bad.
if ($bytes === false || $strong === false) {
// @codeCoverageIgnoreStart
throw new \Exception('Error Generating Key');
// @codeCoverageIgnoreEnd
}
return substr(str_replace(array('/', '+', '='), '', base64_encode($bytes)), 0, $len);
}
}

View File

@@ -0,0 +1,18 @@
<?php
/**
* OAuth 2.0 Key algorithm interface
*
* @package php-loep/oauth2-server
* @author Alex Bilbie <hello@alexbilbie.com>
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
* @license http://mit-license.org/
* @link http://github.com/php-loep/oauth2-server
*/
namespace League\OAuth2\Server\Util\KeyAlgorithm;
interface KeyAlgorithmInterface
{
public function make($len = 40);
}

View File

@@ -76,22 +76,25 @@ class Request implements RequestInterface
protected function readHeaders()
{
if (function_exists('getallheaders')) {
if (function_exists('apache_request_headers')) {
// @codeCoverageIgnoreStart
$headers = getallheaders();
$headers = apache_request_headers();
} elseif (function_exists('http_get_request_headers')) {
$headers = http_get_request_headers();
} else {
// @codeCoverageIgnoreEnd
$headers = array();
foreach ($this->server() as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_') {
$name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))));
// HTTP_FOO_BAR becomes FOO-BAR
$name = str_replace(array('HTTP_', '_'), array('', '-'), $name);
$headers[$name] = $value;
}
}
}
return $this->normalizeHeaders($headers);
}
}
protected function getPropertyValue($property, $index = null, $default = null)
{
@@ -143,4 +146,4 @@ class Request implements RequestInterface
return $key;
}
}
}

View File

@@ -11,11 +11,16 @@
namespace League\OAuth2\Server\Util;
use League\OAuth2\Server\Util\KeyAlgorithm\DefaultAlgorithm;
use League\OAuth2\Server\Util\KeyAlgorithm\KeyAlgorithmInterface;
/**
* SecureKey class
*/
class SecureKey
{
protected static $algorithm;
/**
* Generate a new unique code
* @param integer $len Length of the generated code
@@ -23,18 +28,27 @@ class SecureKey
*/
public static function make($len = 40)
{
// We generate twice as many bytes here because we want to ensure we have
// enough after we base64 encode it to get the length we need because we
// take out the "/", "+", and "=" characters.
$bytes = openssl_random_pseudo_bytes($len * 2, $strong);
return self::getAlgorithm()->make($len);
}
// We want to stop execution if the key fails because, well, that is bad.
if ($bytes === false || $strong === false) {
// @codeCoverageIgnoreStart
throw new \Exception('Error Generating Key');
// @codeCoverageIgnoreEnd
/**
* @param KeyAlgorithmInterface $algorithm
*/
public static function setAlgorithm(KeyAlgorithmInterface $algorithm)
{
self::$algorithm = $algorithm;
}
/**
* @return KeyAlgorithmInterface
*/
public static function getAlgorithm()
{
if (!self::$algorithm) {
self::$algorithm = new DefaultAlgorithm();
}
return substr(str_replace(array('/', '+', '='), '', base64_encode($bytes)), 0, $len);
return self::$algorithm;
}
}

View File

@@ -4,19 +4,45 @@ use \Mockery as m;
class Resource_Server_test extends PHPUnit_Framework_TestCase
{
private $session;
private $session;
public function setUp()
{
public function setUp()
{
$this->session = M::mock('League\OAuth2\Server\Storage\SessionInterface');
}
}
private function returnDefault()
{
return new League\OAuth2\Server\Resource($this->session);
}
private function returnDefault()
{
return new League\OAuth2\Server\Resource($this->session);
}
public function test_setRequest()
public function test_getExceptionMessage()
{
$m = League\OAuth2\Server\Resource::getExceptionMessage('invalid_request');
$reflector = new ReflectionClass($this->returnDefault());
$exceptionMessages = $reflector->getProperty('exceptionMessages');
$exceptionMessages->setAccessible(true);
$v = $exceptionMessages->getValue();
$this->assertEquals($v['invalid_request'], $m);
}
public function test_getExceptionCode()
{
$this->assertEquals('invalid_request', League\OAuth2\Server\Resource::getExceptionType(0));
$this->assertEquals('invalid_token', League\OAuth2\Server\Resource::getExceptionType(1));
$this->assertEquals('insufficient_scope', League\OAuth2\Server\Resource::getExceptionType(2));
}
public function test_getExceptionHttpHeaders()
{
$this->assertEquals(array('HTTP/1.1 400 Bad Request'), League\OAuth2\Server\Resource::getExceptionHttpHeaders('invalid_request'));
$this->assertContains('HTTP/1.1 401 Unauthorized', League\OAuth2\Server\Resource::getExceptionHttpHeaders('invalid_token'));
$this->assertEquals(array('HTTP/1.1 403 Forbidden'), League\OAuth2\Server\Resource::getExceptionHttpHeaders('insufficient_scope'));
}
public function test_setRequest()
{
$s = $this->returnDefault();
$request = new League\OAuth2\Server\Util\Request();
@@ -49,7 +75,7 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase
public function test_setTokenKey()
{
$s = $this->returnDefault();
$s->setTokenKey('oauth_token');
$s->setTokenKey('oauth_token');
$reflector = new ReflectionClass($s);
$requestProperty = $reflector->getProperty('tokenKey');
@@ -66,25 +92,25 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase
}
/**
* @expectedException League\OAuth2\Server\Exception\InvalidAccessTokenException
* @expectedException League\OAuth2\Server\Exception\MissingAccessTokenException
*/
public function test_determineAccessToken_missingToken()
{
$_SERVER['HTTP_AUTHORIZATION'] = 'Bearer';
$request = new League\OAuth2\Server\Util\Request(array(), array(), array(), array(), $_SERVER);
$_SERVER['HTTP_AUTHORIZATION'] = 'Bearer';
$request = new League\OAuth2\Server\Util\Request(array(), array(), array(), array(), $_SERVER);
$s = $this->returnDefault();
$s->setRequest($request);
$s = $this->returnDefault();
$s->setRequest($request);
$reflector = new ReflectionClass($s);
$method = $reflector->getMethod('determineAccessToken');
$method->setAccessible(true);
$reflector = new ReflectionClass($s);
$method = $reflector->getMethod('determineAccessToken');
$method->setAccessible(true);
$method->invoke($s);
$method->invoke($s);
}
/**
* @expectedException League\OAuth2\Server\Exception\InvalidAccessTokenException
* @expectedException League\OAuth2\Server\Exception\MissingAccessTokenException
*/
public function test_determineAccessToken_brokenCurlRequest()
{
@@ -114,14 +140,14 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase
$s = $this->returnDefault();
$s->setRequest($request);
$reflector = new ReflectionClass($s);
$reflector = new ReflectionClass($s);
$method = $reflector->getMethod('determineAccessToken');
$method->setAccessible(true);
$method = $reflector->getMethod('determineAccessToken');
$method->setAccessible(true);
$result = $method->invoke($s);
$result = $method->invoke($s);
$this->assertEquals('abcdef', $result);
$this->assertEquals('abcdef', $result);
}
public function test_determineAccessToken_fromBrokenCurlHeader()
@@ -149,21 +175,54 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase
public function test_determineAccessToken_fromMethod()
{
$s = $this->returnDefault();
$s = $this->returnDefault();
$_GET[$s->getTokenKey()] = 'abcdef';
$_SERVER['REQUEST_METHOD'] = 'get';
$_GET[$s->getTokenKey()] = 'abcdef';
$_SERVER['REQUEST_METHOD'] = 'get';
$request = new League\OAuth2\Server\Util\Request($_GET, array(), array(), array(), $_SERVER);
$s->setRequest($request);
$request = new League\OAuth2\Server\Util\Request($_GET, array(), array(), array(), $_SERVER);
$s->setRequest($request);
$reflector = new ReflectionClass($s);
$method = $reflector->getMethod('determineAccessToken');
$method->setAccessible(true);
$reflector = new ReflectionClass($s);
$method = $reflector->getMethod('determineAccessToken');
$method->setAccessible(true);
$result = $method->invoke($s);
$result = $method->invoke($s);
$this->assertEquals('abcdef', $result);
$this->assertEquals('abcdef', $result);
}
public function test_hasScope_isRequired()
{
$s = $this->returnDefault();
$reflector = new ReflectionClass($s);
$param = $reflector->getProperty('sessionScopes');
$param->setAccessible(true);
$param->setValue($s, array(
'a', 'b', 'c'
));
$result = $s->hasScope(array('a', 'b'), true);
$this->assertEquals(true, $result);
}
/**
* @expectedException League\OAuth2\Server\Exception\InsufficientScopeException
*/
public function test_hasScope_isRequiredFailure()
{
$s = $this->returnDefault();
$reflector = new ReflectionClass($s);
$param = $reflector->getProperty('sessionScopes');
$param->setAccessible(true);
$param->setValue($s, array(
'a', 'b', 'c'
));
$s->hasScope('d', true);
}
/**
@@ -171,9 +230,9 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase
*/
public function test_isValid_notValid()
{
$this->session->shouldReceive('validateAccessToken')->andReturn(false);
$this->session->shouldReceive('validateAccessToken')->andReturn(false);
$request = new League\OAuth2\Server\Util\Request();
$request = new League\OAuth2\Server\Util\Request();
$requestReflector = new ReflectionClass($request);
$param = $requestReflector->getProperty('headers');
$param->setAccessible(true);
@@ -188,19 +247,19 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase
public function test_isValid_valid()
{
$this->session->shouldReceive('validateAccessToken')->andReturn(array(
'session_id' => 1,
'owner_type' => 'user',
'owner_id' => 123,
$this->session->shouldReceive('validateAccessToken')->andReturn(array(
'session_id' => 1,
'owner_type' => 'user',
'owner_id' => 123,
'client_id' => 'testapp'
));
));
$this->session->shouldReceive('getScopes')->andReturn(array(
$this->session->shouldReceive('getScopes')->andReturn(array(
array('scope' => 'foo'),
array('scope' => 'bar')
));
$request = new League\OAuth2\Server\Util\Request();
$request = new League\OAuth2\Server\Util\Request();
$requestReflector = new ReflectionClass($request);
$param = $requestReflector->getProperty('headers');
$param->setAccessible(true);
@@ -211,16 +270,15 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase
$s = $this->returnDefault();
$s->setRequest($request);
$this->assertTrue($s->isValid());
$this->assertEquals(123, $s->getOwnerId());
$this->assertEquals('user', $s->getOwnerType());
$this->assertEquals('abcdef', $s->getAccessToken());
$this->assertTrue($s->isValid());
$this->assertEquals(123, $s->getOwnerId());
$this->assertEquals('user', $s->getOwnerType());
$this->assertEquals('abcdef', $s->getAccessToken());
$this->assertEquals('testapp', $s->getClientId());
$this->assertTrue($s->hasScope('foo'));
$this->assertTrue($s->hasScope('bar'));
$this->assertTrue($s->hasScope(array('foo', 'bar')));
$this->assertFalse($s->hasScope(array('foobar')));
$this->assertFalse($s->hasScope('foobar'));
$this->assertFalse($s->hasScope(new StdClass));
}
}
}

View File

@@ -2,14 +2,14 @@
class RedirectUri_test extends PHPUnit_Framework_TestCase
{
function test_make()
{
$v1 = League\OAuth2\Server\Util\RedirectUri::make('https://foobar/', array('foo'=>'bar'));
$v2 = League\OAuth2\Server\Util\RedirectUri::make('https://foobar/', array('foo'=>'bar'), '#');
$v3 = League\OAuth2\Server\Util\RedirectUri::make('https://foobar/', array('foo'=>'bar', 'bar' => 'foo'));
function test_make()
{
$v1 = League\OAuth2\Server\Util\RedirectUri::make('https://foobar/', array('foo'=>'bar'));
$v2 = League\OAuth2\Server\Util\RedirectUri::make('https://foobar/', array('foo'=>'bar'), '#');
$v3 = League\OAuth2\Server\Util\RedirectUri::make('https://foobar/', array('foo'=>'bar', 'bar' => 'foo'));
$this->assertEquals('https://foobar/?foo=bar', $v1);
$this->assertEquals('https://foobar/#foo=bar', $v2);
$this->assertEquals('https://foobar/?foo=bar&bar=foo', $v3);
}
}
$this->assertEquals('https://foobar/?foo=bar', $v1);
$this->assertEquals('https://foobar/#foo=bar', $v2);
$this->assertEquals('https://foobar/?foo=bar&bar=foo', $v3);
}
}

View File

@@ -2,86 +2,86 @@
class Request_test extends PHPUnit_Framework_TestCase
{
private $request;
private $request;
function setUp()
{
$this->request = new League\OAuth2\Server\Util\Request(
array('foo' => 'bar'),
array('foo' => 'bar'),
array('foo' => 'bar'),
array('foo' => 'bar'),
array('HTTP_HOST' => 'foobar.com')
);
}
function setUp()
{
$this->request = new League\OAuth2\Server\Util\Request(
array('foo' => 'bar'),
array('foo' => 'bar'),
array('foo' => 'bar'),
array('foo' => 'bar'),
array('HTTP_HOST' => 'foobar.com')
);
}
function test_buildFromIndex()
{
$r = new League\OAuth2\Server\Util\Request();
$r->buildFromGlobals();
function test_buildFromIndex()
{
$r = new League\OAuth2\Server\Util\Request();
$r->buildFromGlobals();
$this->assertTrue($r instanceof League\OAuth2\Server\Util\Request);
}
$this->assertTrue($r instanceof League\OAuth2\Server\Util\Request);
}
function test_get()
{
$this->assertEquals('bar', $this->request->get('foo'));
$this->assertEquals(array('foo' => 'bar'), $this->request->get());
}
function test_get()
{
$this->assertEquals('bar', $this->request->get('foo'));
$this->assertEquals(array('foo' => 'bar'), $this->request->get());
}
function test_post()
{
$this->assertEquals('bar', $this->request->post('foo'));
$this->assertEquals(array('foo' => 'bar'), $this->request->post());
}
function test_post()
{
$this->assertEquals('bar', $this->request->post('foo'));
$this->assertEquals(array('foo' => 'bar'), $this->request->post());
}
function test_file()
{
$this->assertEquals('bar', $this->request->file('foo'));
$this->assertEquals(array('foo' => 'bar'), $this->request->file());
}
function test_file()
{
$this->assertEquals('bar', $this->request->file('foo'));
$this->assertEquals(array('foo' => 'bar'), $this->request->file());
}
function test_cookie()
{
$this->assertEquals('bar', $this->request->cookie('foo'));
$this->assertEquals(array('foo' => 'bar'), $this->request->cookie());
}
function test_cookie()
{
$this->assertEquals('bar', $this->request->cookie('foo'));
$this->assertEquals(array('foo' => 'bar'), $this->request->cookie());
}
function test_server()
{
$this->assertEquals('foobar.com', $this->request->server('HTTP_HOST'));
$this->assertEquals(array('HTTP_HOST' => 'foobar.com'), $this->request->server());
}
function test_server()
{
$this->assertEquals('foobar.com', $this->request->server('HTTP_HOST'));
$this->assertEquals(array('HTTP_HOST' => 'foobar.com'), $this->request->server());
}
function test_header()
{
$this->assertEquals('foobar.com', $this->request->header('Host'));
$this->assertEquals(array('Host' => 'foobar.com'), $this->request->header());
}
function test_header()
{
$this->assertEquals('foobar.com', $this->request->header('Host'));
$this->assertEquals(array('Host' => 'foobar.com'), $this->request->header());
}
function test_canonical_header()
{
$request = new League\OAuth2\Server\Util\Request(
array('foo' => 'bar'),
array('foo' => 'bar'),
array('foo' => 'bar'),
array('foo' => 'bar'),
array('HTTP_HOST' => 'foobar.com'),
array('authorization' => 'Bearer ajdfkljadslfjasdlkj')
);
function test_canonical_header()
{
$request = new League\OAuth2\Server\Util\Request(
array('foo' => 'bar'),
array('foo' => 'bar'),
array('foo' => 'bar'),
array('foo' => 'bar'),
array('HTTP_HOST' => 'foobar.com'),
array('authorization' => 'Bearer ajdfkljadslfjasdlkj')
);
$this->assertEquals('Bearer ajdfkljadslfjasdlkj', $request->header('Authorization'));
}
$this->assertEquals('Bearer ajdfkljadslfjasdlkj', $request->header('Authorization'));
}
/**
* @expectedException InvalidArgumentException
*/
function test_unknownProperty()
{
$reflector = new ReflectionClass($this->request);
$method = $reflector->getMethod('getPropertyValue');
$method->setAccessible(true);
/**
* @expectedException InvalidArgumentException
*/
function test_unknownProperty()
{
$reflector = new ReflectionClass($this->request);
$method = $reflector->getMethod('getPropertyValue');
$method->setAccessible(true);
$method->invoke($this->request, 'blah');
}
}
$method->invoke($this->request, 'blah');
}
}

View File

@@ -2,14 +2,31 @@
class Secure_Key_test extends PHPUnit_Framework_TestCase
{
function test_make()
{
$v1 = League\OAuth2\Server\Util\SecureKey::make();
$v2 = League\OAuth2\Server\Util\SecureKey::make();
$v3 = League\OAuth2\Server\Util\SecureKey::make(50);
function test_make()
{
$v1 = League\OAuth2\Server\Util\SecureKey::make();
$v2 = League\OAuth2\Server\Util\SecureKey::make();
$v3 = League\OAuth2\Server\Util\SecureKey::make(50);
$this->assertEquals(40, strlen($v1));
$this->assertTrue($v1 !== $v2);
$this->assertEquals(50, strlen($v3));
}
}
$this->assertEquals(40, strlen($v1));
$this->assertTrue($v1 !== $v2);
$this->assertEquals(50, strlen($v3));
}
public function test_make_with_different_algorithm()
{
$algorithm = $this->getMock('League\OAuth2\Server\Util\KeyAlgorithm\KeyAlgorithmInterface');
$result = 'dasdsdsaads';
$algorithm
->expects($this->once())
->method('make')
->with(11)
->will($this->returnValue($result))
;
League\OAuth2\Server\Util\SecureKey::setAlgorithm($algorithm);
$this->assertSame($algorithm, League\OAuth2\Server\Util\SecureKey::getAlgorithm());
$this->assertEquals($result, League\OAuth2\Server\Util\SecureKey::make(11));
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* Created by PhpStorm.
* User: jderay
* Date: 3/11/14
* Time: 12:31 PM
*/
class Default_Algorithm_test extends PHPUnit_Framework_TestCase
{
public function test_make()
{
$algorithm = new League\OAuth2\Server\Util\KeyAlgorithm\DefaultAlgorithm();
$v1 = $algorithm->make();
$v2 = $algorithm->make();
$v3 = $algorithm->make(50);
$this->assertEquals(40, strlen($v1));
$this->assertTrue($v1 !== $v2);
$this->assertEquals(50, strlen($v3));
}
}