From 3617a3b37d9b7cd85e60371f629552272267a81e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 9 May 2013 07:17:41 -0700 Subject: [PATCH 1/6] Renamed primary key in oauth_client_endpoints table --- sql/mysql.sql | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sql/mysql.sql b/sql/mysql.sql index f61886659..7db701896 100644 --- a/sql/mysql.sql +++ b/sql/mysql.sql @@ -8,13 +8,13 @@ CREATE TABLE `oauth_clients` ( ) ENGINE=INNODB DEFAULT CHARSET=utf8; CREATE TABLE `oauth_client_endpoints` ( - `endpoint_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, - `client_id` CHAR(40) NOT NULL, - `redirect_uri` VARCHAR(255) NOT NULL, - PRIMARY KEY (`endpoint_id`), + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `client_id` char(40) NOT NULL, + `redirect_uri` varchar(255) NOT NULL, + 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; CREATE TABLE `oauth_sessions` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, From 86a483f28834f05474aec12afa4f78923903b830 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 9 May 2013 07:54:09 -0700 Subject: [PATCH 2/6] Adding missing column to oauth_session_authcodes --- sql/mysql.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/mysql.sql b/sql/mysql.sql index 7db701896..925b202f6 100644 --- a/sql/mysql.sql +++ b/sql/mysql.sql @@ -41,6 +41,7 @@ CREATE TABLE `oauth_session_authcodes` ( `session_id` int(10) unsigned NOT NULL, `auth_code` char(40) NOT NULL DEFAULT '', `auth_code_expires` int(10) unsigned NOT NULL, + `scope_ids` char(255) DEFAULT NULL, PRIMARY KEY (`session_id`), CONSTRAINT `f_oaseau_seid` FOREIGN KEY (`session_id`) REFERENCES `oauth_sessions` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=utf8; From c0683586e2fe6e03b219edb54b305e6ec05e20b2 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 9 May 2013 07:55:10 -0700 Subject: [PATCH 3/6] A refresh token should be bound to a client ID --- sql/mysql.sql | 3 +++ src/League/OAuth2/Server/Grant/AuthCode.php | 2 +- src/League/OAuth2/Server/Grant/Password.php | 2 +- src/League/OAuth2/Server/Grant/RefreshToken.php | 4 ++-- src/League/OAuth2/Server/Storage/PDO/Session.php | 12 +++++++----- .../OAuth2/Server/Storage/SessionInterface.php | 8 +++++--- 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/sql/mysql.sql b/sql/mysql.sql index 925b202f6..11b0de2a6 100644 --- a/sql/mysql.sql +++ b/sql/mysql.sql @@ -57,7 +57,10 @@ CREATE TABLE `oauth_session_refresh_tokens` ( `session_access_token_id` int(10) unsigned NOT NULL, `refresh_token` char(40) NOT NULL DEFAULT '', `refresh_token_expires` int(10) unsigned NOT NULL, + `client_id` char(40) NOT NULL DEFAULT '', PRIMARY KEY (`session_access_token_id`), + 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; diff --git a/src/League/OAuth2/Server/Grant/AuthCode.php b/src/League/OAuth2/Server/Grant/AuthCode.php index 9ea1e9dae..504a729a8 100644 --- a/src/League/OAuth2/Server/Grant/AuthCode.php +++ b/src/League/OAuth2/Server/Grant/AuthCode.php @@ -283,7 +283,7 @@ public function completeFlow($inputParams = null) if ($this->authServer->hasGrantType('refresh_token')) { $refreshToken = SecureKey::make(); $refreshTokenTTL = time() + $this->authServer->getGrantType('refresh_token')->getRefreshTokenTTL(); - $this->authServer->getStorage('session')->associateRefreshToken($accessTokenId, $refreshToken, $refreshTokenTTL); + $this->authServer->getStorage('session')->associateRefreshToken($accessTokenId, $refreshToken, $refreshTokenTTL, $authParams['client_id']); $response['refresh_token'] = $refreshToken; } diff --git a/src/League/OAuth2/Server/Grant/Password.php b/src/League/OAuth2/Server/Grant/Password.php index 45e6c0eeb..e59f5ecfa 100644 --- a/src/League/OAuth2/Server/Grant/Password.php +++ b/src/League/OAuth2/Server/Grant/Password.php @@ -214,7 +214,7 @@ public function completeFlow($inputParams = null) if ($this->authServer->hasGrantType('refresh_token')) { $refreshToken = SecureKey::make(); $refreshTokenTTL = time() + $this->authServer->getGrantType('refresh_token')->getRefreshTokenTTL(); - $this->authServer->getStorage('session')->associateRefreshToken($accessTokenId, $refreshToken, $refreshTokenTTL); + $this->authServer->getStorage('session')->associateRefreshToken($accessTokenId, $refreshToken, $refreshTokenTTL, $authParams['client_id']); $response['refresh_token'] = $refreshToken; } diff --git a/src/League/OAuth2/Server/Grant/RefreshToken.php b/src/League/OAuth2/Server/Grant/RefreshToken.php index fe62291d4..cf5dfe3b2 100644 --- a/src/League/OAuth2/Server/Grant/RefreshToken.php +++ b/src/League/OAuth2/Server/Grant/RefreshToken.php @@ -143,7 +143,7 @@ public function completeFlow($inputParams = null) } // Validate refresh token - $accessTokenId = $this->authServer->getStorage('session')->validateRefreshToken($authParams['refresh_token']); + $accessTokenId = $this->authServer->getStorage('session')->validateRefreshToken($authParams['refresh_token'], $authParams['client_id']); if ($accessTokenId === false) { throw new Exception\ClientException($this->authServer->getExceptionMessage('invalid_refresh'), 0); @@ -168,7 +168,7 @@ public function completeFlow($inputParams = null) $this->authServer->getStorage('session')->associateScope($newAccessTokenId, $scope['id']); } - $this->authServer->getStorage('session')->associateRefreshToken($newAccessTokenId, $refreshToken, $refreshTokenExpires); + $this->authServer->getStorage('session')->associateRefreshToken($newAccessTokenId, $refreshToken, $refreshTokenExpires, $authParams['client_id']); return array( 'access_token' => $accessToken, diff --git a/src/League/OAuth2/Server/Storage/PDO/Session.php b/src/League/OAuth2/Server/Storage/PDO/Session.php index cc2b21ba0..34321039a 100644 --- a/src/League/OAuth2/Server/Storage/PDO/Session.php +++ b/src/League/OAuth2/Server/Storage/PDO/Session.php @@ -91,15 +91,16 @@ public function associateAccessToken($sessionId, $accessToken, $expireTime) * @param int $expireTime Unix timestamp of the refresh token expiry time * @return void */ - public function associateRefreshToken($accessTokenId, $refreshToken, $expireTime) + public function associateRefreshToken($accessTokenId, $refreshToken, $expireTime, $clientId) { $db = \ezcDbInstance::get(); - $stmt = $db->prepare('INSERT INTO oauth_session_refresh_tokens (session_access_token_id, refresh_token, refresh_token_expires) VALUE - (:accessTokenId, :refreshToken, :expireTime)'); + $stmt = $db->prepare('INSERT INTO oauth_session_refresh_tokens (session_access_token_id, refresh_token, refresh_token_expires, client_id) VALUE + (:accessTokenId, :refreshToken, :expireTime, :clientId)'); $stmt->bindValue(':accessTokenId', $accessTokenId); $stmt->bindValue(':refreshToken', $refreshToken); $stmt->bindValue(':expireTime', $expireTime); + $stmt->bindValue(':clientId', $clientId); $stmt->execute(); } @@ -188,13 +189,14 @@ public function validateAccessToken($accessToken) * @param string $refreshToken The access token * @return void */ - public function validateRefreshToken($refreshToken) + public function validateRefreshToken($refreshToken, $clientId) { $db = \ezcDbInstance::get(); $stmt = $db->prepare('SELECT session_access_token_id FROM `oauth_session_refresh_tokens` WHERE - refresh_token = :refreshToken AND refresh_token_expires >= ' . time()); + refresh_token = :refreshToken AND client_id = :clientId AND refresh_token_expires >= ' . time()); $stmt->bindValue(':refreshToken', $refreshToken); + $stmt->bindValue(':clientId', $clientId); $stmt->execute(); $result = $stmt->fetchObject(); diff --git a/src/League/OAuth2/Server/Storage/SessionInterface.php b/src/League/OAuth2/Server/Storage/SessionInterface.php index 5cd5c84f6..46c207a8e 100644 --- a/src/League/OAuth2/Server/Storage/SessionInterface.php +++ b/src/League/OAuth2/Server/Storage/SessionInterface.php @@ -91,9 +91,10 @@ public function associateAccessToken($sessionId, $accessToken, $expireTime); * @param int $accessTokenId The access token ID * @param string $refreshToken The refresh token * @param int $expireTime Unix timestamp of the refresh token expiry time + * @param string $clientId The client ID * @return void */ - public function associateRefreshToken($accessTokenId, $refreshToken, $expireTime); + public function associateRefreshToken($accessTokenId, $refreshToken, $expireTime, $clientId); /** * Assocate an authorization code with a session @@ -191,13 +192,14 @@ public function validateAccessToken($accessToken); * * * SELECT session_access_token_id FROM `oauth_session_refresh_tokens` WHERE refresh_token = :refreshToken - * AND refresh_token_expires >= UNIX_TIMESTAMP(NOW()) + * AND refresh_token_expires >= UNIX_TIMESTAMP(NOW()) AND client_id = :clientId * * * @param string $refreshToken The access token + * @param string $clientId The client ID * @return int|bool The ID of the access token the refresh token is linked to (or false if invalid) */ - public function validateRefreshToken($refreshToken); + public function validateRefreshToken($refreshToken, $clientId); /** * Get an access token by ID From 77fbb2a851bf23d6b237653ad0f000ab5deac75a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 9 May 2013 07:55:54 -0700 Subject: [PATCH 4/6] Removed docblocks from session PDO class --- .../OAuth2/Server/Storage/PDO/Session.php | 80 ------------------- 1 file changed, 80 deletions(-) diff --git a/src/League/OAuth2/Server/Storage/PDO/Session.php b/src/League/OAuth2/Server/Storage/PDO/Session.php index 34321039a..3f16b0746 100644 --- a/src/League/OAuth2/Server/Storage/PDO/Session.php +++ b/src/League/OAuth2/Server/Storage/PDO/Session.php @@ -6,13 +6,6 @@ class Session implements SessionInterface { - /** - * Create a new session - * @param string $clientId The client ID - * @param string $ownerType The type of the session owner (e.g. "user") - * @param string $ownerId The ID of the session owner (e.g. "123") - * @return int The session ID - */ public function createSession($clientId, $ownerType, $ownerId) { $db = \ezcDbInstance::get(); @@ -27,13 +20,6 @@ public function createSession($clientId, $ownerType, $ownerId) return $db->lastInsertId(); } - /** - * Delete a session - * @param string $clientId The client ID - * @param string $ownerType The type of the session owner (e.g. "user") - * @param string $ownerId The ID of the session owner (e.g. "123") - * @return void - */ public function deleteSession($clientId, $ownerType, $ownerId) { $db = \ezcDbInstance::get(); @@ -46,12 +32,6 @@ public function deleteSession($clientId, $ownerType, $ownerId) $stmt->execute(); } - /** - * Associate a redirect URI with a session - * @param int $sessionId The session ID - * @param string $redirectUri The redirect URI - * @return void - */ public function associateRedirectUri($sessionId, $redirectUri) { $db = \ezcDbInstance::get(); @@ -63,13 +43,6 @@ public function associateRedirectUri($sessionId, $redirectUri) $stmt->execute(); } - /** - * Associate an access token with a session - * @param int $sessionId The session ID - * @param string $accessToken The access token - * @param int $expireTime Unix timestamp of the access token expiry time - * @return void - */ public function associateAccessToken($sessionId, $accessToken, $expireTime) { $db = \ezcDbInstance::get(); @@ -84,13 +57,6 @@ public function associateAccessToken($sessionId, $accessToken, $expireTime) return $db->lastInsertId(); } - /** - * Associate a refresh token with a session - * @param int $accessTokenId The access token ID - * @param string $refreshToken The refresh token - * @param int $expireTime Unix timestamp of the refresh token expiry time - * @return void - */ public function associateRefreshToken($accessTokenId, $refreshToken, $expireTime, $clientId) { $db = \ezcDbInstance::get(); @@ -104,14 +70,6 @@ public function associateRefreshToken($accessTokenId, $refreshToken, $expireTime $stmt->execute(); } - /** - * Assocate an authorization code with a session - * @param int $sessionId The session ID - * @param string $authCode The authorization code - * @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 void - */ public function associateAuthCode($sessionId, $authCode, $expireTime, $scopeIds = null) { $db = \ezcDbInstance::get(); @@ -125,11 +83,6 @@ public function associateAuthCode($sessionId, $authCode, $expireTime, $scopeIds $stmt->execute(); } - /** - * Remove an associated authorization token from a session - * @param int $sessionId The session ID - * @return void - */ public function removeAuthCode($sessionId) { $db = \ezcDbInstance::get(); @@ -139,13 +92,6 @@ public function removeAuthCode($sessionId) $stmt->execute(); } - /** - * Validate an authorization code - * @param string $clientId The client ID - * @param string $redirectUri The redirect URI - * @param string $authCode The authorization code - * @return void - */ public function validateAuthCode($clientId, $redirectUri, $authCode) { $db = \ezcDbInstance::get(); @@ -167,11 +113,6 @@ public function validateAuthCode($clientId, $redirectUri, $authCode) return ($result === false) ? false : (array) $result; } - /** - * Validate an access token - * @param string $accessToken The access token to be validated - * @return void - */ public function validateAccessToken($accessToken) { $db = \ezcDbInstance::get(); @@ -184,11 +125,6 @@ public function validateAccessToken($accessToken) return ($result === false) ? false : (array) $result; } - /** - * Validate a refresh token - * @param string $refreshToken The access token - * @return void - */ public function validateRefreshToken($refreshToken, $clientId) { $db = \ezcDbInstance::get(); @@ -203,11 +139,6 @@ public function validateRefreshToken($refreshToken, $clientId) return ($result === false) ? false : $result->session_access_token_id; } - /** - * Get an access token by ID - * @param int $accessTokenId The access token ID - * @return array - */ public function getAccessToken($accessTokenId) { $db = \ezcDbInstance::get(); @@ -220,12 +151,6 @@ public function getAccessToken($accessTokenId) return ($result === false) ? false : (array) $result; } - /** - * Associate a scope with an access token - * @param int $accessTokenId The ID of the access token - * @param int $scopeId The ID of the scope - * @return void - */ public function associateScope($accessTokenId, $scopeId) { $db = \ezcDbInstance::get(); @@ -237,11 +162,6 @@ public function associateScope($accessTokenId, $scopeId) $stmt->execute(); } - /** - * Get all associated access tokens for an access token - * @param string $accessToken The access token - * @return array - */ public function getScopes($accessToken) { $db = \ezcDbInstance::get(); From 9f9a8282941402f6a108da8b62f22f4aa3b52a9a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 9 May 2013 08:01:18 -0700 Subject: [PATCH 5/6] Updated changelog --- CHANGELOG.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30712a491..a903ab1d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,22 @@ # Changelog -## 2.0.0 (released 2013-05-06) +## 2.0.4 (released 2013-05-09) + +* Renamed primary key in oauth_client_endpoints table +* Adding missing column to oauth_session_authcodes +* SECURITY FIX: A refresh token should be bound to a client ID + +## 2.0.3 (released 2013-05-08) + +* Fixed a link to code in composer.json + +## 2.0.2 (released 2013-05-08) + +* Updated README with wiki guides +* Removed `null` as default parameters in some methods in the storage interfaces +* Fixed license copyright + +## 2.0.0 (released 2013-05-08) **If you're upgrading from v1.0.8 there are lots of breaking changes** From 08a705567969301f3faa7fa3f03633f0ef0e7fde Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 9 May 2013 08:01:25 -0700 Subject: [PATCH 6/6] Version bump --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b3c7e009d..2029ee459 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "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": "2.0.3", + "version": "2.0.4", "homepage": "https://github.com/php-loep/oauth2-server", "license": "MIT", "require": {