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.

286 lines
7.0 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
  1. <?php
  2. /**
  3. * @author Clark Tomlinson <clark@owncloud.com>
  4. * @since 2/19/15, 10:02 AM
  5. * @copyright Copyright (c) 2015, ownCloud, Inc.
  6. * @license AGPL-3.0
  7. *
  8. * This code is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License, version 3,
  10. * as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License, version 3,
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>
  19. *
  20. */
  21. namespace OCA\Encryption\Hooks;
  22. use OCP\Util as OCUtil;
  23. use OCA\Encryption\Hooks\Contracts\IHook;
  24. use OCA\Encryption\KeyManager;
  25. use OCA\Encryption\Crypto\Crypt;
  26. use OCA\Encryption\Users\Setup;
  27. use OCP\App;
  28. use OCP\ILogger;
  29. use OCP\IUserSession;
  30. use OCA\Encryption\Util;
  31. use OCA\Encryption\Session;
  32. use OCA\Encryption\Recovery;
  33. class UserHooks implements IHook {
  34. /**
  35. * @var KeyManager
  36. */
  37. private $keyManager;
  38. /**
  39. * @var ILogger
  40. */
  41. private $logger;
  42. /**
  43. * @var Setup
  44. */
  45. private $userSetup;
  46. /**
  47. * @var IUserSession
  48. */
  49. private $user;
  50. /**
  51. * @var Util
  52. */
  53. private $util;
  54. /**
  55. * @var Session
  56. */
  57. private $session;
  58. /**
  59. * @var Recovery
  60. */
  61. private $recovery;
  62. /**
  63. * @var Crypt
  64. */
  65. private $crypt;
  66. /**
  67. * UserHooks constructor.
  68. *
  69. * @param KeyManager $keyManager
  70. * @param ILogger $logger
  71. * @param Setup $userSetup
  72. * @param IUserSession $user
  73. * @param Util $util
  74. * @param Session $session
  75. * @param Crypt $crypt
  76. * @param Recovery $recovery
  77. */
  78. public function __construct(KeyManager $keyManager,
  79. ILogger $logger,
  80. Setup $userSetup,
  81. IUserSession $user,
  82. Util $util,
  83. Session $session,
  84. Crypt $crypt,
  85. Recovery $recovery) {
  86. $this->keyManager = $keyManager;
  87. $this->logger = $logger;
  88. $this->userSetup = $userSetup;
  89. $this->user = $user;
  90. $this->util = $util;
  91. $this->session = $session;
  92. $this->recovery = $recovery;
  93. $this->crypt = $crypt;
  94. }
  95. /**
  96. * Connects Hooks
  97. *
  98. * @return null
  99. */
  100. public function addHooks() {
  101. OCUtil::connectHook('OC_User', 'post_login', $this, 'login');
  102. OCUtil::connectHook('OC_User', 'logout', $this, 'logout');
  103. OCUtil::connectHook('OC_User',
  104. 'post_setPassword',
  105. $this,
  106. 'setPassphrase');
  107. OCUtil::connectHook('OC_User',
  108. 'pre_setPassword',
  109. $this,
  110. 'preSetPassphrase');
  111. OCUtil::connectHook('OC_User',
  112. 'post_createUser',
  113. $this,
  114. 'postCreateUser');
  115. OCUtil::connectHook('OC_User',
  116. 'post_deleteUser',
  117. $this,
  118. 'postDeleteUser');
  119. }
  120. /**
  121. * Startup encryption backend upon user login
  122. *
  123. * @note This method should never be called for users using client side encryption
  124. * @param array $params
  125. * @return bool
  126. */
  127. public function login($params) {
  128. if (!App::isEnabled('encryption')) {
  129. return true;
  130. }
  131. // ensure filesystem is loaded
  132. // Todo: update?
  133. if (!\OC\Files\Filesystem::$loaded) {
  134. \OC_Util::setupFS($params['uid']);
  135. }
  136. // setup user, if user not ready force relogin
  137. if (!$this->userSetup->setupUser($params['uid'], $params['password'])) {
  138. return false;
  139. }
  140. $this->keyManager->init($params['uid'], $params['password']);
  141. }
  142. /**
  143. * remove keys from session during logout
  144. */
  145. public function logout() {
  146. $this->session->clear();
  147. }
  148. /**
  149. * setup encryption backend upon user created
  150. *
  151. * @note This method should never be called for users using client side encryption
  152. * @param array $params
  153. */
  154. public function postCreateUser($params) {
  155. if (App::isEnabled('encryption')) {
  156. $this->userSetup->setupUser($params['uid'], $params['password']);
  157. }
  158. }
  159. /**
  160. * cleanup encryption backend upon user deleted
  161. *
  162. * @param array $params : uid, password
  163. * @note This method should never be called for users using client side encryption
  164. */
  165. public function postDeleteUser($params) {
  166. if (App::isEnabled('encryption')) {
  167. $this->keyManager->deletePublicKey($params['uid']);
  168. }
  169. }
  170. /**
  171. * If the password can't be changed within ownCloud, than update the key password in advance.
  172. *
  173. * @param array $params : uid, password
  174. * @return bool
  175. */
  176. public function preSetPassphrase($params) {
  177. if (App::isEnabled('encryption')) {
  178. if (!$this->user->getUser()->canChangePassword()) {
  179. $this->setPassphrase($params);
  180. }
  181. }
  182. }
  183. /**
  184. * Change a user's encryption passphrase
  185. *
  186. * @param array $params keys: uid, password
  187. * @return bool
  188. */
  189. public function setPassphrase($params) {
  190. // Get existing decrypted private key
  191. $privateKey = $this->session->getPrivateKey();
  192. if ($params['uid'] === $this->user->getUser()->getUID() && $privateKey) {
  193. // Encrypt private key with new user pwd as passphrase
  194. $encryptedPrivateKey = $this->crypt->symmetricEncryptFileContent($privateKey,
  195. $params['password']);
  196. // Save private key
  197. if ($encryptedPrivateKey) {
  198. $this->keyManager->setPrivateKey($this->user->getUser()->getUID(),
  199. $encryptedPrivateKey);
  200. } else {
  201. $this->logger->error('Encryption could not update users encryption password');
  202. }
  203. // NOTE: Session does not need to be updated as the
  204. // private key has not changed, only the passphrase
  205. // used to decrypt it has changed
  206. } else { // admin changed the password for a different user, create new keys and reencrypt file keys
  207. $user = $params['uid'];
  208. $recoveryPassword = isset($params['recoveryPassword']) ? $params['recoveryPassword'] : null;
  209. // we generate new keys if...
  210. // ...we have a recovery password and the user enabled the recovery key
  211. // ...encryption was activated for the first time (no keys exists)
  212. // ...the user doesn't have any files
  213. if (
  214. ($this->recovery->isRecoveryEnabledForUser($user) && $recoveryPassword)
  215. || !$this->keyManager->userHasKeys($user)
  216. || !$this->util->userHasFiles($user)
  217. ) {
  218. // backup old keys
  219. //$this->backupAllKeys('recovery');
  220. $newUserPassword = $params['password'];
  221. $keyPair = $this->crypt->createKeyPair();
  222. // Save public key
  223. $this->keyManager->setPublicKey($user, $keyPair['publicKey']);
  224. // Encrypt private key with new password
  225. $encryptedKey = $this->crypt->symmetricEncryptFileContent($keyPair['privateKey'],
  226. $newUserPassword);
  227. if ($encryptedKey) {
  228. $this->keyManager->setPrivateKey($user, $encryptedKey);
  229. if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files
  230. $this->recovery->recoverUsersFiles($recoveryPassword, $user);
  231. }
  232. } else {
  233. $this->logger->error('Encryption Could not update users encryption password');
  234. }
  235. }
  236. }
  237. }
  238. /**
  239. * after password reset we create a new key pair for the user
  240. *
  241. * @param array $params
  242. */
  243. public function postPasswordReset($params) {
  244. $password = $params['password'];
  245. $this->keyManager->replaceUserKeys($params['uid']);
  246. $this->userSetup->setupServerSide($params['uid'], $password);
  247. }
  248. }