summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/Migrations/Version25000Date20220905140840.php57
-rw-r--r--lib/composer/composer/autoload_classmap.php1
-rw-r--r--lib/composer/composer/autoload_static.php1
-rw-r--r--lib/private/Authentication/Token/PublicKeyToken.php6
-rw-r--r--lib/private/Authentication/Token/PublicKeyTokenProvider.php20
-rw-r--r--tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php2
-rw-r--r--version.php2
7 files changed, 84 insertions, 5 deletions
diff --git a/core/Migrations/Version25000Date20220905140840.php b/core/Migrations/Version25000Date20220905140840.php
new file mode 100644
index 00000000000..6cda6132a7f
--- /dev/null
+++ b/core/Migrations/Version25000Date20220905140840.php
@@ -0,0 +1,57 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2022 Marcel Klehr <mklehr@gmx.net>
+ *
+ * @author Marcel Klehr <mklehr@gmx.net>
+ *
+ * @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\Core\Migrations;
+
+use Closure;
+use OCP\DB\ISchemaWrapper;
+use OCP\DB\Types;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+class Version25000Date20220905140840 extends SimpleMigrationStep {
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ * @return null|ISchemaWrapper
+ */
+ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
+ /** @var ISchemaWrapper $schema */
+ $schema = $schemaClosure();
+
+ $authTokenTable = $schema->getTable('authtoken');
+ if (!$authTokenTable->hasColumn('password_hash')) {
+ $authTokenTable->addColumn('password_hash', Types::STRING, [
+ 'notnull' => false,
+ 'length' => 255,
+ ]);
+ return $schema;
+ }
+ return null;
+ }
+}
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 635318d4fcb..af114d3965f 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -1077,6 +1077,7 @@ return array(
'OC\\Core\\Migrations\\Version24000Date20220425072957' => $baseDir . '/core/Migrations/Version24000Date20220425072957.php',
'OC\\Core\\Migrations\\Version25000Date20220515204012' => $baseDir . '/core/Migrations/Version25000Date20220515204012.php',
'OC\\Core\\Migrations\\Version25000Date20220602190540' => $baseDir . '/core/Migrations/Version25000Date20220602190540.php',
+ 'OC\\Core\\Migrations\\Version25000Date20220905140840' => $baseDir . '/core/Migrations/Version25000Date20220905140840.php',
'OC\\Core\\Migrations\\Version25000Date20221007010957' => $baseDir . '/core/Migrations/Version25000Date20221007010957.php',
'OC\\Core\\Notification\\CoreNotifier' => $baseDir . '/core/Notification/CoreNotifier.php',
'OC\\Core\\Service\\LoginFlowV2Service' => $baseDir . '/core/Service/LoginFlowV2Service.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index fe105e68051..838edb14fa0 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -1110,6 +1110,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Core\\Migrations\\Version24000Date20220425072957' => __DIR__ . '/../../..' . '/core/Migrations/Version24000Date20220425072957.php',
'OC\\Core\\Migrations\\Version25000Date20220515204012' => __DIR__ . '/../../..' . '/core/Migrations/Version25000Date20220515204012.php',
'OC\\Core\\Migrations\\Version25000Date20220602190540' => __DIR__ . '/../../..' . '/core/Migrations/Version25000Date20220602190540.php',
+ 'OC\\Core\\Migrations\\Version25000Date20220905140840' => __DIR__ . '/../../..' . '/core/Migrations/Version25000Date20220905140840.php',
'OC\\Core\\Migrations\\Version25000Date20221007010957' => __DIR__ . '/../../..' . '/core/Migrations/Version25000Date20221007010957.php',
'OC\\Core\\Notification\\CoreNotifier' => __DIR__ . '/../../..' . '/core/Notification/CoreNotifier.php',
'OC\\Core\\Service\\LoginFlowV2Service' => __DIR__ . '/../../..' . '/core/Service/LoginFlowV2Service.php',
diff --git a/lib/private/Authentication/Token/PublicKeyToken.php b/lib/private/Authentication/Token/PublicKeyToken.php
index d060fe14103..45335e17c31 100644
--- a/lib/private/Authentication/Token/PublicKeyToken.php
+++ b/lib/private/Authentication/Token/PublicKeyToken.php
@@ -45,6 +45,8 @@ use OCP\AppFramework\Db\Entity;
* @method void setPublicKey(string $key)
* @method void setVersion(int $version)
* @method bool getPasswordInvalid()
+ * @method string getPasswordHash()
+ * @method setPasswordHash(string $hash)
*/
class PublicKeyToken extends Entity implements INamedToken, IWipeableToken {
public const VERSION = 2;
@@ -58,6 +60,9 @@ class PublicKeyToken extends Entity implements INamedToken, IWipeableToken {
/** @var string encrypted user password */
protected $password;
+ /** @var string hashed user password */
+ protected $passwordHash;
+
/** @var string token name (e.g. browser/OS) */
protected $name;
@@ -98,6 +103,7 @@ class PublicKeyToken extends Entity implements INamedToken, IWipeableToken {
$this->addType('uid', 'string');
$this->addType('loginName', 'string');
$this->addType('password', 'string');
+ $this->addType('passwordHash', 'string');
$this->addType('name', 'string');
$this->addType('token', 'string');
$this->addType('type', 'int');
diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php
index d00d3e41539..7f1b10e0956 100644
--- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php
+++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php
@@ -42,6 +42,7 @@ use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IUserManager;
use OCP\Security\ICrypto;
+use OCP\Security\IHasher;
use Psr\Log\LoggerInterface;
class PublicKeyTokenProvider implements IProvider {
@@ -67,12 +68,15 @@ class PublicKeyTokenProvider implements IProvider {
/** @var CappedMemoryCache */
private $cache;
+ private IHasher $hasher;
+
public function __construct(PublicKeyTokenMapper $mapper,
ICrypto $crypto,
IConfig $config,
IDBConnection $db,
LoggerInterface $logger,
- ITimeFactory $time) {
+ ITimeFactory $time,
+ IHasher $hasher) {
$this->mapper = $mapper;
$this->crypto = $crypto;
$this->config = $config;
@@ -81,6 +85,7 @@ class PublicKeyTokenProvider implements IProvider {
$this->time = $time;
$this->cache = new CappedMemoryCache();
+ $this->hasher = $hasher;
}
/**
@@ -287,10 +292,15 @@ class PublicKeyTokenProvider implements IProvider {
foreach ($tokens as $t) {
$publicKey = $t->getPublicKey();
$t->setPassword($this->encryptPassword($password, $publicKey));
+ $t->setPasswordHash($this->hashPassword($password));
$this->updateToken($t);
}
}
+ private function hashPassword(string $password): string {
+ return $this->hasher->hash(sha1($password) . $password);
+ }
+
public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken {
$this->cache->clear();
@@ -402,6 +412,7 @@ class PublicKeyTokenProvider implements IProvider {
throw new \RuntimeException('Trying to save a password with more than 469 characters is not supported. If you want to use big passwords, disable the auth.storeCryptedPassword option in config.php');
}
$dbToken->setPassword($this->encryptPassword($password, $publicKey));
+ $dbToken->setPasswordHash($this->hashPassword($password));
}
$dbToken->setName($name);
@@ -436,11 +447,12 @@ class PublicKeyTokenProvider implements IProvider {
// Update the password for all tokens
$tokens = $this->mapper->getTokenByUser($uid);
+ $passwordHash = $this->hashPassword($password);
foreach ($tokens as $t) {
$publicKey = $t->getPublicKey();
- $encryptedPassword = $this->encryptPassword($password, $publicKey);
- if ($t->getPassword() !== $encryptedPassword) {
- $t->setPassword($encryptedPassword);
+ if ($t->getPasswordHash() === null || $this->hasher->verify(sha1($password) . $password, $t->getPasswordHash())) {
+ $t->setPassword($this->encryptPassword($password, $publicKey));
+ $t->setPasswordHash($passwordHash);
$t->setPasswordInvalid(false);
$this->updateToken($t);
}
diff --git a/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php b/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php
index d6e8dba31be..ca7618dfd6d 100644
--- a/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php
+++ b/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php
@@ -64,6 +64,7 @@ class PublicKeyTokenProviderTest extends TestCase {
parent::setUp();
$this->mapper = $this->createMock(PublicKeyTokenMapper::class);
+ $this->hasher = \OC::$server->getHasher();
$this->crypto = \OC::$server->getCrypto();
$this->config = $this->createMock(IConfig::class);
$this->config->method('getSystemValue')
@@ -87,6 +88,7 @@ class PublicKeyTokenProviderTest extends TestCase {
$this->db,
$this->logger,
$this->timeFactory,
+ $this->hasher,
);
}
diff --git a/version.php b/version.php
index 882a1997d4e..17f9bb2ed1f 100644
--- a/version.php
+++ b/version.php
@@ -30,7 +30,7 @@
// between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel
// when updating major/minor version number.
-$OC_Version = [26, 0, 0, 1];
+$OC_Version = [26, 0, 0, 2];
// The human readable string
$OC_VersionString = '26.0.0 dev';