mirror of
https://github.com/elyby/oauth2-server.git
synced 2025-05-31 14:12:07 +05:30
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
740ea24e08 | ||
|
e1c14abf6c | ||
|
d1aae27359 | ||
|
80aeaf9200 | ||
|
282bb20cc8 | ||
|
b727be55a2 | ||
|
cf80a2d6ce | ||
|
72a5c1794a | ||
|
707c85b0d6 | ||
|
c56562b0b8 | ||
|
d0b2498b43 | ||
|
17be6f4549 | ||
|
b50fbff1e3 | ||
|
7375a348c6 | ||
|
ae5dd9ce65 | ||
|
f9e56ff62a | ||
|
1bcf7ee20f | ||
|
bee9c6a51d | ||
|
851c7c0eb1 | ||
|
7fff4a8fe8 | ||
|
44ac01ee0e | ||
|
60bd334b46 | ||
|
2653a174bb | ||
|
676fb4c06a |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -11,4 +11,5 @@
|
||||
/tests/codecept/tests/_log
|
||||
oauth2-server.paw
|
||||
/output_*/
|
||||
/_site
|
||||
/_site
|
||||
.idea
|
10
.travis.yml
10
.travis.yml
@@ -33,4 +33,12 @@ branches:
|
||||
- master
|
||||
env:
|
||||
global:
|
||||
secure: "C4wD/BQefKSu9W594iyLp+IBCjlM8kKlmp+nXKXnZGi0L8IkV3m4mmNOb8PExxGMhZ3mlev5DnU4Uoh4oJaUxnkR1FpX4dSEpyzU3VknUzSE2yZOlL+bdCw3o85TGoCcp/+ReJCOw5sncxTskJKHlW1YMa33FznaXwLNoImpjTg="
|
||||
secure: "C4wD/BQefKSu9W594iyLp+IBCjlM8kKlmp+nXKXnZGi0L8IkV3m4mmNOb8PExxGMhZ3mlev5DnU4Uoh4oJaUxnkR1FpX4dSEpyzU3VknUzSE2yZOlL+bdCw3o85TGoCcp/+ReJCOw5sncxTskJKHlW1YMa33FznaXwLNoImpjTg="
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/7de0ca12596cd5268f30
|
||||
on_success: always # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
||||
|
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,5 +1,16 @@
|
||||
# Changelog
|
||||
|
||||
## 4.1.1 (released 2014-12-31)
|
||||
|
||||
* Changed `symfony/http-foundation` dependency version to `~2.4` so package can be installed in Laravel `4.1.*`
|
||||
|
||||
## 4.1.0 (released 2014-12-27)
|
||||
|
||||
* Added MAC token support (Issue #158)
|
||||
* Fixed example init code (Issue #280)
|
||||
* Toggle refresh token rotation (Issue #286)
|
||||
* Docblock fixes
|
||||
|
||||
## 4.0.5 (released 2014-12-15)
|
||||
|
||||
* Prevent duplicate session in auth code grant (Issue #282)
|
||||
|
@@ -5,7 +5,7 @@
|
||||
[](https://travis-ci.org/thephpleague/oauth2-server)
|
||||
[](https://scrutinizer-ci.com/g/thephpleague/oauth2-server/code-structure)
|
||||
[](https://scrutinizer-ci.com/g/thephpleague/oauth2-server)
|
||||
[](https://packagist.org/packages/league/oauth2-server)
|
||||
[](https://packagist.org/packages/league/oauth2-server) [](https://gitter.im/thephpleague/oauth2-server?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
||||
|
||||
A standards compliant [OAuth 2.0](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-v2/) authorization server and resource server written in PHP which makes working with OAuth 2.0 trivial. You can easily configure an OAuth 2.0 server to protect your API with access tokens, or allow clients to request new access tokens and refresh them.
|
||||
@@ -22,9 +22,11 @@ You can also define your own grants.
|
||||
In addition it supports the following token types:
|
||||
|
||||
* Bearer tokens
|
||||
* MAC tokens (coming soon)
|
||||
* MAC tokens
|
||||
* JSON web tokens (coming soon)
|
||||
|
||||
You can also create you own tokens.
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": ">=5.4.0",
|
||||
"symfony/http-foundation": "~2.5",
|
||||
"symfony/http-foundation": "~2.4",
|
||||
"league/event": "1.0.*"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@@ -102,7 +102,7 @@ Capsule::table('oauth_scopes')->insert([
|
||||
print 'Creating sessions table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('oauth_sessions', function ($table) {
|
||||
$table->increments('id');
|
||||
$table->increments('id')->unsigned();
|
||||
$table->string('owner_type');
|
||||
$table->string('owner_id');
|
||||
$table->string('client_id');
|
||||
@@ -135,7 +135,7 @@ print 'Creating access tokens table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('oauth_access_tokens', function ($table) {
|
||||
$table->string('access_token')->primary();
|
||||
$table->integer('session_id');
|
||||
$table->integer('session_id')->unsigned();
|
||||
$table->integer('expire_time');
|
||||
|
||||
$table->foreign('session_id')->references('id')->on('oauth_sessions')->onDelete('cascade');
|
||||
@@ -168,7 +168,7 @@ Capsule::schema()->create('oauth_refresh_tokens', function ($table) {
|
||||
$table->integer('expire_time');
|
||||
$table->string('access_token');
|
||||
|
||||
$table->foreign('access_token')->references('id')->on('oauth_access_tokens')->onDelete('cascade');
|
||||
$table->foreign('access_token')->references('access_token')->on('oauth_access_tokens')->onDelete('cascade');
|
||||
});
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -177,7 +177,7 @@ print 'Creating auth codes table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('oauth_auth_codes', function ($table) {
|
||||
$table->string('auth_code')->primary();
|
||||
$table->integer('session_id');
|
||||
$table->integer('session_id')->unsigned();
|
||||
$table->integer('expire_time');
|
||||
$table->string('client_redirect_uri');
|
||||
|
||||
@@ -189,7 +189,7 @@ Capsule::schema()->create('oauth_auth_codes', function ($table) {
|
||||
print 'Creating oauth access token scopes table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('oauth_access_token_scopes', function ($table) {
|
||||
$table->increments('id');
|
||||
$table->increments('id')->unsigned();
|
||||
$table->string('access_token');
|
||||
$table->string('scope');
|
||||
|
||||
@@ -240,8 +240,8 @@ Capsule::schema()->create('oauth_auth_code_scopes', function ($table) {
|
||||
print 'Creating oauth session scopes table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('oauth_session_scopes', function ($table) {
|
||||
$table->increments('id');
|
||||
$table->string('session_id');
|
||||
$table->increments('id')->unsigned();
|
||||
$table->integer('session_id')->unsigned();
|
||||
$table->string('scope');
|
||||
|
||||
$table->foreign('session_id')->references('id')->on('oauth_sessions')->onDelete('cascade');
|
||||
|
@@ -15,6 +15,7 @@ use League\Event\Emitter;
|
||||
use League\OAuth2\Server\Storage\AccessTokenInterface;
|
||||
use League\OAuth2\Server\Storage\AuthCodeInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\MacTokenInterface;
|
||||
use League\OAuth2\Server\Storage\RefreshTokenInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
@@ -75,6 +76,11 @@ abstract class AbstractServer
|
||||
*/
|
||||
protected $clientStorage;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Storage\MacTokenInterface
|
||||
*/
|
||||
protected $macStorage;
|
||||
|
||||
/**
|
||||
* Token type
|
||||
*
|
||||
@@ -332,4 +338,20 @@ abstract class AbstractServer
|
||||
{
|
||||
return $this->tokenType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MacTokenInterface
|
||||
*/
|
||||
public function getMacStorage()
|
||||
{
|
||||
return $this->macStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MacTokenInterface $macStorage
|
||||
*/
|
||||
public function setMacStorage(MacTokenInterface $macStorage)
|
||||
{
|
||||
$this->macStorage = $macStorage;
|
||||
}
|
||||
}
|
||||
|
@@ -181,7 +181,7 @@ class AuthorizationServer extends AbstractServer
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the "state" paremter in checkAuthoriseParams()
|
||||
* Require the "state" parameter in checkAuthoriseParams()
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
@@ -191,7 +191,7 @@ class AuthorizationServer extends AbstractServer
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the "state" paremter in checkAuthoriseParams()
|
||||
* Require the "state" parameter in checkAuthoriseParams()
|
||||
*
|
||||
* @param boolean $require
|
||||
*
|
||||
|
@@ -35,6 +35,13 @@ class RefreshTokenGrant extends AbstractGrant
|
||||
*/
|
||||
protected $refreshTokenTTL = 604800;
|
||||
|
||||
/**
|
||||
* Rotate token (default = true)
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $refreshTokenRotate = true;
|
||||
|
||||
/**
|
||||
* Set the TTL of the refresh token
|
||||
*
|
||||
@@ -57,6 +64,25 @@ class RefreshTokenGrant extends AbstractGrant
|
||||
return $this->refreshTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rotation boolean of the refresh token
|
||||
* @param bool $refreshTokenRotate
|
||||
*/
|
||||
public function setRefreshTokenRotation($refreshTokenRotate = true)
|
||||
{
|
||||
$this->refreshTokenRotate = $refreshTokenRotate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rotation boolean of the refresh token
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldRotateRefreshTokens()
|
||||
{
|
||||
return $this->refreshTokenRotate;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -146,17 +172,21 @@ class RefreshTokenGrant extends AbstractGrant
|
||||
$this->server->getTokenType()->setParam('access_token', $newAccessToken->getId());
|
||||
$this->server->getTokenType()->setParam('expires_in', $this->getAccessTokenTTL());
|
||||
|
||||
// Expire the old refresh token
|
||||
$oldRefreshToken->expire();
|
||||
if ($this->shouldRotateRefreshTokens()) {
|
||||
// Expire the old refresh token
|
||||
$oldRefreshToken->expire();
|
||||
|
||||
// Generate a new refresh token
|
||||
$newRefreshToken = new RefreshTokenEntity($this->server);
|
||||
$newRefreshToken->setId(SecureKey::generate());
|
||||
$newRefreshToken->setExpireTime($this->getRefreshTokenTTL() + time());
|
||||
$newRefreshToken->setAccessToken($newAccessToken);
|
||||
$newRefreshToken->save();
|
||||
// Generate a new refresh token
|
||||
$newRefreshToken = new RefreshTokenEntity($this->server);
|
||||
$newRefreshToken->setId(SecureKey::generate());
|
||||
$newRefreshToken->setExpireTime($this->getRefreshTokenTTL() + time());
|
||||
$newRefreshToken->setAccessToken($newAccessToken);
|
||||
$newRefreshToken->save();
|
||||
|
||||
$this->server->getTokenType()->setParam('refresh_token', $newRefreshToken->getId());
|
||||
$this->server->getTokenType()->setParam('refresh_token', $newRefreshToken->getId());
|
||||
} else {
|
||||
$this->server->getTokenType()->setParam('refresh_token', $oldRefreshToken->getId());
|
||||
}
|
||||
|
||||
return $this->server->getTokenType()->generateResponse();
|
||||
}
|
||||
|
34
src/Storage/MacTokenInterface.php
Normal file
34
src/Storage/MacTokenInterface.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 MAC Token Interface
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Storage;
|
||||
|
||||
|
||||
/**
|
||||
* MacTokenInterface
|
||||
*/
|
||||
interface MacTokenInterface extends StorageInterface
|
||||
{
|
||||
/**
|
||||
* Create a MAC key linked to an access token
|
||||
* @param string $macKey
|
||||
* @param string $accessToken
|
||||
* @return void
|
||||
*/
|
||||
public function create($macKey, $accessToken);
|
||||
|
||||
/**
|
||||
* Get a MAC key by access token
|
||||
* @param string $accessToken
|
||||
* @return string
|
||||
*/
|
||||
public function getByAccessToken($accessToken);
|
||||
}
|
149
src/TokenType/MAC.php
Normal file
149
src/TokenType/MAC.php
Normal file
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 MAC Token Type
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\TokenType;
|
||||
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* MAC Token Type
|
||||
*/
|
||||
class MAC extends AbstractTokenType implements TokenTypeInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function generateResponse()
|
||||
{
|
||||
$macKey = SecureKey::generate();
|
||||
$this->server->getMacStorage()->create($macKey, $this->getParam('access_token'));
|
||||
|
||||
$response = [
|
||||
'access_token' => $this->getParam('access_token'),
|
||||
'token_type' => 'mac',
|
||||
'expires_in' => $this->getParam('expires_in'),
|
||||
'mac_key' => $macKey,
|
||||
'mac_algorithm' => 'hmac-sha-256',
|
||||
];
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function determineAccessTokenInHeader(Request $request)
|
||||
{
|
||||
if ($request->headers->has('Authorization') === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$header = $request->headers->get('Authorization');
|
||||
|
||||
if (substr($header, 0, 4) !== 'MAC ') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find all the parameters expressed in the header
|
||||
$paramsRaw = explode(',', substr($header, 4));
|
||||
$params = new ParameterBag();
|
||||
|
||||
array_map(function ($param) use (&$params) {
|
||||
$param = trim($param);
|
||||
|
||||
preg_match_all('/([a-zA-Z]*)="([\w=]*)"/', $param, $matches);
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
if (count($matches) !== 3) {
|
||||
return;
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
$key = reset($matches[1]);
|
||||
$value = trim(reset($matches[2]));
|
||||
|
||||
if (empty($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$params->set($key, $value);
|
||||
}, $paramsRaw);
|
||||
|
||||
// Validate parameters
|
||||
if ($params->has('id') === false || $params->has('ts') === false || $params->has('nonce') === false || $params->has('mac') === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int) $params->get('ts') !== time()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$accessToken = $params->get('id');
|
||||
$timestamp = (int) $params->get('ts');
|
||||
$nonce = $params->get('nonce');
|
||||
$signature = $params->get('mac');
|
||||
|
||||
// Try to find the MAC key for the access token
|
||||
$macKey = $this->server->getMacStorage()->getByAccessToken($accessToken);
|
||||
|
||||
if ($macKey === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate and compare the signature
|
||||
$calculatedSignatureParts = [
|
||||
$timestamp,
|
||||
$nonce,
|
||||
strtoupper($request->getMethod()),
|
||||
$request->getUri(),
|
||||
$request->getHost(),
|
||||
$request->getPort(),
|
||||
];
|
||||
|
||||
if ($params->has('ext')) {
|
||||
$calculatedSignatureParts[] = $params->get('ext');
|
||||
}
|
||||
|
||||
$calculatedSignature = base64_encode(hash_hmac('sha256', implode("\n", $calculatedSignatureParts), $macKey));
|
||||
|
||||
// Return the access token if the signature matches
|
||||
return ($this->hash_equals($calculatedSignature, $signature)) ? $accessToken : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent timing attack
|
||||
* @param string $knownString
|
||||
* @param string $userString
|
||||
* @return bool
|
||||
*/
|
||||
private function hash_equals($knownString, $userString)
|
||||
{
|
||||
if (!function_exists('hash_equals')) {
|
||||
function hash_equals($knownString, $userString)
|
||||
{
|
||||
if (strlen($knownString) !== strlen($userString)) {
|
||||
return false;
|
||||
}
|
||||
$len = strlen($knownString);
|
||||
$result = 0;
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$result |= (ord($knownString[$i]) ^ ord($userString[$i]));
|
||||
}
|
||||
// They are only identical strings if $result is exactly 0...
|
||||
return 0 === $result;
|
||||
}
|
||||
}
|
||||
|
||||
return hash_equals($knownString, $userString);
|
||||
}
|
||||
}
|
@@ -421,4 +421,81 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$server->issueAccessToken();
|
||||
}
|
||||
|
||||
public function testCompleteFlowRotateRefreshToken()
|
||||
{
|
||||
$_POST = [
|
||||
'grant_type' => 'refresh_token',
|
||||
'client_id' => 'testapp',
|
||||
'client_secret' => 'foobar',
|
||||
'refresh_token' => 'refresh_token',
|
||||
];
|
||||
|
||||
$server = new AuthorizationServer();
|
||||
$grant = new RefreshTokenGrant();
|
||||
|
||||
$clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface');
|
||||
$clientStorage->shouldReceive('setServer');
|
||||
$clientStorage->shouldReceive('get')->andReturn(
|
||||
(new ClientEntity($server))->hydrate(['id' => 'testapp'])
|
||||
);
|
||||
|
||||
$sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface');
|
||||
$sessionStorage->shouldReceive('setServer');
|
||||
$sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]);
|
||||
$sessionStorage->shouldReceive('associateScope');
|
||||
$sessionStorage->shouldReceive('getByAccessToken')->andReturn(
|
||||
(new SessionEntity($server))
|
||||
);
|
||||
|
||||
$accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface');
|
||||
$accessTokenStorage->shouldReceive('setServer');
|
||||
$accessTokenStorage->shouldReceive('get')->andReturn(
|
||||
(new AccessTokenEntity($server))
|
||||
);
|
||||
$accessTokenStorage->shouldReceive('delete');
|
||||
$accessTokenStorage->shouldReceive('create');
|
||||
$accessTokenStorage->shouldReceive('getScopes')->andReturn([
|
||||
(new ScopeEntity($server))->hydrate(['id' => 'foo']),
|
||||
]);
|
||||
$accessTokenStorage->shouldReceive('associateScope');
|
||||
|
||||
$refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface');
|
||||
$refreshTokenStorage->shouldReceive('setServer');
|
||||
$refreshTokenStorage->shouldReceive('associateScope');
|
||||
$refreshTokenStorage->shouldReceive('delete');
|
||||
$refreshTokenStorage->shouldReceive('create');
|
||||
$refreshTokenStorage->shouldReceive('get')->andReturn(
|
||||
(new RefreshTokenEntity($server))->setId('refresh_token')->setExpireTime(time() + 86400)
|
||||
);
|
||||
|
||||
$scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface');
|
||||
$scopeStorage->shouldReceive('setServer');
|
||||
$scopeStorage->shouldReceive('get')->andReturn(
|
||||
(new ScopeEntity($server))->hydrate(['id' => 'foo'])
|
||||
);
|
||||
|
||||
$server->setClientStorage($clientStorage);
|
||||
$server->setScopeStorage($scopeStorage);
|
||||
$server->setSessionStorage($sessionStorage);
|
||||
$server->setAccessTokenStorage($accessTokenStorage);
|
||||
$server->setRefreshTokenStorage($refreshTokenStorage);
|
||||
|
||||
$server->addGrantType($grant);
|
||||
|
||||
$response = $server->issueAccessToken();
|
||||
$this->assertTrue(array_key_exists('access_token', $response));
|
||||
$this->assertTrue(array_key_exists('refresh_token', $response));
|
||||
$this->assertTrue(array_key_exists('token_type', $response));
|
||||
$this->assertTrue(array_key_exists('expires_in', $response));
|
||||
$this->assertNotEquals($response['refresh_token'], $_POST['refresh_token']);
|
||||
|
||||
$grant->setRefreshTokenRotation(false);
|
||||
$response = $server->issueAccessToken();
|
||||
$this->assertTrue(array_key_exists('access_token', $response));
|
||||
$this->assertTrue(array_key_exists('refresh_token', $response));
|
||||
$this->assertTrue(array_key_exists('token_type', $response));
|
||||
$this->assertTrue(array_key_exists('expires_in', $response));
|
||||
$this->assertEquals($response['refresh_token'], $_POST['refresh_token']);
|
||||
}
|
||||
}
|
||||
|
165
tests/unit/TokenType/MacTest.php
Normal file
165
tests/unit/TokenType/MacTest.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
namespace LeagueTests\TokenType;
|
||||
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\Entity\AccessTokenEntity;
|
||||
use League\OAuth2\Server\TokenType\MAC;
|
||||
use Mockery as M;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class MacTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testGenerateResponse()
|
||||
{
|
||||
$macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface');
|
||||
$macStorage->shouldReceive('create');
|
||||
|
||||
$server = new AuthorizationServer();
|
||||
$server->setMacStorage($macStorage);
|
||||
|
||||
$tokenType = new MAC();
|
||||
$tokenType->setServer($server);
|
||||
|
||||
$accessToken = new AccessTokenEntity($server);
|
||||
$accessToken->setId(uniqid());
|
||||
$accessToken->setExpireTime(time());
|
||||
|
||||
$tokenType->setParam('access_token', $accessToken->getId());
|
||||
$tokenType->setParam('expires_in', 3600);
|
||||
|
||||
$response = $tokenType->generateResponse();
|
||||
|
||||
$this->assertEquals($accessToken->getId(), $response['access_token']);
|
||||
$this->assertEquals('mac', $response['token_type']);
|
||||
$this->assertEquals(3600, $response['expires_in']);
|
||||
$this->assertEquals('hmac-sha-256', $response['mac_algorithm']);
|
||||
$this->assertArrayHasKey('mac_key', $response);
|
||||
}
|
||||
|
||||
public function testDetermineAccessTokenInHeaderValid()
|
||||
{
|
||||
$macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface');
|
||||
$macStorage->shouldReceive('getByAccessToken')->andReturn('abcdef');
|
||||
|
||||
$server = new AuthorizationServer();
|
||||
$server->setMacStorage($macStorage);
|
||||
|
||||
$ts = time();
|
||||
|
||||
$request = Request::createFromGlobals();
|
||||
$calculatedSignatureParts = [
|
||||
$ts,
|
||||
'foo',
|
||||
strtoupper($request->getMethod()),
|
||||
$request->getUri(),
|
||||
$request->getHost(),
|
||||
$request->getPort(),
|
||||
'ext'
|
||||
];
|
||||
$calculatedSignature = base64_encode(hash_hmac('sha256', implode("\n", $calculatedSignatureParts), 'abcdef'));
|
||||
|
||||
$request->headers->set('Authorization', sprintf('MAC id="foo", nonce="foo", ts="%s", mac="%s", ext="ext"', $ts, $calculatedSignature));
|
||||
|
||||
$tokenType = new MAC();
|
||||
$tokenType->setServer($server);
|
||||
|
||||
$response = $tokenType->determineAccessTokenInHeader($request);
|
||||
$this->assertEquals('foo', $response);
|
||||
}
|
||||
|
||||
public function testDetermineAccessTokenInHeaderMissingHeader()
|
||||
{
|
||||
$macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface');
|
||||
$macStorage->shouldReceive('getByAccessToken')->andReturn('abcdef');
|
||||
|
||||
$server = new AuthorizationServer();
|
||||
$server->setMacStorage($macStorage);
|
||||
|
||||
$request = Request::createFromGlobals();
|
||||
$tokenType = new MAC();
|
||||
$tokenType->setServer($server);
|
||||
|
||||
$response = $tokenType->determineAccessTokenInHeader($request);
|
||||
|
||||
$this->assertEquals(null, $response);
|
||||
}
|
||||
|
||||
public function testDetermineAccessTokenInHeaderMissingAuthMac()
|
||||
{
|
||||
$macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface');
|
||||
$macStorage->shouldReceive('getByAccessToken')->andReturn('abcdef');
|
||||
|
||||
$server = new AuthorizationServer();
|
||||
$server->setMacStorage($macStorage);
|
||||
|
||||
$request = Request::createFromGlobals();
|
||||
$request->headers->set('Authorization', '');
|
||||
|
||||
$tokenType = new MAC();
|
||||
$tokenType->setServer($server);
|
||||
|
||||
$response = $tokenType->determineAccessTokenInHeader($request);
|
||||
|
||||
$this->assertEquals(null, $response);
|
||||
}
|
||||
|
||||
public function testDetermineAccessTokenInHeaderInvalidParam()
|
||||
{
|
||||
$macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface');
|
||||
$macStorage->shouldReceive('getByAccessToken')->andReturn('abcdef');
|
||||
|
||||
$server = new AuthorizationServer();
|
||||
$server->setMacStorage($macStorage);
|
||||
|
||||
$request = Request::createFromGlobals();
|
||||
$request->headers->set('Authorization', 'MAC ');
|
||||
|
||||
$tokenType = new MAC();
|
||||
$tokenType->setServer($server);
|
||||
|
||||
$response = $tokenType->determineAccessTokenInHeader($request);
|
||||
|
||||
$this->assertEquals(null, $response);
|
||||
}
|
||||
|
||||
public function testDetermineAccessTokenInHeaderMismatchTimestamp()
|
||||
{
|
||||
$macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface');
|
||||
$macStorage->shouldReceive('getByAccessToken')->andReturn('abcdef');
|
||||
|
||||
$server = new AuthorizationServer();
|
||||
$server->setMacStorage($macStorage);
|
||||
|
||||
$ts = time() - 100;
|
||||
|
||||
$request = Request::createFromGlobals();
|
||||
$request->headers->set('Authorization', sprintf('MAC id="foo", nonce="foo", ts="%s", mac="%s", ext="ext"', $ts, 'foo'));
|
||||
|
||||
$tokenType = new MAC();
|
||||
$tokenType->setServer($server);
|
||||
|
||||
$response = $tokenType->determineAccessTokenInHeader($request);
|
||||
$this->assertEquals(null, $response);
|
||||
}
|
||||
|
||||
public function testDetermineAccessTokenInHeaderMissingMacKey()
|
||||
{
|
||||
$macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface');
|
||||
$macStorage->shouldReceive('getByAccessToken')->andReturn(null);
|
||||
|
||||
$server = new AuthorizationServer();
|
||||
$server->setMacStorage($macStorage);
|
||||
|
||||
$ts = time();
|
||||
|
||||
$request = Request::createFromGlobals();
|
||||
$request->headers->set('Authorization', sprintf('MAC id="foo", nonce="foo", ts="%s", mac="%s", ext="ext"', $ts, 'foo'));
|
||||
|
||||
$tokenType = new MAC();
|
||||
$tokenType->setServer($server);
|
||||
|
||||
$response = $tokenType->determineAccessTokenInHeader($request);
|
||||
$this->assertEquals(null, $response);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user