diff options
Diffstat (limited to 'apps/encryption/hooks/userhooks.php')
-rw-r--r-- | apps/encryption/hooks/userhooks.php | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/apps/encryption/hooks/userhooks.php b/apps/encryption/hooks/userhooks.php new file mode 100644 index 00000000000..1ec0950d941 --- /dev/null +++ b/apps/encryption/hooks/userhooks.php @@ -0,0 +1,286 @@ +<?php +/** + * @author Clark Tomlinson <clark@owncloud.com> + * @since 2/19/15, 10:02 AM + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCA\Encryption\Hooks; + + +use OCP\Util as OCUtil; +use OCA\Encryption\Hooks\Contracts\IHook; +use OCA\Encryption\KeyManager; +use OCA\Encryption\Crypto\Crypt; +use OCA\Encryption\Users\Setup; +use OCP\App; +use OCP\ILogger; +use OCP\IUserSession; +use OCA\Encryption\Util; +use OCA\Encryption\Session; +use OCA\Encryption\Recovery; + +class UserHooks implements IHook { + /** + * @var KeyManager + */ + private $keyManager; + /** + * @var ILogger + */ + private $logger; + /** + * @var Setup + */ + private $userSetup; + /** + * @var IUserSession + */ + private $user; + /** + * @var Util + */ + private $util; + /** + * @var Session + */ + private $session; + /** + * @var Recovery + */ + private $recovery; + /** + * @var Crypt + */ + private $crypt; + + /** + * UserHooks constructor. + * + * @param KeyManager $keyManager + * @param ILogger $logger + * @param Setup $userSetup + * @param IUserSession $user + * @param Util $util + * @param Session $session + * @param Crypt $crypt + * @param Recovery $recovery + */ + public function __construct(KeyManager $keyManager, + ILogger $logger, + Setup $userSetup, + IUserSession $user, + Util $util, + Session $session, + Crypt $crypt, + Recovery $recovery) { + + $this->keyManager = $keyManager; + $this->logger = $logger; + $this->userSetup = $userSetup; + $this->user = $user; + $this->util = $util; + $this->session = $session; + $this->recovery = $recovery; + $this->crypt = $crypt; + } + + /** + * Connects Hooks + * + * @return null + */ + public function addHooks() { + OCUtil::connectHook('OC_User', 'post_login', $this, 'login'); + OCUtil::connectHook('OC_User', 'logout', $this, 'logout'); + OCUtil::connectHook('OC_User', + 'post_setPassword', + $this, + 'setPassphrase'); + OCUtil::connectHook('OC_User', + 'pre_setPassword', + $this, + 'preSetPassphrase'); + OCUtil::connectHook('OC_User', + 'post_createUser', + $this, + 'postCreateUser'); + OCUtil::connectHook('OC_User', + 'post_deleteUser', + $this, + 'postDeleteUser'); + } + + + /** + * Startup encryption backend upon user login + * + * @note This method should never be called for users using client side encryption + * @param array $params + * @return bool + */ + public function login($params) { + + if (!App::isEnabled('encryption')) { + return true; + } + + // ensure filesystem is loaded + // Todo: update? + if (!\OC\Files\Filesystem::$loaded) { + \OC_Util::setupFS($params['uid']); + } + + // setup user, if user not ready force relogin + if (!$this->userSetup->setupUser($params['uid'], $params['password'])) { + return false; + } + + $this->keyManager->init($params['uid'], $params['password']); + } + + /** + * remove keys from session during logout + */ + public function logout() { + $this->session->clear(); + } + + /** + * setup encryption backend upon user created + * + * @note This method should never be called for users using client side encryption + * @param array $params + */ + public function postCreateUser($params) { + + if (App::isEnabled('encryption')) { + $this->userSetup->setupUser($params['uid'], $params['password']); + } + } + + /** + * cleanup encryption backend upon user deleted + * + * @param array $params : uid, password + * @note This method should never be called for users using client side encryption + */ + public function postDeleteUser($params) { + + if (App::isEnabled('encryption')) { + $this->keyManager->deletePublicKey($params['uid']); + } + } + + /** + * If the password can't be changed within ownCloud, than update the key password in advance. + * + * @param array $params : uid, password + * @return bool + */ + public function preSetPassphrase($params) { + if (App::isEnabled('encryption')) { + + if (!$this->user->getUser()->canChangePassword()) { + $this->setPassphrase($params); + } + } + } + + /** + * Change a user's encryption passphrase + * + * @param array $params keys: uid, password + * @return bool + */ + public function setPassphrase($params) { + + // Get existing decrypted private key + $privateKey = $this->session->getPrivateKey(); + + if ($params['uid'] === $this->user->getUser()->getUID() && $privateKey) { + + // Encrypt private key with new user pwd as passphrase + $encryptedPrivateKey = $this->crypt->symmetricEncryptFileContent($privateKey, + $params['password']); + + // Save private key + if ($encryptedPrivateKey) { + $this->keyManager->setPrivateKey($this->user->getUser()->getUID(), + $encryptedPrivateKey); + } else { + $this->logger->error('Encryption could not update users encryption password'); + } + + // NOTE: Session does not need to be updated as the + // private key has not changed, only the passphrase + // used to decrypt it has changed + } else { // admin changed the password for a different user, create new keys and reencrypt file keys + $user = $params['uid']; + $recoveryPassword = isset($params['recoveryPassword']) ? $params['recoveryPassword'] : null; + + // we generate new keys if... + // ...we have a recovery password and the user enabled the recovery key + // ...encryption was activated for the first time (no keys exists) + // ...the user doesn't have any files + if ( + ($this->recovery->isRecoveryEnabledForUser($user) && $recoveryPassword) + || !$this->keyManager->userHasKeys($user) + || !$this->util->userHasFiles($user) + ) { + + // backup old keys + //$this->backupAllKeys('recovery'); + + $newUserPassword = $params['password']; + + $keyPair = $this->crypt->createKeyPair(); + + // Save public key + $this->keyManager->setPublicKey($user, $keyPair['publicKey']); + + // Encrypt private key with new password + $encryptedKey = $this->crypt->symmetricEncryptFileContent($keyPair['privateKey'], + $newUserPassword); + + if ($encryptedKey) { + $this->keyManager->setPrivateKey($user, $encryptedKey); + + if ($recoveryPassword) { // if recovery key is set we can re-encrypt the key files + $this->recovery->recoverUsersFiles($recoveryPassword, $user); + } + } else { + $this->logger->error('Encryption Could not update users encryption password'); + } + } + } + } + + + + /** + * after password reset we create a new key pair for the user + * + * @param array $params + */ + public function postPasswordReset($params) { + $password = $params['password']; + + $this->keyManager->replaceUserKeys($params['uid']); + $this->userSetup->setupServerSide($params['uid'], $password); + } +} |