ChangePasswordController.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <?php
  2. /**
  3. *
  4. *
  5. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  6. * @author Daniel Calviño Sánchez <danxuliu@gmail.com>
  7. * @author Joas Schilling <coding@schilljs.com>
  8. * @author Lukas Reschke <lukas@statuscode.ch>
  9. * @author Matthew Setter <matthew@matthewsetter.com>
  10. * @author Morris Jobke <hey@morrisjobke.de>
  11. * @author Roeland Jago Douma <roeland@famdouma.nl>
  12. *
  13. * @license GNU AGPL version 3 or any later version
  14. *
  15. * This program is free software: you can redistribute it and/or modify
  16. * it under the terms of the GNU Affero General Public License as
  17. * published by the Free Software Foundation, either version 3 of the
  18. * License, or (at your option) any later version.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU Affero General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU Affero General Public License
  26. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  27. *
  28. */
  29. // FIXME: disabled for now to be able to inject IGroupManager and also use
  30. // getSubAdmin()
  31. //declare(strict_types=1);
  32. namespace OCA\Settings\Controller;
  33. use OC\HintException;
  34. use OC\User\Session;
  35. use OCP\App\IAppManager;
  36. use OCP\AppFramework\Controller;
  37. use OCP\AppFramework\Http\JSONResponse;
  38. use OCP\IGroupManager;
  39. use OCP\IL10N;
  40. use OCP\IRequest;
  41. use OCP\IUser;
  42. use OCP\IUserManager;
  43. use OCP\IUserSession;
  44. class ChangePasswordController extends Controller {
  45. /** @var string */
  46. private $userId;
  47. /** @var IUserManager */
  48. private $userManager;
  49. /** @var IL10N */
  50. private $l;
  51. /** @var IGroupManager */
  52. private $groupManager;
  53. /** @var Session */
  54. private $userSession;
  55. /** @var IAppManager */
  56. private $appManager;
  57. public function __construct(string $appName,
  58. IRequest $request,
  59. string $userId,
  60. IUserManager $userManager,
  61. IUserSession $userSession,
  62. IGroupManager $groupManager,
  63. IAppManager $appManager,
  64. IL10N $l) {
  65. parent::__construct($appName, $request);
  66. $this->userId = $userId;
  67. $this->userManager = $userManager;
  68. $this->userSession = $userSession;
  69. $this->groupManager = $groupManager;
  70. $this->appManager = $appManager;
  71. $this->l = $l;
  72. }
  73. /**
  74. * @NoAdminRequired
  75. * @NoSubAdminRequired
  76. * @BruteForceProtection(action=changePersonalPassword)
  77. */
  78. public function changePersonalPassword(string $oldpassword = '', string $newpassword = null): JSONResponse {
  79. $loginName = $this->userSession->getLoginName();
  80. /** @var IUser $user */
  81. $user = $this->userManager->checkPassword($loginName, $oldpassword);
  82. if ($user === false) {
  83. $response = new JSONResponse([
  84. 'status' => 'error',
  85. 'data' => [
  86. 'message' => $this->l->t('Wrong password'),
  87. ],
  88. ]);
  89. $response->throttle();
  90. return $response;
  91. }
  92. try {
  93. if ($newpassword === null || $user->setPassword($newpassword) === false) {
  94. return new JSONResponse([
  95. 'status' => 'error'
  96. ]);
  97. }
  98. // password policy app throws exception
  99. } catch (HintException $e) {
  100. return new JSONResponse([
  101. 'status' => 'error',
  102. 'data' => [
  103. 'message' => $e->getHint(),
  104. ],
  105. ]);
  106. }
  107. $this->userSession->updateSessionTokenPassword($newpassword);
  108. return new JSONResponse([
  109. 'status' => 'success',
  110. 'data' => [
  111. 'message' => $this->l->t('Saved'),
  112. ],
  113. ]);
  114. }
  115. /**
  116. * @NoAdminRequired
  117. * @PasswordConfirmationRequired
  118. */
  119. public function changeUserPassword(string $username = null, string $password = null, string $recoveryPassword = null): JSONResponse {
  120. if ($username === null) {
  121. return new JSONResponse([
  122. 'status' => 'error',
  123. 'data' => [
  124. 'message' => $this->l->t('No user supplied'),
  125. ],
  126. ]);
  127. }
  128. if ($password === null) {
  129. return new JSONResponse([
  130. 'status' => 'error',
  131. 'data' => [
  132. 'message' => $this->l->t('Unable to change password'),
  133. ],
  134. ]);
  135. }
  136. $currentUser = $this->userSession->getUser();
  137. $targetUser = $this->userManager->get($username);
  138. if ($currentUser === null || $targetUser === null ||
  139. !($this->groupManager->isAdmin($this->userId) ||
  140. $this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $targetUser))
  141. ) {
  142. return new JSONResponse([
  143. 'status' => 'error',
  144. 'data' => [
  145. 'message' => $this->l->t('Authentication error'),
  146. ],
  147. ]);
  148. }
  149. if ($this->appManager->isEnabledForUser('encryption')) {
  150. //handle the recovery case
  151. $crypt = new \OCA\Encryption\Crypto\Crypt(
  152. \OC::$server->getLogger(),
  153. \OC::$server->getUserSession(),
  154. \OC::$server->getConfig(),
  155. \OC::$server->getL10N('encryption'));
  156. $keyStorage = \OC::$server->getEncryptionKeyStorage();
  157. $util = new \OCA\Encryption\Util(
  158. new \OC\Files\View(),
  159. $crypt,
  160. \OC::$server->getLogger(),
  161. \OC::$server->getUserSession(),
  162. \OC::$server->getConfig(),
  163. \OC::$server->getUserManager());
  164. $keyManager = new \OCA\Encryption\KeyManager(
  165. $keyStorage,
  166. $crypt,
  167. \OC::$server->getConfig(),
  168. \OC::$server->getUserSession(),
  169. new \OCA\Encryption\Session(\OC::$server->getSession()),
  170. \OC::$server->getLogger(),
  171. $util);
  172. $recovery = new \OCA\Encryption\Recovery(
  173. \OC::$server->getUserSession(),
  174. $crypt,
  175. $keyManager,
  176. \OC::$server->getConfig(),
  177. \OC::$server->getEncryptionFilesHelper(),
  178. new \OC\Files\View());
  179. $recoveryAdminEnabled = $recovery->isRecoveryKeyEnabled();
  180. $validRecoveryPassword = false;
  181. $recoveryEnabledForUser = false;
  182. if ($recoveryAdminEnabled) {
  183. $validRecoveryPassword = $keyManager->checkRecoveryPassword($recoveryPassword);
  184. $recoveryEnabledForUser = $recovery->isRecoveryEnabledForUser($username);
  185. }
  186. if ($recoveryEnabledForUser && $recoveryPassword === '') {
  187. return new JSONResponse([
  188. 'status' => 'error',
  189. 'data' => [
  190. 'message' => $this->l->t('Please provide an admin recovery password; otherwise, all user data will be lost.'),
  191. ]
  192. ]);
  193. } elseif ($recoveryEnabledForUser && ! $validRecoveryPassword) {
  194. return new JSONResponse([
  195. 'status' => 'error',
  196. 'data' => [
  197. 'message' => $this->l->t('Wrong admin recovery password. Please check the password and try again.'),
  198. ]
  199. ]);
  200. } else { // now we know that everything is fine regarding the recovery password, let's try to change the password
  201. try {
  202. $result = $targetUser->setPassword($password, $recoveryPassword);
  203. // password policy app throws exception
  204. } catch (HintException $e) {
  205. return new JSONResponse([
  206. 'status' => 'error',
  207. 'data' => [
  208. 'message' => $e->getHint(),
  209. ],
  210. ]);
  211. }
  212. if (!$result && $recoveryEnabledForUser) {
  213. return new JSONResponse([
  214. 'status' => 'error',
  215. 'data' => [
  216. 'message' => $this->l->t('Backend doesn\'t support password change, but the user\'s encryption key was updated.'),
  217. ]
  218. ]);
  219. } elseif (!$result && !$recoveryEnabledForUser) {
  220. return new JSONResponse([
  221. 'status' => 'error',
  222. 'data' => [
  223. 'message' => $this->l->t('Unable to change password'),
  224. ]
  225. ]);
  226. }
  227. }
  228. } else {
  229. try {
  230. if ($targetUser->setPassword($password) === false) {
  231. return new JSONResponse([
  232. 'status' => 'error',
  233. 'data' => [
  234. 'message' => $this->l->t('Unable to change password'),
  235. ],
  236. ]);
  237. }
  238. // password policy app throws exception
  239. } catch (HintException $e) {
  240. return new JSONResponse([
  241. 'status' => 'error',
  242. 'data' => [
  243. 'message' => $e->getHint(),
  244. ],
  245. ]);
  246. }
  247. }
  248. return new JSONResponse([
  249. 'status' => 'success',
  250. 'data' => [
  251. 'username' => $username,
  252. ],
  253. ]);
  254. }
  255. }