Merge branch 'release/2.1'

This commit is contained in:
Alex Bilbie 2013-05-10 17:59:29 -07:00
commit 5d0b295a82
19 changed files with 580 additions and 87 deletions

View File

@ -1,5 +1,16 @@
# Changelog # Changelog
## 2.1 (released 2013-05-10)
* Moved zetacomponents/database to "suggest" in composer.json. If you rely on this feature you now need to include " zetacomponents/database" into "require" key in your own composer.json. (Issue #51)
* New method in Refresh grant called `rotateRefreshTokens()`. Pass in `true` to issue a new refresh token each time an access token is refreshed. This parameter needs to be set to true in order to request reduced scopes with the new access token. (Issue #47)
* Rename `key` column in oauth_scopes table to `scope` as `key` is a reserved SQL word. (Issue #45)
* The `scope` parameter is no longer required by default as per the RFC. (Issue #43)
* You can now set multiple default scopes by passing an array into `setDefaultScope()`. (Issue #42)
* The password and client credentials grants now allow for multiple sessions per user. (Issue #32)
* Scopes associated to authorization codes are not held in their own table (Issue #44)
* Database schema updates.
## 2.0.5 (released 2013-05-09) ## 2.0.5 (released 2013-05-09)
* Fixed `oauth_session_token_scopes` table primary key * Fixed `oauth_session_token_scopes` table primary key

View File

@ -1,12 +1,11 @@
{ {
"name": "league/oauth2-server", "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.", "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": "2.0.5", "version": "2.1",
"homepage": "https://github.com/php-loep/oauth2-server", "homepage": "https://github.com/php-loep/oauth2-server",
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": ">=5.3.0", "php": ">=5.3.0"
"zetacomponents/database": "dev-master"
}, },
"require-dev": { "require-dev": {
"mockery/mockery": ">=0.7.2" "mockery/mockery": ">=0.7.2"
@ -43,5 +42,7 @@
"League\\OAuth2\\Server": "src/" "League\\OAuth2\\Server": "src/"
} }
}, },
"suggest": {} "suggest": {
"zetacomponents/database": "Allows use of the build in PDO storage classes"
}
} }

View File

@ -38,12 +38,13 @@ CREATE TABLE `oauth_session_access_tokens` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `oauth_session_authcodes` ( CREATE TABLE `oauth_session_authcodes` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`session_id` int(10) unsigned NOT NULL, `session_id` int(10) unsigned NOT NULL,
`auth_code` char(40) NOT NULL, `auth_code` char(40) NOT NULL,
`auth_code_expires` int(10) unsigned NOT NULL, `auth_code_expires` int(10) unsigned NOT NULL,
`scope_ids` char(255) DEFAULT NULL, PRIMARY KEY (`id`),
PRIMARY KEY (`session_id`), KEY `session_id` (`session_id`),
CONSTRAINT `f_oaseau_seid` FOREIGN KEY (`session_id`) REFERENCES `oauth_sessions` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION 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;
CREATE TABLE `oauth_session_redirects` ( CREATE TABLE `oauth_session_redirects` (
@ -65,13 +66,13 @@ CREATE TABLE `oauth_session_refresh_tokens` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `oauth_scopes` ( CREATE TABLE `oauth_scopes` (
`id` SMALLINT(5) UNSIGNED NOT NULL AUTO_INCREMENT, `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`key` VARCHAR(255) NOT NULL, `scope` varchar(255) NOT NULL,
`name` VARCHAR(255) NOT NULL, `name` varchar(255) NOT NULL,
`description` VARCHAR(255) DEFAULT NULL, `description` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `u_oasc_sc` (`key`) UNIQUE KEY `u_oasc_sc` (`scope`)
) ENGINE=INNODB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `oauth_session_token_scopes` ( CREATE TABLE `oauth_session_token_scopes` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
@ -83,3 +84,12 @@ CREATE TABLE `oauth_session_token_scopes` (
CONSTRAINT `f_oasetosc_scid` FOREIGN KEY (`scope_id`) REFERENCES `oauth_scopes` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION, 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 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;
CREATE TABLE `oauth_session_authcode_scopes` (
`oauth_session_authcode_id` int(10) unsigned NOT NULL,
`scope_id` smallint(5) unsigned NOT NULL,
KEY `oauth_session_authcode_id` (`oauth_session_authcode_id`),
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;

View File

@ -59,11 +59,11 @@ class Authorization
* Require the "scope" parameter to be in checkAuthoriseParams() * Require the "scope" parameter to be in checkAuthoriseParams()
* @var boolean * @var boolean
*/ */
protected $requireScopeParam = true; protected $requireScopeParam = false;
/** /**
* Default scope to be used if none is provided and requireScopeParam is false * Default scope(s) to be used if none is provided
* @var string * @var string|array
*/ */
protected $defaultScope = null; protected $defaultScope = null;
@ -271,7 +271,7 @@ class Authorization
* @param boolean $require * @param boolean $require
* @return void * @return void
*/ */
public function requireScopeParam($require = true) public function requireScopeParam($require = false)
{ {
$this->requireScopeParam = $require; $this->requireScopeParam = $require;
} }
@ -287,7 +287,7 @@ class Authorization
/** /**
* Default scope to be used if none is provided and requireScopeParam is false * Default scope to be used if none is provided and requireScopeParam is false
* @var string * @var string|array
*/ */
public function setDefaultScope($default = null) public function setDefaultScope($default = null)
{ {

View File

@ -152,11 +152,15 @@ class AuthCode implements GrantTypeInterface {
if ($scopes[$i] === '') unset($scopes[$i]); // Remove any junk scopes if ($scopes[$i] === '') unset($scopes[$i]); // Remove any junk scopes
} }
if ($this->authServer->scopeParamRequired() === true && count($scopes) === 0) { if ($this->authServer->scopeParamRequired() === true && $this->authServer->getDefaultScope() === null && count($scopes) === 0) {
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'scope'), 0); throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'scope'), 0);
} elseif (count($scopes) === 0 && $this->authServer->getDefaultScope()) { } elseif (count($scopes) === 0 && $this->authServer->getDefaultScope() !== null) {
if (is_array($this->authServer->getDefaultScope())) {
$scopes = $this->authServer->getDefaultScope();
} else {
$scopes = array($this->authServer->getDefaultScope()); $scopes = array($this->authServer->getDefaultScope());
} }
}
$authParams['scopes'] = array(); $authParams['scopes'] = array();
@ -189,13 +193,6 @@ class AuthCode implements GrantTypeInterface {
// Remove any old sessions the user might have // Remove any old sessions the user might have
$this->authServer->getStorage('session')->deleteSession($authParams['client_id'], $type, $typeId); $this->authServer->getStorage('session')->deleteSession($authParams['client_id'], $type, $typeId);
// List of scopes IDs
$scopeIds = array();
foreach ($authParams['scopes'] as $scope)
{
$scopeIds[] = $scope['id'];
}
// Create a new session // Create a new session
$sessionId = $this->authServer->getStorage('session')->createSession($authParams['client_id'], $type, $typeId); $sessionId = $this->authServer->getStorage('session')->createSession($authParams['client_id'], $type, $typeId);
@ -203,7 +200,12 @@ class AuthCode implements GrantTypeInterface {
$this->authServer->getStorage('session')->associateRedirectUri($sessionId, $authParams['redirect_uri']); $this->authServer->getStorage('session')->associateRedirectUri($sessionId, $authParams['redirect_uri']);
// Associate the auth code // Associate the auth code
$this->authServer->getStorage('session')->associateAuthCode($sessionId, $authCode, time() + $this->authTokenTTL, implode(',', $scopeIds)); $authCodeId = $this->authServer->getStorage('session')->associateAuthCode($sessionId, $authCode, time() + $this->authTokenTTL);
// Associate the scopes to the auth code
foreach ($authParams['scopes'] as $scope) {
$this->authServer->getStorage('session')->associateAuthCodeScope($authCodeId, $scope['id']);
}
return $authCode; return $authCode;
} }
@ -245,30 +247,30 @@ class AuthCode implements GrantTypeInterface {
} }
// Verify the authorization code matches the client_id and the request_uri // Verify the authorization code matches the client_id and the request_uri
$session = $this->authServer->getStorage('session')->validateAuthCode($authParams['client_id'], $authParams['redirect_uri'], $authParams['code']); $authCodeDetails = $this->authServer->getStorage('session')->validateAuthCode($authParams['client_id'], $authParams['redirect_uri'], $authParams['code']);
if ( ! $session) { if ( ! $authCodeDetails) {
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_grant'), 'code'), 9); throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_grant'), 'code'), 9);
} }
// A session ID was returned so update it with an access token and remove the authorisation code // Get any associated scopes
$scopes = $this->authServer->getStorage('session')->getAuthCodeScopes($authCodeDetails['authcode_id']);
// A session ID was returned so update it with an access token and remove the authorisation code
$accessToken = SecureKey::make(); $accessToken = SecureKey::make();
$accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL(); $accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL();
$accessTokenExpires = time() + $accessTokenExpiresIn; $accessTokenExpires = time() + $accessTokenExpiresIn;
// Remove the auth code // Remove the auth code
$this->authServer->getStorage('session')->removeAuthCode($session['id']); $this->authServer->getStorage('session')->removeAuthCode($authCodeDetails['session_id']);
// Create an access token // Create an access token
$accessTokenId = $this->authServer->getStorage('session')->associateAccessToken($session['id'], $accessToken, $accessTokenExpires); $accessTokenId = $this->authServer->getStorage('session')->associateAccessToken($authCodeDetails['session_id'], $accessToken, $accessTokenExpires);
// Associate scopes with the access token // Associate scopes with the access token
if ( ! is_null($session['scope_ids'])) { if (count($scopes) > 0) {
$scopeIds = explode(',', $session['scope_ids']); foreach ($scopes as $scope) {
$this->authServer->getStorage('session')->associateScope($accessTokenId, $scope['scope_id']);
foreach ($scopeIds as $scopeId) {
$this->authServer->getStorage('session')->associateScope($accessTokenId, $scopeId);
} }
} }

View File

@ -122,11 +122,15 @@ class ClientCredentials implements GrantTypeInterface {
if ($scopes[$i] === '') unset($scopes[$i]); // Remove any junk scopes if ($scopes[$i] === '') unset($scopes[$i]); // Remove any junk scopes
} }
if ($this->authServer->scopeParamRequired() === true && count($scopes) === 0) { if ($this->authServer->scopeParamRequired() === true && $this->authServer->getDefaultScope() === null && count($scopes) === 0) {
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'scope'), 0); throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'scope'), 0);
} elseif (count($scopes) === 0 && $this->authServer->getDefaultScope()) { } elseif (count($scopes) === 0 && $this->authServer->getDefaultScope() !== null) {
if (is_array($this->authServer->getDefaultScope())) {
$scopes = $this->authServer->getDefaultScope();
} else {
$scopes = array($this->authServer->getDefaultScope()); $scopes = array($this->authServer->getDefaultScope());
} }
}
$authParams['scopes'] = array(); $authParams['scopes'] = array();
@ -145,9 +149,6 @@ class ClientCredentials implements GrantTypeInterface {
$accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL(); $accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL();
$accessTokenExpires = time() + $accessTokenExpiresIn; $accessTokenExpires = time() + $accessTokenExpiresIn;
// Delete any existing sessions just to be sure
$this->authServer->getStorage('session')->deleteSession($authParams['client_id'], 'client', $authParams['client_id']);
// Create a new session // Create a new session
$sessionId = $this->authServer->getStorage('session')->createSession($authParams['client_id'], 'client', $authParams['client_id']); $sessionId = $this->authServer->getStorage('session')->createSession($authParams['client_id'], 'client', $authParams['client_id']);

View File

@ -166,11 +166,15 @@ class Password implements GrantTypeInterface {
if ($scopes[$i] === '') unset($scopes[$i]); // Remove any junk scopes if ($scopes[$i] === '') unset($scopes[$i]); // Remove any junk scopes
} }
if ($this->authServer->scopeParamRequired() === true && count($scopes) === 0) { if ($this->authServer->scopeParamRequired() === true && $this->authServer->getDefaultScope() === null && count($scopes) === 0) {
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'scope'), 0); throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'scope'), 0);
} elseif (count($scopes) === 0 && $this->authServer->getDefaultScope()) { } elseif (count($scopes) === 0 && $this->authServer->getDefaultScope() !== null) {
if (is_array($this->authServer->getDefaultScope())) {
$scopes = $this->authServer->getDefaultScope();
} else {
$scopes = array($this->authServer->getDefaultScope()); $scopes = array($this->authServer->getDefaultScope());
} }
}
$authParams['scopes'] = array(); $authParams['scopes'] = array();
@ -189,9 +193,6 @@ class Password implements GrantTypeInterface {
$accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL(); $accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL();
$accessTokenExpires = time() + $accessTokenExpiresIn; $accessTokenExpires = time() + $accessTokenExpiresIn;
// Delete any existing sessions just to be sure
$this->authServer->getStorage('session')->deleteSession($authParams['client_id'], 'user', $userId);
// Create a new session // Create a new session
$sessionId = $this->authServer->getStorage('session')->createSession($authParams['client_id'], 'user', $userId); $sessionId = $this->authServer->getStorage('session')->createSession($authParams['client_id'], 'user', $userId);

View File

@ -54,6 +54,12 @@ class RefreshToken implements GrantTypeInterface {
*/ */
protected $refreshTokenTTL = 604800; protected $refreshTokenTTL = 604800;
/**
* Rotate refresh tokens
* @var boolean
*/
protected $rotateRefreshTokens = false;
/** /**
* Constructor * Constructor
* @param Authorization $authServer Authorization server instance * @param Authorization $authServer Authorization server instance
@ -111,6 +117,16 @@ class RefreshToken implements GrantTypeInterface {
return $this->refreshTokenTTL; return $this->refreshTokenTTL;
} }
/**
* When a new access is token, expire the refresh token used and issue a new one.
* @param boolean $rotateRefreshTokens Set to true to enable (default = false)
* @return void
*/
public function rotateRefreshTokens($rotateRefreshTokens = false)
{
$this->rotateRefreshTokens = $rotateRefreshTokens;
}
/** /**
* Complete the refresh token grant * Complete the refresh token grant
* @param null|array $inputParams * @param null|array $inputParams
@ -119,7 +135,7 @@ class RefreshToken implements GrantTypeInterface {
public function completeFlow($inputParams = null) public function completeFlow($inputParams = null)
{ {
// Get the required params // Get the required params
$authParams = $this->authServer->getParam(array('client_id', 'client_secret', 'refresh_token'), 'post', $inputParams); $authParams = $this->authServer->getParam(array('client_id', 'client_secret', 'refresh_token', 'scope'), 'post', $inputParams);
if (is_null($authParams['client_id'])) { if (is_null($authParams['client_id'])) {
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_id'), 0); throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_id'), 0);
@ -159,24 +175,69 @@ class RefreshToken implements GrantTypeInterface {
$accessToken = SecureKey::make(); $accessToken = SecureKey::make();
$accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL(); $accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL();
$accessTokenExpires = time() + $accessTokenExpiresIn; $accessTokenExpires = time() + $accessTokenExpiresIn;
// Associate the new access token with the session
$newAccessTokenId = $this->authServer->getStorage('session')->associateAccessToken($accessTokenDetails['session_id'], $accessToken, $accessTokenExpires);
if ($this->rotateRefreshTokens === true) {
// Generate a new refresh token
$refreshToken = SecureKey::make(); $refreshToken = SecureKey::make();
$refreshTokenExpires = time() + $this->getRefreshTokenTTL(); $refreshTokenExpires = time() + $this->getRefreshTokenTTL();
$newAccessTokenId = $this->authServer->getStorage('session')->associateAccessToken($accessTokenDetails['session_id'], $accessToken, $accessTokenExpires); // Revoke the old refresh token
$this->authServer->getStorage('session')->removeRefreshToken($authParams['refresh_token']);
// Associate the new refresh token with the new access token
$this->authServer->getStorage('session')->associateRefreshToken($newAccessTokenId, $refreshToken, $refreshTokenExpires, $authParams['client_id']);
}
// There isn't a request for reduced scopes so assign the original ones (or we're not rotating scopes)
if ( ! isset($authParams['scope'])) {
foreach ($scopes as $scope) { foreach ($scopes as $scope) {
$this->authServer->getStorage('session')->associateScope($newAccessTokenId, $scope['id']); $this->authServer->getStorage('session')->associateScope($newAccessTokenId, $scope['id']);
} }
$this->authServer->getStorage('session')->associateRefreshToken($newAccessTokenId, $refreshToken, $refreshTokenExpires, $authParams['client_id']); } elseif ( isset($authParams['scope']) && $this->rotateRefreshTokens === true) {
return array( // The request is asking for reduced scopes and rotate tokens is enabled
$reqestedScopes = explode($this->authServer->getScopeDelimeter(), $authParams['scope']);
for ($i = 0; $i < count($reqestedScopes); $i++) {
$reqestedScopes[$i] = trim($reqestedScopes[$i]);
if ($reqestedScopes[$i] === '') unset($reqestedScopes[$i]); // Remove any junk scopes
}
// Check that there aren't any new scopes being included
$existingScopes = array();
foreach ($scopes as $s) {
$existingScopes[] = $s['scope'];
}
foreach ($reqestedScopes as $reqScope) {
if ( ! in_array($reqScope, $existingScopes)) {
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'scope'), 0);
}
// Associate with the new access token
$scopeDetails = $this->authServer->getStorage('scope')->getScope($reqScope, $authParams['client_id'], $this->identifier);
$this->authServer->getStorage('session')->associateScope($newAccessTokenId, $scopeDetails['id']);
}
}
$response = array(
'access_token' => $accessToken, 'access_token' => $accessToken,
'refresh_token' => $refreshToken,
'token_type' => 'bearer', 'token_type' => 'bearer',
'expires' => $accessTokenExpires, 'expires' => $accessTokenExpires,
'expires_in' => $accessTokenExpiresIn 'expires_in' => $accessTokenExpiresIn
); );
if ($this->rotateRefreshTokens === true) {
$response['refresh_token'] = $refreshToken;
}
return $response;
} }
} }

View File

@ -243,7 +243,19 @@ class Resource
protected function determineAccessToken() protected function determineAccessToken()
{ {
if ($header = $this->getRequest()->header('Authorization')) { if ($header = $this->getRequest()->header('Authorization')) {
$accessToken = trim(str_replace('Bearer', '', $header)); // Check for special case, because cURL sometimes does an
// internal second request and doubles the authorization header,
// which always resulted in an error.
//
// 1st request: Authorization: Bearer XXX
// 2nd request: Authorization: Bearer XXX, Bearer XXX
if (strpos($header, ',') !== false) {
$headerPart = explode(',', $header);
$accessToken = preg_replace('/^(?:\s+)?Bearer(\s{1})/', '', $headerPart[0]);
} else {
$accessToken = preg_replace('/^(?:\s+)?Bearer(\s{1})/', '', $header);
}
$accessToken = ($accessToken === 'Bearer') ? '' : $accessToken;
} else { } else {
$method = $this->getRequest()->server('REQUEST_METHOD'); $method = $this->getRequest()->server('REQUEST_METHOD');
$accessToken = $this->getRequest()->{$method}($this->tokenKey); $accessToken = $this->getRequest()->{$method}($this->tokenKey);

View File

@ -10,7 +10,7 @@ class Scope implements ScopeInterface
{ {
$db = \ezcDbInstance::get(); $db = \ezcDbInstance::get();
$stmt = $db->prepare('SELECT * FROM oauth_scopes WHERE oauth_scopes.key = :scope'); $stmt = $db->prepare('SELECT * FROM oauth_scopes WHERE oauth_scopes.scope = :scope');
$stmt->bindValue(':scope', $scope); $stmt->bindValue(':scope', $scope);
$stmt->execute(); $stmt->execute();
@ -22,7 +22,7 @@ class Scope implements ScopeInterface
return array( return array(
'id' => $row->id, 'id' => $row->id,
'scope' => $row->key, 'scope' => $row->scope,
'name' => $row->name, 'name' => $row->name,
'description' => $row->description 'description' => $row->description
); );

View File

@ -70,17 +70,18 @@ class Session implements SessionInterface
$stmt->execute(); $stmt->execute();
} }
public function associateAuthCode($sessionId, $authCode, $expireTime, $scopeIds = null) public function associateAuthCode($sessionId, $authCode, $expireTime)
{ {
$db = \ezcDbInstance::get(); $db = \ezcDbInstance::get();
$stmt = $db->prepare('INSERT INTO oauth_session_authcodes (session_id, auth_code, auth_code_expires, scope_ids) $stmt = $db->prepare('INSERT INTO oauth_session_authcodes (session_id, auth_code, auth_code_expires)
VALUE (:sessionId, :authCode, :authCodeExpires, :scopeIds)'); VALUE (:sessionId, :authCode, :authCodeExpires)');
$stmt->bindValue(':sessionId', $sessionId); $stmt->bindValue(':sessionId', $sessionId);
$stmt->bindValue(':authCode', $authCode); $stmt->bindValue(':authCode', $authCode);
$stmt->bindValue(':authCodeExpires', $expireTime); $stmt->bindValue(':authCodeExpires', $expireTime);
$stmt->bindValue(':scopeIds', $scopeIds);
$stmt->execute(); $stmt->execute();
return $db->lastInsertId();
} }
public function removeAuthCode($sessionId) public function removeAuthCode($sessionId)
@ -96,12 +97,12 @@ class Session implements SessionInterface
{ {
$db = \ezcDbInstance::get(); $db = \ezcDbInstance::get();
$stmt = $db->prepare('SELECT oauth_sessions.id, oauth_session_authcodes.scope_ids FROM oauth_sessions JOIN $stmt = $db->prepare('SELECT oauth_sessions.id AS session_id, oauth_session_authcodes.id AS authcode_id
oauth_session_authcodes ON oauth_session_authcodes.`session_id` = oauth_sessions.id JOIN FROM oauth_sessions JOIN oauth_session_authcodes ON oauth_session_authcodes.`session_id`
oauth_session_redirects ON oauth_session_redirects.`session_id` = oauth_sessions.id WHERE = oauth_sessions.id JOIN oauth_session_redirects ON oauth_session_redirects.`session_id`
oauth_sessions.client_id = :clientId AND oauth_session_authcodes.`auth_code` = :authCode AND = oauth_sessions.id WHERE oauth_sessions.client_id = :clientId AND oauth_session_authcodes.`auth_code`
`oauth_session_authcodes`.`auth_code_expires` >= :time AND `oauth_session_redirects`.`redirect_uri` = :authCode AND `oauth_session_authcodes`.`auth_code_expires` >= :time AND
= :redirectUri'); `oauth_session_redirects`.`redirect_uri` = :redirectUri');
$stmt->bindValue(':clientId', $clientId); $stmt->bindValue(':clientId', $clientId);
$stmt->bindValue(':redirectUri', $redirectUri); $stmt->bindValue(':redirectUri', $redirectUri);
$stmt->bindValue(':authCode', $authCode); $stmt->bindValue(':authCode', $authCode);
@ -125,6 +126,15 @@ class Session implements SessionInterface
return ($result === false) ? false : (array) $result; return ($result === false) ? false : (array) $result;
} }
public function removeRefreshToken($refreshToken)
{
$db = \ezcDbInstance::get();
$stmt = $db->prepare('DELETE FROM `oauth_session_refresh_tokens` WHERE refresh_token = :refreshToken');
$stmt->bindValue(':refreshToken', $refreshToken);
$stmt->execute();
}
public function validateRefreshToken($refreshToken, $clientId) public function validateRefreshToken($refreshToken, $clientId)
{ {
$db = \ezcDbInstance::get(); $db = \ezcDbInstance::get();
@ -151,6 +161,27 @@ class Session implements SessionInterface
return ($result === false) ? false : (array) $result; return ($result === false) ? false : (array) $result;
} }
public function associateAuthCodeScope($authCodeId, $scopeId)
{
$db = \ezcDbInstance::get();
$stmt = $db->prepare('INSERT INTO `oauth_session_authcode_scopes` (`oauth_session_authcode_id`, `scope_id`) VALUES (:authCodeId, :scopeId)');
$stmt->bindValue(':authCodeId', $authCodeId);
$stmt->bindValue(':scopeId', $scopeId);
$stmt->execute();
}
public function getAuthCodeScopes($oauthSessionAuthCodeId)
{
$db = \ezcDbInstance::get();
$stmt = $db->prepare('SELECT scope_id FROM `oauth_session_authcode_scopes` WHERE oauth_session_authcode_id = :authCodeId');
$stmt->bindValue(':authCodeId', $oauthSessionAuthCodeId);
$stmt->execute();
return $stmt->fetchAll();
}
public function associateScope($accessTokenId, $scopeId) public function associateScope($accessTokenId, $scopeId)
{ {
$db = \ezcDbInstance::get(); $db = \ezcDbInstance::get();

View File

@ -19,7 +19,7 @@ interface ScopeInterface
* Example SQL query: * Example SQL query:
* *
* <code> * <code>
* SELECT * FROM oauth_scopes WHERE oauth_scopes.key = :scope * SELECT * FROM oauth_scopes WHERE scope = :scope
* </code> * </code>
* *
* Response: * Response:
@ -28,7 +28,7 @@ interface ScopeInterface
* Array * Array
* ( * (
* [id] => (int) The scope's ID * [id] => (int) The scope's ID
* [key] => (string) The scope itself * [scope] => (string) The scope itself
* [name] => (string) The scope's name * [name] => (string) The scope's name
* [description] => (string) The scope's description * [description] => (string) The scope's description
* ) * )

View File

@ -102,17 +102,16 @@ interface SessionInterface
* Example SQL query: * Example SQL query:
* *
* <code> * <code>
* INSERT INTO oauth_session_authcodes (session_id, auth_code, auth_code_expires, scope_ids) * INSERT INTO oauth_session_authcodes (session_id, auth_code, auth_code_expires)
* VALUE (:sessionId, :authCode, :authCodeExpires, :scopeIds) * VALUE (:sessionId, :authCode, :authCodeExpires)
* </code> * </code>
* *
* @param int $sessionId The session ID * @param int $sessionId The session ID
* @param string $authCode The authorization code * @param string $authCode The authorization code
* @param int $expireTime Unix timestamp of the access token expiry time * @param int $expireTime Unix timestamp of the access token expiry time
* @param string $scopeIds Comma seperated list of scope IDs to be later associated (default = null) * @return int The auth code ID
* @return void
*/ */
public function associateAuthCode($sessionId, $authCode, $expireTime, $scopeIds = null); public function associateAuthCode($sessionId, $authCode, $expireTime);
/** /**
* Remove an associated authorization token from a session * Remove an associated authorization token from a session
@ -134,7 +133,7 @@ interface SessionInterface
* Example SQL query: * Example SQL query:
* *
* <code> * <code>
* SELECT oauth_sessions.id, oauth_session_authcodes.scope_ids FROM oauth_sessions * SELECT oauth_sessions.id AS session_id, oauth_session_authcodes.id AS authcode_id FROM oauth_sessions
* JOIN oauth_session_authcodes ON oauth_session_authcodes.`session_id` = oauth_sessions.id * JOIN oauth_session_authcodes ON oauth_session_authcodes.`session_id` = oauth_sessions.id
* JOIN oauth_session_redirects ON oauth_session_redirects.`session_id` = oauth_sessions.id WHERE * JOIN oauth_session_redirects ON oauth_session_redirects.`session_id` = oauth_sessions.id WHERE
* oauth_sessions.client_id = :clientId AND oauth_session_authcodes.`auth_code` = :authCode * oauth_sessions.client_id = :clientId AND oauth_session_authcodes.`auth_code` = :authCode
@ -146,8 +145,8 @@ interface SessionInterface
* *
* <code> * <code>
* array( * array(
* 'id' => (int), // the session ID * 'session_id' => (int)
* 'scope_ids' => (string) * 'authcode_id' => (int)
* ) * )
* </code> * </code>
* *
@ -185,6 +184,20 @@ interface SessionInterface
*/ */
public function validateAccessToken($accessToken); public function validateAccessToken($accessToken);
/**
* Removes a refresh token
*
* Example SQL query:
*
* <code>
* DELETE FROM `oauth_session_refresh_tokens` WHERE refresh_token = :refreshToken
* </code>
*
* @param string $refreshToken The refresh token to be removed
* @return void
*/
public function removeRefreshToken($refreshToken);
/** /**
* Validate a refresh token * Validate a refresh token
* *
@ -226,6 +239,50 @@ interface SessionInterface
*/ */
public function getAccessToken($accessTokenId); public function getAccessToken($accessTokenId);
/**
* Associate scopes with an auth code (bound to the session)
*
* Example SQL query:
*
* <code>
* INSERT INTO `oauth_session_authcode_scopes` (`oauth_session_authcode_id`, `scope_id`) VALUES
* (:authCodeId, :scopeId)
* </code>
*
* @param int $authCodeId The auth code ID
* @param int $scopeId The scope ID
* @return void
*/
public function associateAuthCodeScope($authCodeId, $scopeId);
/**
* Get the scopes associated with an auth code
*
* Example SQL query:
*
* <code>
* SELECT scope_id FROM `oauth_session_authcode_scopes` WHERE oauth_session_authcode_id = :authCodeId
* </code>
*
* Expected response:
*
* <code>
* array(
* array(
* 'scope_id' => (int)
* ),
* array(
* 'scope_id' => (int)
* ),
* ...
* )
* </code>
*
* @param int $oauthSessionAuthCodeId The session ID
* @return array
*/
public function getAuthCodeScopes($oauthSessionAuthCodeId);
/** /**
* Associate a scope with an access token * Associate a scope with an access token
* *

View File

@ -156,6 +156,7 @@ class Auth_Code_Grant_Test extends PHPUnit_Framework_TestCase
$g = new League\OAuth2\Server\Grant\AuthCode($a); $g = new League\OAuth2\Server\Grant\AuthCode($a);
$a->addGrantType($g); $a->addGrantType($g);
$a->addGrantType(new League\OAuth2\Server\Grant\AuthCode($a)); $a->addGrantType(new League\OAuth2\Server\Grant\AuthCode($a));
$a->requireScopeParam(true);
$g->checkAuthoriseParams(array( $g->checkAuthoriseParams(array(
'client_id' => 1234, 'client_id' => 1234,
@ -196,6 +197,41 @@ class Auth_Code_Grant_Test extends PHPUnit_Framework_TestCase
)); ));
$this->assertArrayHasKey('scopes', $params); $this->assertArrayHasKey('scopes', $params);
$this->assertEquals(1, count($params['scopes']));
}
public function test_checkAuthoriseParams_defaultScopeArray()
{
$this->client->shouldReceive('getClient')->andReturn(array(
'client_id' => 1234,
'client_secret' => 5678,
'redirect_uri' => 'http://foo/redirect',
'name' => 'Example Client'
));
$this->scope->shouldReceive('getScope')->andReturn(array(
'id' => 1,
'scope' => 'foo',
'name' => 'Foo Name',
'description' => 'Foo Name Description'
));
$a = $this->returnDefault();
$g = new League\OAuth2\Server\Grant\AuthCode($a);
$a->addGrantType($g);
$a->addGrantType(new League\OAuth2\Server\Grant\AuthCode($a));
$a->setDefaultScope(array('test.scope', 'test.scope2'));
$a->requireScopeParam(false);
$params = $g->checkAuthoriseParams(array(
'client_id' => 1234,
'redirect_uri' => 'http://foo/redirect',
'response_type' => 'code',
'scope' => ''
));
$this->assertArrayHasKey('scopes', $params);
$this->assertEquals(2, count($params['scopes']));
} }
/** /**
@ -340,7 +376,8 @@ class Auth_Code_Grant_Test extends PHPUnit_Framework_TestCase
$this->session->shouldReceive('createSession')->andReturn(1); $this->session->shouldReceive('createSession')->andReturn(1);
$this->session->shouldReceive('associateScope')->andReturn(null); $this->session->shouldReceive('associateScope')->andReturn(null);
$this->session->shouldReceive('associateRedirectUri')->andReturn(null); $this->session->shouldReceive('associateRedirectUri')->andReturn(null);
$this->session->shouldReceive('associateAuthCode')->andReturn(null); $this->session->shouldReceive('associateAuthCode')->andReturn(1);
$this->session->shouldReceive('associateAuthCodeScope')->andReturn(null);
$a = $this->returnDefault(); $a = $this->returnDefault();
$g = new League\OAuth2\Server\Grant\AuthCode($a); $g = new League\OAuth2\Server\Grant\AuthCode($a);

View File

@ -358,13 +358,14 @@ class Authorization_Server_test extends PHPUnit_Framework_TestCase
)); ));
$this->session->shouldReceive('validateAuthCode')->andReturn(array( $this->session->shouldReceive('validateAuthCode')->andReturn(array(
'id' => 1, 'session_id' => 1,
'scope_ids' => '1' 'authcode_id' => 1
)); ));
$this->session->shouldReceive('updateSession')->andReturn(null); $this->session->shouldReceive('updateSession')->andReturn(null);
$this->session->shouldReceive('removeAuthCode')->andReturn(null); $this->session->shouldReceive('removeAuthCode')->andReturn(null);
$this->session->shouldReceive('associateAccessToken')->andReturn(1); $this->session->shouldReceive('associateAccessToken')->andReturn(1);
$this->session->shouldReceive('associateScope')->andReturn(null); $this->session->shouldReceive('associateScope')->andReturn(null);
$this->session->shouldReceive('getAuthCodeScopes')->andReturn(array('scope_id' => 1));
$a = $this->returnDefault(); $a = $this->returnDefault();
$a->addGrantType(new League\OAuth2\Server\Grant\AuthCode($a)); $a->addGrantType(new League\OAuth2\Server\Grant\AuthCode($a));
@ -399,6 +400,8 @@ class Authorization_Server_test extends PHPUnit_Framework_TestCase
$this->session->shouldReceive('updateSession')->andReturn(null); $this->session->shouldReceive('updateSession')->andReturn(null);
$this->session->shouldReceive('removeAuthCode')->andReturn(null); $this->session->shouldReceive('removeAuthCode')->andReturn(null);
$this->session->shouldReceive('associateAccessToken')->andReturn(1); $this->session->shouldReceive('associateAccessToken')->andReturn(1);
$this->session->shouldReceive('getAuthCodeScopes')->andReturn(array('scope_id' => 1));
$this->session->shouldReceive('associateScope')->andReturn(null);
$a = $this->returnDefault(); $a = $this->returnDefault();
$a->addGrantType(new League\OAuth2\Server\Grant\AuthCode($a)); $a->addGrantType(new League\OAuth2\Server\Grant\AuthCode($a));
@ -436,6 +439,8 @@ class Authorization_Server_test extends PHPUnit_Framework_TestCase
$this->session->shouldReceive('updateSession')->andReturn(null); $this->session->shouldReceive('updateSession')->andReturn(null);
$this->session->shouldReceive('removeAuthCode')->andReturn(null); $this->session->shouldReceive('removeAuthCode')->andReturn(null);
$this->session->shouldReceive('associateAccessToken')->andReturn(1); $this->session->shouldReceive('associateAccessToken')->andReturn(1);
$this->session->shouldReceive('getAuthCodeScopes')->andReturn(array('scope_id' => 1));
$this->session->shouldReceive('associateScope')->andReturn(null);
$a = $this->returnDefault(); $a = $this->returnDefault();
$grant = new League\OAuth2\Server\Grant\AuthCode($a); $grant = new League\OAuth2\Server\Grant\AuthCode($a);
@ -477,6 +482,8 @@ class Authorization_Server_test extends PHPUnit_Framework_TestCase
$this->session->shouldReceive('updateSession')->andReturn(null); $this->session->shouldReceive('updateSession')->andReturn(null);
$this->session->shouldReceive('removeAuthCode')->andReturn(null); $this->session->shouldReceive('removeAuthCode')->andReturn(null);
$this->session->shouldReceive('associateAccessToken')->andReturn(1); $this->session->shouldReceive('associateAccessToken')->andReturn(1);
$this->session->shouldReceive('getAuthCodeScopes')->andReturn(array('scope_id' => 1));
$this->session->shouldReceive('associateScope')->andReturn(null);
$a = $this->returnDefault(); $a = $this->returnDefault();
$a->addGrantType(new League\OAuth2\Server\Grant\AuthCode($a)); $a->addGrantType(new League\OAuth2\Server\Grant\AuthCode($a));

View File

@ -146,6 +146,47 @@ class Client_Credentials_Grant_Test extends PHPUnit_Framework_TestCase
$this->assertArrayHasKey('expires_in', $v); $this->assertArrayHasKey('expires_in', $v);
} }
public function test_issueAccessToken_clientCredentialsGrant_defaultScopeArray()
{
$this->scope->shouldReceive('getScope')->andReturn(array(
'id' => 1,
'key' => 'foo',
'name' => 'Foo Name',
'description' => 'Foo Name Description'
));
$this->client->shouldReceive('getClient')->andReturn(array(
'client_id' => 1234,
'client_secret' => 5678,
'redirect_uri' => 'http://foo/redirect',
'name' => 'Example Client'
));
$this->client->shouldReceive('validateRefreshToken')->andReturn(1);
$this->session->shouldReceive('validateAuthCode')->andReturn(1);
$this->session->shouldReceive('createSession')->andReturn(1);
$this->session->shouldReceive('deleteSession')->andReturn(null);
$this->session->shouldReceive('associateScope')->andReturn(null);
$this->session->shouldReceive('associateAccessToken')->andReturn(1);
$a = $this->returnDefault();
$a->addGrantType(new League\OAuth2\Server\Grant\ClientCredentials($a));
$a->requireScopeParam(false);
$a->setDefaultScope(array('foobar', 'barfoo'));
$v = $a->issueAccessToken(array(
'grant_type' => 'client_credentials',
'client_id' => 1234,
'client_secret' => 5678,
'scope' => ''
));
$this->assertArrayHasKey('access_token', $v);
$this->assertArrayHasKey('token_type', $v);
$this->assertArrayHasKey('expires', $v);
$this->assertArrayHasKey('expires_in', $v);
}
/** /**
* @expectedException League\OAuth2\Server\Exception\ClientException * @expectedException League\OAuth2\Server\Exception\ClientException
* @expectedExceptionCode 4 * @expectedExceptionCode 4

View File

@ -338,6 +338,54 @@ class Password_Grant_Test extends PHPUnit_Framework_TestCase
$this->assertArrayHasKey('expires_in', $v); $this->assertArrayHasKey('expires_in', $v);
} }
public function test_issueAccessToken_passwordGrant_defaultScopeArray()
{
$this->scope->shouldReceive('getScope')->andReturn(array(
'id' => 1,
'scope' => 'foo',
'name' => 'Foo Name',
'description' => 'Foo Name Description'
));
$this->client->shouldReceive('getClient')->andReturn(array(
'client_id' => 1234,
'client_secret' => 5678,
'redirect_uri' => 'http://foo/redirect',
'name' => 'Example Client'
));
$this->client->shouldReceive('validateRefreshToken')->andReturn(1);
$this->session->shouldReceive('validateAuthCode')->andReturn(1);
$this->session->shouldReceive('createSession')->andReturn(1);
$this->session->shouldReceive('deleteSession')->andReturn(null);
$this->session->shouldReceive('updateRefreshToken')->andReturn(null);
$this->session->shouldReceive('associateScope')->andReturn(null);
$this->session->shouldReceive('associateAccessToken')->andReturn(1);
$testCredentials = function() { return 1; };
$a = $this->returnDefault();
$pgrant = new League\OAuth2\Server\Grant\Password($a);
$pgrant->setVerifyCredentialsCallback($testCredentials);
$a->addGrantType($pgrant);
$a->requireScopeParam(false);
$a->setDefaultScope(array('foobar', 'barfoo'));
$v = $a->issueAccessToken(array(
'grant_type' => 'password',
'client_id' => 1234,
'client_secret' => 5678,
'username' => 'foo',
'password' => 'bar',
'scope' => ''
));
$this->assertArrayHasKey('access_token', $v);
$this->assertArrayHasKey('token_type', $v);
$this->assertArrayHasKey('expires', $v);
$this->assertArrayHasKey('expires_in', $v);
}
public function test_issueAccessToken_passwordGrant_goodScope() public function test_issueAccessToken_passwordGrant_goodScope()
{ {
$this->scope->shouldReceive('getScope')->andReturn(array( $this->scope->shouldReceive('getScope')->andReturn(array(

View File

@ -42,6 +42,8 @@ class Refresh_Token_test extends PHPUnit_Framework_TestCase
$this->session->shouldReceive('removeAuthCode')->andReturn(null); $this->session->shouldReceive('removeAuthCode')->andReturn(null);
$this->session->shouldReceive('associateAccessToken')->andReturn(1); $this->session->shouldReceive('associateAccessToken')->andReturn(1);
$this->session->shouldReceive('associateRefreshToken')->andReturn(1); $this->session->shouldReceive('associateRefreshToken')->andReturn(1);
$this->session->shouldReceive('associateScope')->andReturn(null);
$this->session->shouldReceive('getAuthCodeScopes')->andReturn(array('scope_id' => 1));
$a = $this->returnDefault(); $a = $this->returnDefault();
$a->addGrantType(new League\OAuth2\Server\Grant\AuthCode($a)); $a->addGrantType(new League\OAuth2\Server\Grant\AuthCode($a));
@ -183,6 +185,7 @@ class Refresh_Token_test extends PHPUnit_Framework_TestCase
$this->session->shouldReceive('updateRefreshToken')->andReturn(null); $this->session->shouldReceive('updateRefreshToken')->andReturn(null);
$this->session->shouldReceive('associateAccessToken')->andReturn(1); $this->session->shouldReceive('associateAccessToken')->andReturn(1);
$this->session->shouldReceive('associateRefreshToken')->andReturn(1); $this->session->shouldReceive('associateRefreshToken')->andReturn(1);
$this->session->shouldReceive('removeRefreshToken')->andReturn(1);
$this->session->shouldReceive('getAccessToken')->andReturn(null); $this->session->shouldReceive('getAccessToken')->andReturn(null);
$this->session->shouldReceive('getScopes')->andReturn(array()); $this->session->shouldReceive('getScopes')->andReturn(array());
@ -203,7 +206,6 @@ class Refresh_Token_test extends PHPUnit_Framework_TestCase
$this->assertArrayHasKey('token_type', $v); $this->assertArrayHasKey('token_type', $v);
$this->assertArrayHasKey('expires', $v); $this->assertArrayHasKey('expires', $v);
$this->assertArrayHasKey('expires_in', $v); $this->assertArrayHasKey('expires_in', $v);
$this->assertArrayHasKey('refresh_token', $v);
$this->assertEquals($a->getAccessTokenTTL(), $v['expires_in']); $this->assertEquals($a->getAccessTokenTTL(), $v['expires_in']);
$this->assertEquals(time()+$a->getAccessTokenTTL(), $v['expires']); $this->assertEquals(time()+$a->getAccessTokenTTL(), $v['expires']);
@ -226,6 +228,7 @@ class Refresh_Token_test extends PHPUnit_Framework_TestCase
$this->session->shouldReceive('getScopes')->andReturn(array('id' => 1)); $this->session->shouldReceive('getScopes')->andReturn(array('id' => 1));
$this->session->shouldReceive('associateAccessToken')->andReturn(1); $this->session->shouldReceive('associateAccessToken')->andReturn(1);
$this->session->shouldReceive('associateRefreshToken')->andReturn(1); $this->session->shouldReceive('associateRefreshToken')->andReturn(1);
$this->session->shouldReceive('removeRefreshToken')->andReturn(1);
$this->session->shouldReceive('associateScope')->andReturn(null); $this->session->shouldReceive('associateScope')->andReturn(null);
$a = $this->returnDefault(); $a = $this->returnDefault();
@ -238,6 +241,48 @@ class Refresh_Token_test extends PHPUnit_Framework_TestCase
'refresh_token' => 'abcdef', 'refresh_token' => 'abcdef',
)); ));
$this->assertArrayHasKey('access_token', $v);
$this->assertArrayHasKey('token_type', $v);
$this->assertArrayHasKey('expires', $v);
$this->assertArrayHasKey('expires_in', $v);
$this->assertEquals($a->getAccessTokenTTL(), $v['expires_in']);
$this->assertEquals(time()+$a->getAccessTokenTTL(), $v['expires']);
}
public function test_issueAccessToken_refreshTokenGrant_rotateTokens()
{
$this->client->shouldReceive('getClient')->andReturn(array(
'client_id' => 1234,
'client_secret' => 5678,
'redirect_uri' => 'http://foo/redirect',
'name' => 'Example Client'
));
$this->session->shouldReceive('validateRefreshToken')->andReturn(1);
$this->session->shouldReceive('validateAuthCode')->andReturn(1);
$this->session->shouldReceive('updateSession')->andReturn(null);
$this->session->shouldReceive('updateRefreshToken')->andReturn(null);
$this->session->shouldReceive('getAccessToken')->andReturn(null);
$this->session->shouldReceive('getScopes')->andReturn(array('id' => 1));
$this->session->shouldReceive('associateAccessToken')->andReturn(1);
$this->session->shouldReceive('associateRefreshToken')->andReturn(1);
$this->session->shouldReceive('removeRefreshToken')->andReturn(1);
$this->session->shouldReceive('associateScope')->andReturn(null);
$a = $this->returnDefault();
$rt = new League\OAuth2\Server\Grant\RefreshToken($a);
$rt->rotateRefreshTokens(true);
$a->addGrantType($rt);
$v = $a->issueAccessToken(array(
'grant_type' => 'refresh_token',
'client_id' => 1234,
'client_secret' => 5678,
'refresh_token' => 'abcdef',
));
$this->assertArrayHasKey('access_token', $v); $this->assertArrayHasKey('access_token', $v);
$this->assertArrayHasKey('token_type', $v); $this->assertArrayHasKey('token_type', $v);
$this->assertArrayHasKey('expires', $v); $this->assertArrayHasKey('expires', $v);
@ -265,6 +310,7 @@ class Refresh_Token_test extends PHPUnit_Framework_TestCase
$this->session->shouldReceive('getScopes')->andReturn(array('id' => 1)); $this->session->shouldReceive('getScopes')->andReturn(array('id' => 1));
$this->session->shouldReceive('associateAccessToken')->andReturn(1); $this->session->shouldReceive('associateAccessToken')->andReturn(1);
$this->session->shouldReceive('associateRefreshToken')->andReturn(1); $this->session->shouldReceive('associateRefreshToken')->andReturn(1);
$this->session->shouldReceive('removeRefreshToken')->andReturn(1);
$this->session->shouldReceive('associateScope')->andReturn(null); $this->session->shouldReceive('associateScope')->andReturn(null);
$a = $this->returnDefault(); $a = $this->returnDefault();
@ -279,6 +325,52 @@ class Refresh_Token_test extends PHPUnit_Framework_TestCase
'refresh_token' => 'abcdef', 'refresh_token' => 'abcdef',
)); ));
$this->assertArrayHasKey('access_token', $v);
$this->assertArrayHasKey('token_type', $v);
$this->assertArrayHasKey('expires', $v);
$this->assertArrayHasKey('expires_in', $v);
$this->assertNotEquals($a->getAccessTokenTTL(), $v['expires_in']);
$this->assertNotEquals(time()+$a->getAccessTokenTTL(), $v['expires']);
$this->assertEquals(30, $v['expires_in']);
$this->assertEquals(time()+30, $v['expires']);
}
public function test_issueAccessToken_refreshTokenGrant_newScopes()
{
$this->client->shouldReceive('getClient')->andReturn(array(
'client_id' => 1234,
'client_secret' => 5678,
'redirect_uri' => 'http://foo/redirect',
'name' => 'Example Client'
));
$this->session->shouldReceive('validateRefreshToken')->andReturn(1);
$this->session->shouldReceive('validateAuthCode')->andReturn(1);
$this->session->shouldReceive('updateSession')->andReturn(null);
$this->session->shouldReceive('updateRefreshToken')->andReturn(null);
$this->session->shouldReceive('getAccessToken')->andReturn(null);
$this->session->shouldReceive('getScopes')->andReturn(array(array('id' => 1, 'scope' => 'foo'), array('id' => 2, 'scope' => 'bar')));
$this->session->shouldReceive('associateAccessToken')->andReturn(1);
$this->session->shouldReceive('associateRefreshToken')->andReturn(1);
$this->session->shouldReceive('removeRefreshToken')->andReturn(1);
$this->session->shouldReceive('associateScope')->andReturn(null);
$this->scope->shouldReceive('getScope')->andReturn(array('id' => 1, 'scope' => 'foo'));
$a = $this->returnDefault();
$grant = new League\OAuth2\Server\Grant\RefreshToken($a);
$grant->setAccessTokenTTL(30);
$grant->rotateRefreshTokens(true);
$a->addGrantType($grant);
$v = $a->issueAccessToken(array(
'grant_type' => 'refresh_token',
'client_id' => 1234,
'client_secret' => 5678,
'refresh_token' => 'abcdef',
'scope' => 'foo'
));
$this->assertArrayHasKey('access_token', $v); $this->assertArrayHasKey('access_token', $v);
$this->assertArrayHasKey('token_type', $v); $this->assertArrayHasKey('token_type', $v);
$this->assertArrayHasKey('expires', $v); $this->assertArrayHasKey('expires', $v);
@ -290,4 +382,44 @@ class Refresh_Token_test extends PHPUnit_Framework_TestCase
$this->assertEquals(30, $v['expires_in']); $this->assertEquals(30, $v['expires_in']);
$this->assertEquals(time()+30, $v['expires']); $this->assertEquals(time()+30, $v['expires']);
} }
/**
* @expectedException League\OAuth2\Server\Exception\ClientException
* @expectedExceptionCode 0
*/
public function test_issueAccessToken_refreshTokenGrant_badNewScopes()
{
$this->client->shouldReceive('getClient')->andReturn(array(
'client_id' => 1234,
'client_secret' => 5678,
'redirect_uri' => 'http://foo/redirect',
'name' => 'Example Client'
));
$this->session->shouldReceive('validateRefreshToken')->andReturn(1);
$this->session->shouldReceive('validateAuthCode')->andReturn(1);
$this->session->shouldReceive('updateSession')->andReturn(null);
$this->session->shouldReceive('updateRefreshToken')->andReturn(null);
$this->session->shouldReceive('getAccessToken')->andReturn(null);
$this->session->shouldReceive('getScopes')->andReturn(array(array('id' => 1, 'scope' => 'foo'), array('id' => 2, 'scope' => 'bar')));
$this->session->shouldReceive('associateAccessToken')->andReturn(1);
$this->session->shouldReceive('associateRefreshToken')->andReturn(1);
$this->session->shouldReceive('removeRefreshToken')->andReturn(1);
$this->session->shouldReceive('associateScope')->andReturn(null);
$this->scope->shouldReceive('getScope')->andReturn(array('id' => 1, 'scope' => 'foo'));
$a = $this->returnDefault();
$grant = new League\OAuth2\Server\Grant\RefreshToken($a);
$grant->setAccessTokenTTL(30);
$grant->rotateRefreshTokens(true);
$a->addGrantType($grant);
$a->issueAccessToken(array(
'grant_type' => 'refresh_token',
'client_id' => 1234,
'client_secret' => 5678,
'refresh_token' => 'abcdef',
'scope' => 'foobar'
));
}
} }

View File

@ -83,6 +83,24 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase
$method->invoke($s); $method->invoke($s);
} }
/**
* @expectedException League\OAuth2\Server\Exception\InvalidAccessTokenException
*/
public function test_determineAccessToken_brokenCurlRequest()
{
$_SERVER['HTTP_AUTHORIZATION'] = 'Bearer, Bearer abcdef';
$request = new League\OAuth2\Server\Util\Request(array(), array(), array(), array(), $_SERVER);
$s = $this->returnDefault();
$s->setRequest($request);
$reflector = new ReflectionClass($s);
$method = $reflector->getMethod('determineAccessToken');
$method->setAccessible(true);
$method->invoke($s);
}
public function test_determineAccessToken_fromHeader() public function test_determineAccessToken_fromHeader()
{ {
$request = new League\OAuth2\Server\Util\Request(); $request = new League\OAuth2\Server\Util\Request();
@ -106,6 +124,29 @@ class Resource_Server_test extends PHPUnit_Framework_TestCase
$this->assertEquals('abcdef', $result); $this->assertEquals('abcdef', $result);
} }
public function test_determineAccessToken_fromBrokenCurlHeader()
{
$request = new League\OAuth2\Server\Util\Request();
$requestReflector = new ReflectionClass($request);
$param = $requestReflector->getProperty('headers');
$param->setAccessible(true);
$param->setValue($request, array(
'Authorization' => 'Bearer abcdef, Bearer abcdef'
));
$s = $this->returnDefault();
$s->setRequest($request);
$reflector = new ReflectionClass($s);
$method = $reflector->getMethod('determineAccessToken');
$method->setAccessible(true);
$result = $method->invoke($s);
$this->assertEquals('abcdef', $result);
}
public function test_determineAccessToken_fromMethod() public function test_determineAccessToken_fromMethod()
{ {
$s = $this->returnDefault(); $s = $this->returnDefault();