diff options
author | Morris Jobke <hey@morrisjobke.de> | 2018-10-02 22:45:10 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-02 22:45:10 +0300 |
commit | 6b730b4c478bc4f55a89fd7d6a7c2715e2e5b829 (patch) | |
tree | 06218c0625e5ddc4045a7990347bcb8ca7fdc5ce /lib | |
parent | 19d552e00b16d8b5423b01755b5b1027df5a21ed (diff) | |
parent | 19f84f7b5485e204014671d0439e8af5693acbb1 (diff) |
Merge pull request #11390 from nextcloud/feature/11043/apptoken_v3
Apptoken v3: imrpove token handling on external password change
Diffstat (limited to 'lib')
-rw-r--r-- | lib/composer/composer/autoload_classmap.php | 1 | ||||
-rw-r--r-- | lib/composer/composer/autoload_static.php | 1 | ||||
-rw-r--r-- | lib/private/Authentication/Token/DefaultTokenProvider.php | 12 | ||||
-rw-r--r-- | lib/private/Authentication/Token/IProvider.php | 16 | ||||
-rw-r--r-- | lib/private/Authentication/Token/Manager.php | 12 | ||||
-rw-r--r-- | lib/private/Authentication/Token/PublicKeyToken.php | 9 | ||||
-rw-r--r-- | lib/private/Authentication/Token/PublicKeyTokenMapper.php | 15 | ||||
-rw-r--r-- | lib/private/Authentication/Token/PublicKeyTokenProvider.php | 26 | ||||
-rw-r--r-- | lib/private/User/Session.php | 17 |
9 files changed, 106 insertions, 3 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 2522be9ec8f..7de8d3a4429 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -626,6 +626,7 @@ return array( 'OC\\Core\\Migrations\\Version14000Date20180626223656' => $baseDir . '/core/Migrations/Version14000Date20180626223656.php', 'OC\\Core\\Migrations\\Version14000Date20180710092004' => $baseDir . '/core/Migrations/Version14000Date20180710092004.php', 'OC\\Core\\Migrations\\Version14000Date20180712153140' => $baseDir . '/core/Migrations/Version14000Date20180712153140.php', + 'OC\\Core\\Migrations\\Version15000Date20180926101451' => $baseDir . '/core/Migrations/Version15000Date20180926101451.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 e4e64ac1d55..8d92f623a09 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -656,6 +656,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Core\\Migrations\\Version14000Date20180626223656' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180626223656.php', 'OC\\Core\\Migrations\\Version14000Date20180710092004' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180710092004.php', 'OC\\Core\\Migrations\\Version14000Date20180712153140' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180712153140.php', + 'OC\\Core\\Migrations\\Version15000Date20180926101451' => __DIR__ . '/../../..' . '/core/Migrations/Version15000Date20180926101451.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', diff --git a/lib/private/Authentication/Token/DefaultTokenProvider.php b/lib/private/Authentication/Token/DefaultTokenProvider.php index ad45303fa7c..a27a875a27f 100644 --- a/lib/private/Authentication/Token/DefaultTokenProvider.php +++ b/lib/private/Authentication/Token/DefaultTokenProvider.php @@ -338,4 +338,16 @@ class DefaultTokenProvider implements IProvider { } } + public function markPasswordInvalid(IToken $token, string $tokenId) { + if (!($token instanceof DefaultToken)) { + throw new InvalidTokenException(); + } + + //No need to mark as invalid. We just invalide default tokens + $this->invalidateToken($tokenId); + } + + public function updatePasswords(string $uid, string $password) { + // Nothing to do here + } } diff --git a/lib/private/Authentication/Token/IProvider.php b/lib/private/Authentication/Token/IProvider.php index ab46bd12126..7ee76b7b384 100644 --- a/lib/private/Authentication/Token/IProvider.php +++ b/lib/private/Authentication/Token/IProvider.php @@ -156,4 +156,20 @@ interface IProvider { * @return IToken */ public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken; + + /** + * Marks a token as having an invalid password. + * + * @param IToken $token + * @param string $tokenId + */ + public function markPasswordInvalid(IToken $token, string $tokenId); + + /** + * Update all the passwords of $uid if required + * + * @param string $uid + * @param string $password + */ + public function updatePasswords(string $uid, string $password); } diff --git a/lib/private/Authentication/Token/Manager.php b/lib/private/Authentication/Token/Manager.php index 254a1598943..7c991eadea9 100644 --- a/lib/private/Authentication/Token/Manager.php +++ b/lib/private/Authentication/Token/Manager.php @@ -227,4 +227,16 @@ class Manager implements IProvider { } throw new InvalidTokenException(); } + + + public function markPasswordInvalid(IToken $token, string $tokenId) { + $this->getProvider($token)->markPasswordInvalid($token, $tokenId); + } + + public function updatePasswords(string $uid, string $password) { + $this->defaultTokenProvider->updatePasswords($uid, $password); + $this->publicKeyTokenProvider->updatePasswords($uid, $password); + } + + } diff --git a/lib/private/Authentication/Token/PublicKeyToken.php b/lib/private/Authentication/Token/PublicKeyToken.php index 0e793ce8c7c..b6f55146707 100644 --- a/lib/private/Authentication/Token/PublicKeyToken.php +++ b/lib/private/Authentication/Token/PublicKeyToken.php @@ -43,6 +43,7 @@ use OCP\AppFramework\Db\Entity; * @method string getPublicKey() * @method void setPublicKey(string $key) * @method void setVersion(int $version) + * @method bool getPasswordInvalid() */ class PublicKeyToken extends Entity implements IToken { @@ -90,6 +91,9 @@ class PublicKeyToken extends Entity implements IToken { /** @var int */ protected $version; + /** @var bool */ + protected $passwordInvalid; + public function __construct() { $this->addType('uid', 'string'); $this->addType('loginName', 'string'); @@ -105,6 +109,7 @@ class PublicKeyToken extends Entity implements IToken { $this->addType('publicKey', 'string'); $this->addType('privateKey', 'string'); $this->addType('version', 'int'); + $this->addType('passwordInvalid', 'bool'); } public function getId(): int { @@ -214,4 +219,8 @@ class PublicKeyToken extends Entity implements IToken { public function getExpires() { return parent::getExpires(); } + + public function setPasswordInvalid(bool $invalid) { + parent::setPasswordInvalid($invalid); + } } diff --git a/lib/private/Authentication/Token/PublicKeyTokenMapper.php b/lib/private/Authentication/Token/PublicKeyTokenMapper.php index 5e5c69dbc46..df91066c44f 100644 --- a/lib/private/Authentication/Token/PublicKeyTokenMapper.php +++ b/lib/private/Authentication/Token/PublicKeyTokenMapper.php @@ -169,4 +169,19 @@ class PublicKeyTokenMapper extends QBMapper { $qb->execute(); } + + public function hasExpiredTokens(string $uid): bool { + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from('authtoken') + ->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid))) + ->andWhere($qb->expr()->eq('password_invalid', $qb->createNamedParameter(true), IQueryBuilder::PARAM_BOOL)) + ->setMaxResults(1); + + $cursor = $qb->execute(); + $data = $cursor->fetchAll(); + $cursor->closeCursor(); + + return count($data) === 1; + } } diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php index 7e98ee939ce..33c0b1d59eb 100644 --- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php +++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php @@ -317,4 +317,30 @@ class PublicKeyTokenProvider implements IProvider { return $dbToken; } + + public function markPasswordInvalid(IToken $token, string $tokenId) { + if (!($token instanceof PublicKeyToken)) { + throw new InvalidTokenException(); + } + + $token->setPasswordInvalid(true); + $this->mapper->update($token); + } + + public function updatePasswords(string $uid, string $password) { + if (!$this->mapper->hasExpiredTokens($uid)) { + // Nothing to do here + return; + } + + // Update the password for all tokens + $tokens = $this->mapper->getTokenByUser($uid); + foreach ($tokens as $t) { + $publicKey = $t->getPublicKey(); + $t->setPassword($this->encryptPassword($password, $publicKey)); + $this->updateToken($t); + } + } + + } diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php index 5593e178ca3..a9c638dca93 100644 --- a/lib/private/User/Session.php +++ b/lib/private/User/Session.php @@ -694,12 +694,19 @@ class Session implements IUserSession, Emitter { return true; } - if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false - || (!is_null($this->activeUser) && !$this->activeUser->isEnabled())) { + // Invalidate token if the user is no longer active + if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) { $this->tokenProvider->invalidateToken($token); - // Password has changed or user was disabled -> log user out return false; } + + // If the token password is no longer valid mark it as such + if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false) { + $this->tokenProvider->markPasswordInvalid($dbToken, $token); + // User is logged out + return false; + } + $dbToken->setLastCheck($now); return true; } @@ -943,5 +950,9 @@ class Session implements IUserSession, Emitter { } } + public function updateTokens(string $uid, string $password) { + $this->tokenProvider->updatePasswords($uid, $password); + } + } |