Compare commits

...

10 Commits
4.1.0 ... 4.1.2

Author SHA1 Message Date
Alex Bilbie
19b64c2e65 Merge pull request #290 from sarciszewski/patch-1
Remove side-effects in hash_equals()
2015-01-01 12:52:03 +00:00
Scott Arciszewski
612775466c Remove side-effects in hash_equals()
This is functionally identical, but without the side-effect of defining a function in the current namespace.

Also, it uses absolute function reference (`\hash_equals` instead of `hash_equals`) because if someone defined `League\OAuth2\Server\TokenType\hash_equals()` elsewhere, it would try that first.

Kudos for using `hash_equals()` in your original design for this feature. Many OAuth2 implementations neglect this nuance :)
2015-01-01 01:34:22 -05:00
Alex Bilbie
740ea24e08 Changelog update 2014-12-31 16:03:26 +00:00
Alex Bilbie
e1c14abf6c Lowered symfony/http-foundation to ~2.4 so Laravel can use it 2014-12-31 15:51:52 +00:00
Alex Bilbie
d1aae27359 Version bump 2014-12-27 23:01:11 +00:00
Alex Bilbie
80aeaf9200 Merge branch 'Symplicity-master' into release/4.1.0 2014-12-27 23:00:17 +00:00
Alex Bilbie
282bb20cc8 Fix docblocks + method name 2014-12-27 23:00:11 +00:00
Alex Bilbie
b727be55a2 Merge branch 'master' of https://github.com/Symplicity/oauth2-server into Symplicity-master 2014-12-27 22:57:08 +00:00
Alex Bilbie
cf80a2d6ce README update 2014-12-27 22:55:30 +00:00
Dave Walker
851c7c0eb1 Per the spec:
The authorization server MAY issue a new refresh token, in which case
   the client MUST discard the old refresh token and replace it with the
   new refresh token.  The authorization server MAY revoke the old
   refresh token after issuing a new refresh token to the client.  If a
   new refresh token is issued, the refresh token scope MUST be
   identical to that of the refresh token included by the client in the
   request.

This commit allows users to specifiy the time before the Refresh Token
expire time to issue a new Refresh Token.

alter method names, naming convention(?)
2014-12-21 18:51:52 -05:00
6 changed files with 143 additions and 27 deletions

View File

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

View File

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

View File

@@ -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": {

View File

@@ -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();
}

View File

@@ -128,22 +128,18 @@ class MAC extends AbstractTokenType implements TokenTypeInterface
*/
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;
}
if (function_exists('\hash_equals')) {
return \hash_equals($knownString, $userString);
}
return 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;
}
}

View File

@@ -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']);
}
}