diff options
author | Morris Jobke <hey@morrisjobke.de> | 2018-05-23 16:42:22 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-05-23 16:42:22 +0300 |
commit | 2f059d1caf006253ccfa9334702f86469cc3a3c8 (patch) | |
tree | 44b0f33cf4c609e1280a71fd1ce543ea14582872 /lib | |
parent | 01d3586a0ff930fb8fe5d05d0be98d39c5ed2a35 (diff) | |
parent | 3c002706a4d1e264518b1017f3a8d32576c9e9f8 (diff) |
Merge pull request #9540 from nextcloud/backport/9517/stable13
[stable13] Improve OAuth
Diffstat (limited to 'lib')
-rw-r--r-- | lib/composer/composer/ClassLoader.php | 15 | ||||
-rw-r--r-- | lib/composer/composer/autoload_classmap.php | 2 | ||||
-rw-r--r-- | lib/composer/composer/autoload_static.php | 14 | ||||
-rw-r--r-- | lib/private/Authentication/Exceptions/ExpiredTokenException.php | 40 | ||||
-rw-r--r-- | lib/private/Authentication/Token/DefaultToken.php | 26 | ||||
-rw-r--r-- | lib/private/Authentication/Token/DefaultTokenMapper.php | 6 | ||||
-rw-r--r-- | lib/private/Authentication/Token/DefaultTokenProvider.php | 41 | ||||
-rw-r--r-- | lib/private/Authentication/Token/IProvider.php | 12 | ||||
-rw-r--r-- | lib/private/Authentication/Token/IToken.php | 21 |
9 files changed, 160 insertions, 17 deletions
diff --git a/lib/composer/composer/ClassLoader.php b/lib/composer/composer/ClassLoader.php index c6f6d2322bb..dc02dfb114f 100644 --- a/lib/composer/composer/ClassLoader.php +++ b/lib/composer/composer/ClassLoader.php @@ -43,8 +43,7 @@ namespace Composer\Autoload; class ClassLoader { // PSR-4 - private $firstCharsPsr4 = array(); - private $prefixLengthsPsr4 = array(); // For BC with legacy static maps + private $prefixLengthsPsr4 = array(); private $prefixDirsPsr4 = array(); private $fallbackDirsPsr4 = array(); @@ -171,10 +170,11 @@ class ClassLoader } } elseif (!isset($this->prefixDirsPsr4[$prefix])) { // Register directories for a new namespace. - if ('\\' !== substr($prefix, -1)) { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); } - $this->firstCharsPsr4[$prefix[0]] = true; + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; $this->prefixDirsPsr4[$prefix] = (array) $paths; } elseif ($prepend) { // Prepend directories for an already registered namespace. @@ -221,10 +221,11 @@ class ClassLoader if (!$prefix) { $this->fallbackDirsPsr4 = (array) $paths; } else { - if ('\\' !== substr($prefix, -1)) { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); } - $this->firstCharsPsr4[$prefix[0]] = true; + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; $this->prefixDirsPsr4[$prefix] = (array) $paths; } } @@ -372,7 +373,7 @@ class ClassLoader $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; $first = $class[0]; - if (isset($this->firstCharsPsr4[$first]) || isset($this->prefixLengthsPsr4[$first])) { + if (isset($this->prefixLengthsPsr4[$first])) { $subPath = $class; while (false !== $lastPos = strrpos($subPath, '\\')) { $subPath = substr($subPath, 0, $lastPos); diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index e9de3538b77..8d7a4a7b57d 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -394,6 +394,7 @@ return array( 'OC\\Authentication\\Token\\DefaultTokenCleanupJob' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenCleanupJob.php', 'OC\\Authentication\\Token\\DefaultTokenMapper' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenMapper.php', 'OC\\Authentication\\Token\\DefaultTokenProvider' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenProvider.php', + 'OC\\Authentication\\Token\\ExpiredTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php', 'OC\\Authentication\\Token\\IProvider' => $baseDir . '/lib/private/Authentication/Token/IProvider.php', 'OC\\Authentication\\Token\\IToken' => $baseDir . '/lib/private/Authentication/Token/IToken.php', 'OC\\Authentication\\TwoFactorAuth\\Manager' => $baseDir . '/lib/private/Authentication/TwoFactorAuth/Manager.php', @@ -537,6 +538,7 @@ return array( 'OC\\Core\\Migrations\\Version13000Date20170814074715' => $baseDir . '/core/Migrations/Version13000Date20170814074715.php', 'OC\\Core\\Migrations\\Version13000Date20170919121250' => $baseDir . '/core/Migrations/Version13000Date20170919121250.php', 'OC\\Core\\Migrations\\Version13000Date20170926101637' => $baseDir . '/core/Migrations/Version13000Date20170926101637.php', + 'OC\\Core\\Migrations\\Version13000Date20180516101403' => $baseDir . '/core/Migrations/Version13000Date20180516101403.php', 'OC\\DB\\Adapter' => $baseDir . '/lib/private/DB/Adapter.php', 'OC\\DB\\AdapterMySQL' => $baseDir . '/lib/private/DB/AdapterMySQL.php', 'OC\\DB\\AdapterOCI8' => $baseDir . '/lib/private/DB/AdapterOCI8.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 9988e2118f4..ba65c44f79d 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -6,8 +6,14 @@ namespace Composer\Autoload; class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c { - public static $firstCharsPsr4 = array ( - 'O' => true, + public static $prefixLengthsPsr4 = array ( + 'O' => + array ( + 'OC\\Settings\\' => 12, + 'OC\\Core\\' => 8, + 'OC\\' => 3, + 'OCP\\' => 4, + ), ); public static $prefixDirsPsr4 = array ( @@ -418,6 +424,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Authentication\\Token\\DefaultTokenCleanupJob' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenCleanupJob.php', 'OC\\Authentication\\Token\\DefaultTokenMapper' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenMapper.php', 'OC\\Authentication\\Token\\DefaultTokenProvider' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenProvider.php', + 'OC\\Authentication\\Token\\ExpiredTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/ExpiredTokenException.php', 'OC\\Authentication\\Token\\IProvider' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/IProvider.php', 'OC\\Authentication\\Token\\IToken' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/IToken.php', 'OC\\Authentication\\TwoFactorAuth\\Manager' => __DIR__ . '/../../..' . '/lib/private/Authentication/TwoFactorAuth/Manager.php', @@ -561,6 +568,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Core\\Migrations\\Version13000Date20170814074715' => __DIR__ . '/../../..' . '/core/Migrations/Version13000Date20170814074715.php', 'OC\\Core\\Migrations\\Version13000Date20170919121250' => __DIR__ . '/../../..' . '/core/Migrations/Version13000Date20170919121250.php', 'OC\\Core\\Migrations\\Version13000Date20170926101637' => __DIR__ . '/../../..' . '/core/Migrations/Version13000Date20170926101637.php', + 'OC\\Core\\Migrations\\Version13000Date20180516101403' => __DIR__ . '/../../..' . '/core/Migrations/Version13000Date20180516101403.php', 'OC\\DB\\Adapter' => __DIR__ . '/../../..' . '/lib/private/DB/Adapter.php', 'OC\\DB\\AdapterMySQL' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterMySQL.php', 'OC\\DB\\AdapterOCI8' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterOCI8.php', @@ -986,7 +994,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->firstCharsPsr4 = ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c::$firstCharsPsr4; + $loader->prefixLengthsPsr4 = ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c::$prefixLengthsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c::$prefixDirsPsr4; $loader->classMap = ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c::$classMap; diff --git a/lib/private/Authentication/Exceptions/ExpiredTokenException.php b/lib/private/Authentication/Exceptions/ExpiredTokenException.php new file mode 100644 index 00000000000..8abf01bae09 --- /dev/null +++ b/lib/private/Authentication/Exceptions/ExpiredTokenException.php @@ -0,0 +1,40 @@ +<?php +/** + * @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl> + * + * @author Roeland Jago Douma <roeland@famdouma.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OC\Authentication\Token; + +use OC\Authentication\Exceptions\InvalidTokenException; + +class ExpiredTokenException extends InvalidTokenException { + /** @var IToken */ + private $token; + + public function __construct(IToken $token) { + parent::__construct(); + + $this->token = $token; + } + + public function getToken() { + return $this->token; + } +} diff --git a/lib/private/Authentication/Token/DefaultToken.php b/lib/private/Authentication/Token/DefaultToken.php index e06803d0bfc..f41d0b8b7c4 100644 --- a/lib/private/Authentication/Token/DefaultToken.php +++ b/lib/private/Authentication/Token/DefaultToken.php @@ -29,10 +29,8 @@ use OCP\AppFramework\Db\Entity; * @method void setId(int $id) * @method void setUid(string $uid); * @method void setLoginName(string $loginName) - * @method void setPassword(string $password) * @method void setName(string $name) * @method string getName() - * @method void setToken(string $token) * @method string getToken() * @method void setType(string $type) * @method int getType() @@ -93,10 +91,15 @@ class DefaultToken extends Entity implements IToken { */ protected $scope; + /** @var int */ + protected $expires; + public function __construct() { $this->addType('type', 'int'); $this->addType('lastActivity', 'int'); $this->addType('lastCheck', 'int'); + $this->addType('scope', 'string'); + $this->addType('expires', 'int'); } public function getId() { @@ -174,4 +177,23 @@ class DefaultToken extends Entity implements IToken { parent::setScope((string)$scope); } } + + public function setToken($token) { + parent::setToken($token); + } + + public function setPassword($password = null) { + parent::setPassword($password); + } + + public function setExpires($expires) { + parent::setExpires($expires); + } + + /** + * @return int|null + */ + public function getExpires() { + return parent::getExpires(); + } } diff --git a/lib/private/Authentication/Token/DefaultTokenMapper.php b/lib/private/Authentication/Token/DefaultTokenMapper.php index 41d1b9f203d..70a450602da 100644 --- a/lib/private/Authentication/Token/DefaultTokenMapper.php +++ b/lib/private/Authentication/Token/DefaultTokenMapper.php @@ -78,7 +78,7 @@ class DefaultTokenMapper extends Mapper { public function getToken($token) { /* @var $qb IQueryBuilder */ $qb = $this->db->getQueryBuilder(); - $result = $qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'remember', 'token', 'last_activity', 'last_check', 'scope') + $result = $qb->select('*') ->from('authtoken') ->where($qb->expr()->eq('token', $qb->createNamedParameter($token))) ->execute(); @@ -101,7 +101,7 @@ class DefaultTokenMapper extends Mapper { public function getTokenById($id) { /* @var $qb IQueryBuilder */ $qb = $this->db->getQueryBuilder(); - $result = $qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'token', 'last_activity', 'last_check', 'scope') + $result = $qb->select('*') ->from('authtoken') ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))) ->execute(); @@ -126,7 +126,7 @@ class DefaultTokenMapper extends Mapper { public function getTokenByUser(IUser $user) { /* @var $qb IQueryBuilder */ $qb = $this->db->getQueryBuilder(); - $qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'remember', 'token', 'last_activity', 'last_check', 'scope') + $qb->select('*') ->from('authtoken') ->where($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID()))) ->setMaxResults(1000); diff --git a/lib/private/Authentication/Token/DefaultTokenProvider.php b/lib/private/Authentication/Token/DefaultTokenProvider.php index 36a8b1d5464..4e87424e55c 100644 --- a/lib/private/Authentication/Token/DefaultTokenProvider.php +++ b/lib/private/Authentication/Token/DefaultTokenProvider.php @@ -155,13 +155,20 @@ class DefaultTokenProvider implements IProvider { * @param string $tokenId * @throws InvalidTokenException * @return DefaultToken + * @throws ExpiredTokenException */ public function getToken($tokenId) { try { - return $this->mapper->getToken($this->hashToken($tokenId)); + $token = $this->mapper->getToken($this->hashToken($tokenId)); } catch (DoesNotExistException $ex) { throw new InvalidTokenException(); } + + if ($token->getExpires() !== null && $token->getExpires() < $this->time->getTime()) { + throw new ExpiredTokenException($token); + } + + return $token; } /** @@ -170,13 +177,21 @@ class DefaultTokenProvider implements IProvider { * @param string $tokenId * @throws InvalidTokenException * @return DefaultToken + * @throws ExpiredTokenException + * @return IToken */ public function getTokenById($tokenId) { try { - return $this->mapper->getTokenById($tokenId); + $token = $this->mapper->getTokenById($tokenId); } catch (DoesNotExistException $ex) { throw new InvalidTokenException(); } + + if ($token->getExpires() !== null && $token->getExpires() < $this->time->getTime()) { + throw new ExpiredTokenException($token); + } + + return $token; } /** @@ -267,6 +282,28 @@ class DefaultTokenProvider implements IProvider { } /** + * Rotate the token. Usefull for for example oauth tokens + * + * @param IToken $token + * @param string $oldTokenId + * @param string $newTokenId + * @return IToken + */ + public function rotate(IToken $token, $oldTokenId, $newTokenId) { + try { + $password = $this->getPassword($token, $oldTokenId); + $token->setPassword($this->encryptPassword($password, $newTokenId)); + } catch (PasswordlessTokenException $e) { + + } + + $token->setToken($this->hashToken($newTokenId)); + $this->updateToken($token); + + return $token; + } + + /** * @param string $token * @return string */ diff --git a/lib/private/Authentication/Token/IProvider.php b/lib/private/Authentication/Token/IProvider.php index e1cc8182ff0..8b812a9533c 100644 --- a/lib/private/Authentication/Token/IProvider.php +++ b/lib/private/Authentication/Token/IProvider.php @@ -51,6 +51,7 @@ interface IProvider { * * @param string $tokenId * @throws InvalidTokenException + * @throws ExpiredTokenException * @return IToken */ public function getToken($tokenId); @@ -61,6 +62,7 @@ interface IProvider { * @param string $tokenId * @throws InvalidTokenException * @return DefaultToken + * @throws ExpiredTokenException */ public function getTokenById($tokenId); @@ -138,4 +140,14 @@ interface IProvider { * @throws InvalidTokenException */ public function setPassword(IToken $token, $tokenId, $password); + + /** + * Rotate the token. Usefull for for example oauth tokens + * + * @param IToken $token + * @param string $oldTokenId + * @param string $newTokenId + * @return IToken + */ + public function rotate(IToken $token, $oldTokenId, $newTokenId); } diff --git a/lib/private/Authentication/Token/IToken.php b/lib/private/Authentication/Token/IToken.php index a24d31e2ed2..6586a5b2fd7 100644 --- a/lib/private/Authentication/Token/IToken.php +++ b/lib/private/Authentication/Token/IToken.php @@ -94,4 +94,25 @@ interface IToken extends JsonSerializable { * @param array $scope */ public function setScope($scope); + + /** + * Set the token + * + * @param string $token + */ + public function setToken($token); + + /** + * Set the password + * + * @param string $password + */ + public function setPassword($password); + + /** + * Set the expiration time of the token + * + * @param int|null $expires + */ + public function setExpires($expires); } |