You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ChangePasswordController.php 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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. /** @var IUser $user */
  80. $user = $this->userManager->checkPassword($this->userId, $oldpassword);
  81. if ($user === false) {
  82. $response = new JSONResponse([
  83. 'status' => 'error',
  84. 'data' => [
  85. 'message' => $this->l->t('Wrong password'),
  86. ],
  87. ]);
  88. $response->throttle();
  89. return $response;
  90. }
  91. try {
  92. if ($newpassword === null || $user->setPassword($newpassword) === false) {
  93. return new JSONResponse([
  94. 'status' => 'error'
  95. ]);
  96. }
  97. // password policy app throws exception
  98. } catch(HintException $e) {
  99. return new JSONResponse([
  100. 'status' => 'error',
  101. 'data' => [
  102. 'message' => $e->getHint(),
  103. ],
  104. ]);
  105. }
  106. $this->userSession->updateSessionTokenPassword($newpassword);
  107. return new JSONResponse([
  108. 'status' => 'success',
  109. 'data' => [
  110. 'message' => $this->l->t('Saved'),
  111. ],
  112. ]);
  113. }
  114. /**
  115. * @NoAdminRequired
  116. * @PasswordConfirmationRequired
  117. */
  118. public function changeUserPassword(string $username = null, string $password = null, string $recoveryPassword = null): JSONResponse {
  119. if ($username === null) {
  120. return new JSONResponse([
  121. 'status' => 'error',
  122. 'data' => [
  123. 'message' => $this->l->t('No user supplied'),
  124. ],
  125. ]);
  126. }
  127. if ($password === null) {
  128. return new JSONResponse([
  129. 'status' => 'error',
  130. 'data' => [
  131. 'message' => $this->l->t('Unable to change password'),
  132. ],
  133. ]);
  134. }
  135. $currentUser = $this->userSession->getUser();
  136. $targetUser = $this->userManager->get($username);
  137. if ($currentUser === null || $targetUser === null ||
  138. !($this->groupManager->isAdmin($this->userId) ||
  139. $this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $targetUser))
  140. ) {
  141. return new JSONResponse([
  142. 'status' => 'error',
  143. 'data' => [
  144. 'message' => $this->l->t('Authentication error'),
  145. ],
  146. ]);
  147. }
  148. if ($this->appManager->isEnabledForUser('encryption')) {
  149. //handle the recovery case
  150. $crypt = new \OCA\Encryption\Crypto\Crypt(
  151. \OC::$server->getLogger(),
  152. \OC::$server->getUserSession(),
  153. \OC::$server->getConfig(),
  154. \OC::$server->getL10N('encryption'));
  155. $keyStorage = \OC::$server->getEncryptionKeyStorage();
  156. $util = new \OCA\Encryption\Util(
  157. new \OC\Files\View(),
  158. $crypt,
  159. \OC::$server->getLogger(),
  160. \OC::$server->getUserSession(),
  161. \OC::$server->getConfig(),
  162. \OC::$server->getUserManager());
  163. $keyManager = new \OCA\Encryption\KeyManager(
  164. $keyStorage,
  165. $crypt,
  166. \OC::$server->getConfig(),
  167. \OC::$server->getUserSession(),
  168. new \OCA\Encryption\Session(\OC::$server->getSession()),
  169. \OC::$server->getLogger(),
  170. $util);
  171. $recovery = new \OCA\Encryption\Recovery(
  172. \OC::$server->getUserSession(),
  173. $crypt,
  174. $keyManager,
  175. \OC::$server->getConfig(),
  176. \OC::$server->getEncryptionFilesHelper(),
  177. new \OC\Files\View());
  178. $recoveryAdminEnabled = $recovery->isRecoveryKeyEnabled();
  179. $validRecoveryPassword = false;
  180. $recoveryEnabledForUser = false;
  181. if ($recoveryAdminEnabled) {
  182. $validRecoveryPassword = $keyManager->checkRecoveryPassword($recoveryPassword);
  183. $recoveryEnabledForUser = $recovery->isRecoveryEnabledForUser($username);
  184. }
  185. if ($recoveryEnabledForUser && $recoveryPassword === '') {
  186. return new JSONResponse([
  187. 'status' => 'error',
  188. 'data' => [
  189. 'message' => $this->l->t('Please provide an admin recovery password; otherwise, all user data will be lost.'),
  190. ]
  191. ]);
  192. } elseif ($recoveryEnabledForUser && ! $validRecoveryPassword) {
  193. return new JSONResponse([
  194. 'status' => 'error',
  195. 'data' => [
  196. 'message' => $this->l->t('Wrong admin recovery password. Please check the password and try again.'),
  197. ]
  198. ]);
  199. } else { // now we know that everything is fine regarding the recovery password, let's try to change the password
  200. try {
  201. $result = $targetUser->setPassword($password, $recoveryPassword);
  202. // password policy app throws exception
  203. } catch(HintException $e) {
  204. return new JSONResponse([
  205. 'status' => 'error',
  206. 'data' => [
  207. 'message' => $e->getHint(),
  208. ],
  209. ]);
  210. }
  211. if (!$result && $recoveryEnabledForUser) {
  212. return new JSONResponse([
  213. 'status' => 'error',
  214. 'data' => [
  215. 'message' => $this->l->t('Backend doesn\'t support password change, but the user\'s encryption key was updated.'),
  216. ]
  217. ]);
  218. } elseif (!$result && !$recoveryEnabledForUser) {
  219. return new JSONResponse([
  220. 'status' => 'error',
  221. 'data' => [
  222. 'message' => $this->l->t('Unable to change password'),
  223. ]
  224. ]);
  225. }
  226. }
  227. } else {
  228. try {
  229. if ($targetUser->setPassword($password) === false) {
  230. return new JSONResponse([
  231. 'status' => 'error',
  232. 'data' => [
  233. 'message' => $this->l->t('Unable to change password'),
  234. ],
  235. ]);
  236. }
  237. // password policy app throws exception
  238. } catch(HintException $e) {
  239. return new JSONResponse([
  240. 'status' => 'error',
  241. 'data' => [
  242. 'message' => $e->getHint(),
  243. ],
  244. ]);
  245. }
  246. }
  247. return new JSONResponse([
  248. 'status' => 'success',
  249. 'data' => [
  250. 'username' => $username,
  251. ],
  252. ]);
  253. }
  254. }