* * @author Arthur Schiwon * @author Christoph Wurst * @author Daniel Calviño Sánchez * @author Daniel Kesselberg * @author Joas Schilling * @author Julius Härtl * @author Lukas Reschke * @author Matthew Setter * @author Morris Jobke * @author Roeland Jago Douma * * @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 . * */ // FIXME: disabled for now to be able to inject IGroupManager and also use // getSubAdmin() //declare(strict_types=1); namespace OCA\Settings\Controller; use OC\Group\Manager as GroupManager; use OC\User\Session; use OCP\App\IAppManager; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\JSONResponse; use OCP\HintException; use OCP\IGroupManager; use OCP\IL10N; use OCP\IRequest; use OCP\IUser; use OCP\IUserManager; use OCP\IUserSession; class ChangePasswordController extends Controller { private ?string $userId; private IUserManager $userManager; private IL10N $l; private GroupManager $groupManager; private Session $userSession; private IAppManager $appManager; public function __construct(string $appName, IRequest $request, ?string $userId, IUserManager $userManager, IUserSession $userSession, IGroupManager $groupManager, IAppManager $appManager, IL10N $l) { parent::__construct($appName, $request); $this->userId = $userId; $this->userManager = $userManager; $this->userSession = $userSession; $this->groupManager = $groupManager; $this->appManager = $appManager; $this->l = $l; } /** * @NoAdminRequired * @NoSubAdminRequired * @BruteForceProtection(action=changePersonalPassword) */ public function changePersonalPassword(string $oldpassword = '', string $newpassword = null): JSONResponse { $loginName = $this->userSession->getLoginName(); /** @var IUser $user */ $user = $this->userManager->checkPassword($loginName, $oldpassword); if ($user === false) { $response = new JSONResponse([ 'status' => 'error', 'data' => [ 'message' => $this->l->t('Wrong password'), ], ]); $response->throttle(); return $response; } try { if ($newpassword === null || strlen($newpassword) > 469 || $user->setPassword($newpassword) === false) { return new JSONResponse([ 'status' => 'error', 'data' => [ 'message' => $this->l->t('Unable to change personal password'), ], ]); } // password policy app throws exception } catch (HintException $e) { return new JSONResponse([ 'status' => 'error', 'data' => [ 'message' => $e->getHint(), ], ]); } $this->userSession->updateSessionTokenPassword($newpassword); return new JSONResponse([ 'status' => 'success', 'data' => [ 'message' => $this->l->t('Saved'), ], ]); } /** * @NoAdminRequired * @PasswordConfirmationRequired */ public function changeUserPassword(string $username = null, string $password = null, string $recoveryPassword = null): JSONResponse { if ($username === null) { return new JSONResponse([ 'status' => 'error', 'data' => [ 'message' => $this->l->t('No user supplied'), ], ]); } if ($password === null) { return new JSONResponse([ 'status' => 'error', 'data' => [ 'message' => $this->l->t('Unable to change password'), ], ]); } if (strlen($password) > 469) { return new JSONResponse([ 'status' => 'error', 'data' => [ 'message' => $this->l->t('Unable to change password. Password too long.'), ], ]); } $currentUser = $this->userSession->getUser(); $targetUser = $this->userManager->get($username); if ($currentUser === null || $targetUser === null || !($this->groupManager->isAdmin($this->userId) || $this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $targetUser)) ) { return new JSONResponse([ 'status' => 'error', 'data' => [ 'message' => $this->l->t('Authentication error'), ], ]); } if ($this->appManager->isEnabledForUser('encryption')) { //handle the recovery case $crypt = new \OCA\Encryption\Crypto\Crypt( \OC::$server->getLogger(), \OC::$server->getUserSession(), \OC::$server->getConfig(), \OC::$server->getL10N('encryption')); $keyStorage = \OC::$server->getEncryptionKeyStorage(); $util = new \OCA\Encryption\Util( new \OC\Files\View(), $crypt, \OC::$server->getLogger(), \OC::$server->getUserSession(), \OC::$server->getConfig(), \OC::$server->getUserManager()); $keyManager = new \OCA\Encryption\KeyManager( $keyStorage, $crypt, \OC::$server->getConfig(), \OC::$server->getUserSession(), new \OCA\Encryption\Session(\OC::$server->getSession()), \OC::$server->getLogger(), $util, \OC::$server->getLockingProvider() ); $recovery = new \OCA\Encryption\Recovery( \OC::$server->getUserSession(), $crypt, $keyManager, \OC::$server->getConfig(), \OC::$server->getEncryptionFilesHelper(), new \OC\Files\View()); $recoveryAdminEnabled = $recovery->isRecoveryKeyEnabled(); $validRecoveryPassword = false; $recoveryEnabledForUser = false; if ($recoveryAdminEnabled) { $validRecoveryPassword = $keyManager->checkRecoveryPassword($recoveryPassword); $recoveryEnabledForUser = $recovery->isRecoveryEnabledForUser($username); } if ($recoveryEnabledForUser && $recoveryPassword === '') { return new JSONResponse([ 'status' => 'error', 'data' => [ 'message' => $this->l->t('Please provide an admin recovery password; otherwise, all user data will be lost.'), ] ]); } elseif ($recoveryEnabledForUser && ! $validRecoveryPassword) { return new JSONResponse([ 'status' => 'error', 'data' => [ 'message' => $this->l->t('Wrong admin recovery password. Please check the password and try again.'), ] ]); } else { // now we know that everything is fine regarding the recovery password, let's try to change the password try { $result = $targetUser->setPassword($password, $recoveryPassword); // password policy app throws exception } catch (HintException $e) { return new JSONResponse([ 'status' => 'error', 'data' => [ 'message' => $e->getHint(), ], ]); } if (!$result && $recoveryEnabledForUser) { return new JSONResponse([ 'status' => 'error', 'data' => [ 'message' => $this->l->t('Backend does not support password change, but the user\'s encryption key was updated.'), ] ]); } elseif (!$result && !$recoveryEnabledForUser) { return new JSONResponse([ 'status' => 'error', 'data' => [ 'message' => $this->l->t('Unable to change password'), ] ]); } } } else { try { if ($targetUser->setPassword($password) === false) { return new JSONResponse([ 'status' => 'error', 'data' => [ 'message' => $this->l->t('Unable to change password'), ], ]); } // password policy app throws exception } catch (HintException $e) { return new JSONResponse([ 'status' => 'error', 'data' => [ 'message' => $e->getHint(), ], ]); } } return new JSONResponse([ 'status' => 'success', 'data' => [ 'username' => $username, ], ]); } }