summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorblizzz <blizzz@arthur-schiwon.de>2020-08-07 10:49:42 +0000
committerGitHub <noreply@github.com>2020-08-07 10:49:42 +0000
commita2c262b68a0c64b808f77a8db4a1772f009de9de (patch)
tree14457866ee3f7256fb207799f24f16b5a0b7d7e3 /apps
parent0807e29e1765dfaa184356a89ecea78cee34418e (diff)
parent0b0cc48c8830b71e9ed237c1866163bb85c5d379 (diff)
downloadnextcloud-server-a2c262b68a0c64b808f77a8db4a1772f009de9de.tar.gz
nextcloud-server-a2c262b68a0c64b808f77a8db4a1772f009de9de.zip
Merge pull request #21037 from nextcloud/login-credentails-save
Only save login credentials in database once there is an external storage that needs it
Diffstat (limited to 'apps')
-rw-r--r--apps/files_external/appinfo/info.xml4
-rw-r--r--apps/files_external/lib/BackgroundJob/CredentialsCleanup.php69
-rw-r--r--apps/files_external/lib/Lib/Auth/Password/LoginCredentials.php57
-rw-r--r--apps/files_external/lib/Listener/StorePasswordListener.php64
-rw-r--r--apps/files_external/lib/Service/UserGlobalStoragesService.php13
5 files changed, 181 insertions, 26 deletions
diff --git a/apps/files_external/appinfo/info.xml b/apps/files_external/appinfo/info.xml
index c2ac25bcea9..03a8845d3d6 100644
--- a/apps/files_external/appinfo/info.xml
+++ b/apps/files_external/appinfo/info.xml
@@ -31,6 +31,10 @@ External storage can be configured using the GUI or at the command line. This se
<nextcloud min-version="20" max-version="20"/>
</dependencies>
+ <background-jobs>
+ <job>OCA\Files_External\BackgroundJob\CredentialsCleanup</job>
+ </background-jobs>
+
<commands>
<command>OCA\Files_External\Command\ListCommand</command>
<command>OCA\Files_External\Command\Config</command>
diff --git a/apps/files_external/lib/BackgroundJob/CredentialsCleanup.php b/apps/files_external/lib/BackgroundJob/CredentialsCleanup.php
new file mode 100644
index 00000000000..80cb51f1573
--- /dev/null
+++ b/apps/files_external/lib/BackgroundJob/CredentialsCleanup.php
@@ -0,0 +1,69 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2020 Robin Appelman <robin@icewind.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 OCA\Files_External\BackgroundJob;
+
+use OCA\Files_External\Lib\Auth\Password\LoginCredentials;
+use OCA\Files_External\Lib\StorageConfig;
+use OCA\Files_External\Service\UserGlobalStoragesService;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\BackgroundJob\TimedJob;
+use OCP\Security\ICredentialsManager;
+use OCP\IUser;
+use OCP\IUserManager;
+
+class CredentialsCleanup extends TimedJob {
+ private $credentialsManager;
+ private $userGlobalStoragesService;
+ private $userManager;
+
+ public function __construct(
+ ITimeFactory $time,
+ ICredentialsManager $credentialsManager,
+ UserGlobalStoragesService $userGlobalStoragesService,
+ IUserManager $userManager
+ ) {
+ parent::__construct($time);
+
+ $this->credentialsManager = $credentialsManager;
+ $this->userGlobalStoragesService = $userGlobalStoragesService;
+ $this->userManager = $userManager;
+
+ // run every day
+ $this->setInterval(24 * 60 * 60);
+ }
+
+ protected function run($argument) {
+ $this->userManager->callForSeenUsers(function (IUser $user) {
+ $storages = $this->userGlobalStoragesService->getAllStoragesForUser($user);
+
+ $usesLoginCredentials = array_reduce($storages, function (bool $uses, StorageConfig $storage) {
+ return $uses || $storage->getAuthMechanism() instanceof LoginCredentials;
+ }, false);
+
+ if (!$usesLoginCredentials) {
+ $this->credentialsManager->delete($user->getUID(), LoginCredentials::CREDENTIALS_IDENTIFIER);
+ }
+ });
+ }
+}
diff --git a/apps/files_external/lib/Lib/Auth/Password/LoginCredentials.php b/apps/files_external/lib/Lib/Auth/Password/LoginCredentials.php
index 9f41697452f..982ef57f3e0 100644
--- a/apps/files_external/lib/Lib/Auth/Password/LoginCredentials.php
+++ b/apps/files_external/lib/Lib/Auth/Password/LoginCredentials.php
@@ -27,10 +27,16 @@ namespace OCA\Files_External\Lib\Auth\Password;
use OCA\Files_External\Lib\Auth\AuthMechanism;
use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
use OCA\Files_External\Lib\StorageConfig;
+use OCA\Files_External\Listener\StorePasswordListener;
+use OCP\Authentication\Exceptions\CredentialsUnavailableException;
+use OCP\Authentication\LoginCredentials\IStore as CredentialsStore;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\IL10N;
use OCP\ISession;
use OCP\IUser;
use OCP\Security\ICredentialsManager;
+use OCP\User\Events\PasswordUpdatedEvent;
+use OCP\User\Events\UserLoggedInEvent;
/**
* Username and password from login credentials, saved in DB
@@ -44,45 +50,52 @@ class LoginCredentials extends AuthMechanism {
/** @var ICredentialsManager */
protected $credentialsManager;
- public function __construct(IL10N $l, ISession $session, ICredentialsManager $credentialsManager) {
+ /** @var CredentialsStore */
+ private $credentialsStore;
+
+ public function __construct(IL10N $l, ISession $session, ICredentialsManager $credentialsManager, CredentialsStore $credentialsStore, IEventDispatcher $eventDispatcher) {
$this->session = $session;
$this->credentialsManager = $credentialsManager;
+ $this->credentialsStore = $credentialsStore;
$this
->setIdentifier('password::logincredentials')
->setScheme(self::SCHEME_PASSWORD)
->setText($l->t('Log-in credentials, save in database'))
->addParameters([
- ])
- ;
+ ]);
- \OCP\Util::connectHook('OC_User', 'post_login', $this, 'authenticate');
+ $eventDispatcher->addServiceListener(UserLoggedInEvent::class, StorePasswordListener::class);
+ $eventDispatcher->addServiceListener(PasswordUpdatedEvent::class, StorePasswordListener::class);
}
- /**
- * Hook listener on post login
- *
- * @param array $params
- */
- public function authenticate(array $params) {
- $userId = $params['uid'];
- $credentials = [
- 'user' => $this->session->get('loginname'),
- 'password' => $params['password']
- ];
- $this->credentialsManager->store($userId, self::CREDENTIALS_IDENTIFIER, $credentials);
+ private function getCredentials(IUser $user): array {
+ $credentials = $this->credentialsManager->retrieve($user->getUID(), self::CREDENTIALS_IDENTIFIER);
+
+ if (is_null($credentials)) {
+ // nothing saved in db, try to get it from the session and save it
+ try {
+ $sessionCredentials = $this->credentialsStore->getLoginCredentials();
+
+ $credentials = [
+ 'user' => $sessionCredentials->getLoginName(),
+ 'password' => $sessionCredentials->getPassword()
+ ];
+
+ $this->credentialsManager->store($user->getUID(), self::CREDENTIALS_IDENTIFIER, $credentials);
+ } catch (CredentialsUnavailableException $e) {
+ throw new InsufficientDataForMeaningfulAnswerException('No login credentials saved');
+ }
+ }
+
+ return $credentials;
}
public function manipulateStorageConfig(StorageConfig &$storage, IUser $user = null) {
if (!isset($user)) {
throw new InsufficientDataForMeaningfulAnswerException('No login credentials saved');
}
- $uid = $user->getUID();
- $credentials = $this->credentialsManager->retrieve($uid, self::CREDENTIALS_IDENTIFIER);
-
- if (!isset($credentials)) {
- throw new InsufficientDataForMeaningfulAnswerException('No login credentials saved');
- }
+ $credentials = $this->getCredentials($user);
$storage->setBackendOption('user', $credentials['user']);
$storage->setBackendOption('password', $credentials['password']);
diff --git a/apps/files_external/lib/Listener/StorePasswordListener.php b/apps/files_external/lib/Listener/StorePasswordListener.php
new file mode 100644
index 00000000000..3212f2a48c7
--- /dev/null
+++ b/apps/files_external/lib/Listener/StorePasswordListener.php
@@ -0,0 +1,64 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2020, Morris Jobke <hey@morrisjobke.de>
+ *
+ * @author Morris Jobke <hey@morrisjobke.de>
+ *
+ * @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 OCA\Files_External\Listener;
+
+use OCA\Files_External\Lib\Auth\Password\LoginCredentials;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\Security\ICredentialsManager;
+use OCP\User\Events\PasswordUpdatedEvent;
+use OCP\User\Events\UserLoggedInEvent;
+
+class StorePasswordListener implements IEventListener {
+ /** @var ICredentialsManager */
+ private $credentialsManager;
+
+ public function __construct(ICredentialsManager $credentialsManager) {
+ $this->credentialsManager = $credentialsManager;
+ }
+
+ public function handle(Event $event): void {
+ if (!$event instanceof UserLoggedInEvent && !$event instanceof PasswordUpdatedEvent) {
+ return;
+ }
+
+ if ($event instanceof UserLoggedInEvent && $event->isTokenLogin()) {
+ return;
+ }
+
+ $stored = $this->credentialsManager->retrieve($event->getUser()->getUID(), LoginCredentials::CREDENTIALS_IDENTIFIER);
+
+ if ($stored && $stored['password'] !== $event->getPassword()) {
+ $credentials = [
+ 'user' => $stored['user'],
+ 'password' => $event->getPassword()
+ ];
+
+ $this->credentialsManager->store($event->getUser()->getUID(), LoginCredentials::CREDENTIALS_IDENTIFIER, $credentials);
+ }
+ }
+}
diff --git a/apps/files_external/lib/Service/UserGlobalStoragesService.php b/apps/files_external/lib/Service/UserGlobalStoragesService.php
index 7b9af773233..b8ea137428f 100644
--- a/apps/files_external/lib/Service/UserGlobalStoragesService.php
+++ b/apps/files_external/lib/Service/UserGlobalStoragesService.php
@@ -27,6 +27,7 @@ namespace OCA\Files_External\Service;
use OCA\Files_External\Lib\StorageConfig;
use OCP\Files\Config\IUserMountCache;
use OCP\IGroupManager;
+use OCP\IUser;
use OCP\IUserSession;
/**
@@ -177,14 +178,18 @@ class UserGlobalStoragesService extends GlobalStoragesService {
/**
* Gets all storages for the user, admin, personal, global, etc
*
+ * @param IUser|null $user user to get the storages for, if not set the currently logged in user will be used
* @return StorageConfig[] array of storage configs
*/
- public function getAllStoragesForUser() {
- if (is_null($this->getUser())) {
+ public function getAllStoragesForUser(IUser $user = null) {
+ if (is_null($user)) {
+ $user = $this->getUser();
+ }
+ if (is_null($user)) {
return [];
}
- $groupIds = $this->groupManager->getUserGroupIds($this->getUser());
- $mounts = $this->dbConfig->getMountsForUser($this->getUser()->getUID(), $groupIds);
+ $groupIds = $this->groupManager->getUserGroupIds($user);
+ $mounts = $this->dbConfig->getMountsForUser($user->getUID(), $groupIds);
$configs = array_map([$this, 'getStorageConfigFromDBMount'], $mounts);
$configs = array_filter($configs, function ($config) {
return $config instanceof StorageConfig;