Merge pull request #22777 from owncloud/encrypt_all_master_key

improved encrypt-all script
This commit is contained in:
Thomas Müller 2016-04-27 09:48:46 +02:00
commit 44709276c0
4 changed files with 116 additions and 29 deletions

View File

@ -242,6 +242,7 @@ class Application extends \OCP\AppFramework\App {
$c->getServer()->getUserManager(), $c->getServer()->getUserManager(),
new View(), new View(),
$c->query('KeyManager'), $c->query('KeyManager'),
$c->query('Util'),
$server->getConfig(), $server->getConfig(),
$server->getMailer(), $server->getMailer(),
$server->getL10N('encryption'), $server->getL10N('encryption'),

View File

@ -28,12 +28,12 @@ use OC\Encryption\Exceptions\DecryptionFailedException;
use OC\Files\View; use OC\Files\View;
use OCA\Encryption\KeyManager; use OCA\Encryption\KeyManager;
use OCA\Encryption\Users\Setup; use OCA\Encryption\Users\Setup;
use OCA\Encryption\Util;
use OCP\IConfig; use OCP\IConfig;
use OCP\IL10N; use OCP\IL10N;
use OCP\IUserManager; use OCP\IUserManager;
use OCP\Mail\IMailer; use OCP\Mail\IMailer;
use OCP\Security\ISecureRandom; use OCP\Security\ISecureRandom;
use OCP\Util;
use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Helper\Table;
@ -55,6 +55,9 @@ class EncryptAll {
/** @var KeyManager */ /** @var KeyManager */
protected $keyManager; protected $keyManager;
/** @var Util */
protected $util;
/** @var array */ /** @var array */
protected $userPasswords; protected $userPasswords;
@ -84,6 +87,7 @@ class EncryptAll {
* @param IUserManager $userManager * @param IUserManager $userManager
* @param View $rootView * @param View $rootView
* @param KeyManager $keyManager * @param KeyManager $keyManager
* @param Util $util
* @param IConfig $config * @param IConfig $config
* @param IMailer $mailer * @param IMailer $mailer
* @param IL10N $l * @param IL10N $l
@ -95,6 +99,7 @@ class EncryptAll {
IUserManager $userManager, IUserManager $userManager,
View $rootView, View $rootView,
KeyManager $keyManager, KeyManager $keyManager,
Util $util,
IConfig $config, IConfig $config,
IMailer $mailer, IMailer $mailer,
IL10N $l, IL10N $l,
@ -105,6 +110,7 @@ class EncryptAll {
$this->userManager = $userManager; $this->userManager = $userManager;
$this->rootView = $rootView; $this->rootView = $rootView;
$this->keyManager = $keyManager; $this->keyManager = $keyManager;
$this->util = $util;
$this->config = $config; $this->config = $config;
$this->mailer = $mailer; $this->mailer = $mailer;
$this->l = $l; $this->l = $l;
@ -129,16 +135,21 @@ class EncryptAll {
$this->output->writeln("\n"); $this->output->writeln("\n");
$this->output->writeln($headline); $this->output->writeln($headline);
$this->output->writeln(str_pad('', strlen($headline), '=')); $this->output->writeln(str_pad('', strlen($headline), '='));
//create private/public keys for each user and store the private key password
$this->output->writeln("\n"); $this->output->writeln("\n");
$this->output->writeln('Create key-pair for every user');
$this->output->writeln('------------------------------'); if ($this->util->isMasterKeyEnabled()) {
$this->output->writeln(''); $this->output->writeln('Use master key to encrypt all files.');
$this->output->writeln('This module will encrypt all files in the users files folder initially.'); $this->keyManager->validateMasterKey();
$this->output->writeln('Already existing versions and files in the trash bin will not be encrypted.'); } else {
$this->output->writeln(''); //create private/public keys for each user and store the private key password
$this->createKeyPairs(); $this->output->writeln('Create key-pair for every user');
$this->output->writeln('------------------------------');
$this->output->writeln('');
$this->output->writeln('This module will encrypt all files in the users files folder initially.');
$this->output->writeln('Already existing versions and files in the trash bin will not be encrypted.');
$this->output->writeln('');
$this->createKeyPairs();
}
//setup users file system and encrypt all files one by one (take should encrypt setting of storage into account) //setup users file system and encrypt all files one by one (take should encrypt setting of storage into account)
$this->output->writeln("\n"); $this->output->writeln("\n");
@ -146,12 +157,14 @@ class EncryptAll {
$this->output->writeln('----------------------------'); $this->output->writeln('----------------------------');
$this->output->writeln(''); $this->output->writeln('');
$this->encryptAllUsersFiles(); $this->encryptAllUsersFiles();
//send-out or display password list and write it to a file if ($this->util->isMasterKeyEnabled() === false) {
$this->output->writeln("\n"); //send-out or display password list and write it to a file
$this->output->writeln('Generated encryption key passwords'); $this->output->writeln("\n");
$this->output->writeln('----------------------------------'); $this->output->writeln('Generated encryption key passwords');
$this->output->writeln(''); $this->output->writeln('----------------------------------');
$this->outputPasswords(); $this->output->writeln('');
$this->outputPasswords();
}
$this->output->writeln("\n"); $this->output->writeln("\n");
} }
@ -200,16 +213,42 @@ class EncryptAll {
$progress->start(); $progress->start();
$numberOfUsers = count($this->userPasswords); $numberOfUsers = count($this->userPasswords);
$userNo = 1; $userNo = 1;
foreach ($this->userPasswords as $uid => $password) { if ($this->util->isMasterKeyEnabled()) {
$userCount = "$uid ($userNo of $numberOfUsers)"; $this->encryptAllUserFilesWithMasterKey($progress);
$this->encryptUsersFiles($uid, $progress, $userCount); } else {
$userNo++; foreach ($this->userPasswords as $uid => $password) {
$userCount = "$uid ($userNo of $numberOfUsers)";
$this->encryptUsersFiles($uid, $progress, $userCount);
$userNo++;
}
} }
$progress->setMessage("all files encrypted"); $progress->setMessage("all files encrypted");
$progress->finish(); $progress->finish();
} }
/**
* encrypt all user files with the master key
*
* @param ProgressBar $progress
*/
protected function encryptAllUserFilesWithMasterKey(ProgressBar $progress) {
$userNo = 1;
foreach($this->userManager->getBackends() as $backend) {
$limit = 500;
$offset = 0;
do {
$users = $backend->getUsers('', $limit, $offset);
foreach ($users as $user) {
$userCount = "$user ($userNo)";
$this->encryptUsersFiles($user, $progress, $userCount);
$userNo++;
}
$offset += $limit;
} while(count($users) >= $limit);
}
}
/** /**
* encrypt files from the given user * encrypt files from the given user
* *
@ -384,7 +423,7 @@ class EncryptAll {
$message->setHtmlBody($htmlBody); $message->setHtmlBody($htmlBody);
$message->setPlainBody($textBody); $message->setPlainBody($textBody);
$message->setFrom([ $message->setFrom([
Util::getDefaultEmailAddress('admin-noreply') \OCP\Util::getDefaultEmailAddress('admin-noreply')
]); ]);
$this->mailer->send($message); $this->mailer->send($message);

View File

@ -394,17 +394,20 @@ class KeyManager {
public function getFileKey($path, $uid) { public function getFileKey($path, $uid) {
$encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId, Encryption::ID); $encryptedFileKey = $this->keyStorage->getFileKey($path, $this->fileKeyId, Encryption::ID);
if (empty($encryptedFileKey)) {
return '';
}
if ($this->util->isMasterKeyEnabled()) {
$uid = $this->getMasterKeyId();
}
if (is_null($uid)) { if (is_null($uid)) {
$uid = $this->getPublicShareKeyId(); $uid = $this->getPublicShareKeyId();
$shareKey = $this->getShareKey($path, $uid); $shareKey = $this->getShareKey($path, $uid);
$privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID); $privateKey = $this->keyStorage->getSystemUserKey($this->publicShareKeyId . '.privateKey', Encryption::ID);
$privateKey = $this->crypt->decryptPrivateKey($privateKey); $privateKey = $this->crypt->decryptPrivateKey($privateKey);
} else { } else {
if ($this->util->isMasterKeyEnabled()) {
$uid = $this->getMasterKeyId();
}
$shareKey = $this->getShareKey($path, $uid); $shareKey = $this->getShareKey($path, $uid);
$privateKey = $this->session->getPrivateKey(); $privateKey = $this->session->getPrivateKey();
} }

View File

@ -31,6 +31,9 @@ class EncryptAllTest extends TestCase {
/** @var \PHPUnit_Framework_MockObject_MockObject | \OCA\Encryption\KeyManager */ /** @var \PHPUnit_Framework_MockObject_MockObject | \OCA\Encryption\KeyManager */
protected $keyManager; protected $keyManager;
/** @var \PHPUnit_Framework_MockObject_MockObject | \OCA\Encryption\Util */
protected $util;
/** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IUserManager */ /** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IUserManager */
protected $userManager; protected $userManager;
@ -73,6 +76,8 @@ class EncryptAllTest extends TestCase {
->disableOriginalConstructor()->getMock(); ->disableOriginalConstructor()->getMock();
$this->keyManager = $this->getMockBuilder('OCA\Encryption\KeyManager') $this->keyManager = $this->getMockBuilder('OCA\Encryption\KeyManager')
->disableOriginalConstructor()->getMock(); ->disableOriginalConstructor()->getMock();
$this->util = $this->getMockBuilder('OCA\Encryption\Util')
->disableOriginalConstructor()->getMock();
$this->userManager = $this->getMockBuilder('OCP\IUserManager') $this->userManager = $this->getMockBuilder('OCP\IUserManager')
->disableOriginalConstructor()->getMock(); ->disableOriginalConstructor()->getMock();
$this->view = $this->getMockBuilder('OC\Files\View') $this->view = $this->getMockBuilder('OC\Files\View')
@ -110,6 +115,7 @@ class EncryptAllTest extends TestCase {
$this->userManager, $this->userManager,
$this->view, $this->view,
$this->keyManager, $this->keyManager,
$this->util,
$this->config, $this->config,
$this->mailer, $this->mailer,
$this->l, $this->l,
@ -127,6 +133,7 @@ class EncryptAllTest extends TestCase {
$this->userManager, $this->userManager,
$this->view, $this->view,
$this->keyManager, $this->keyManager,
$this->util,
$this->config, $this->config,
$this->mailer, $this->mailer,
$this->l, $this->l,
@ -137,6 +144,7 @@ class EncryptAllTest extends TestCase {
->setMethods(['createKeyPairs', 'encryptAllUsersFiles', 'outputPasswords']) ->setMethods(['createKeyPairs', 'encryptAllUsersFiles', 'outputPasswords'])
->getMock(); ->getMock();
$this->util->expects($this->any())->method('isMasterKeyEnabled')->willReturn(false);
$encryptAll->expects($this->at(0))->method('createKeyPairs')->with(); $encryptAll->expects($this->at(0))->method('createKeyPairs')->with();
$encryptAll->expects($this->at(1))->method('encryptAllUsersFiles')->with(); $encryptAll->expects($this->at(1))->method('encryptAllUsersFiles')->with();
$encryptAll->expects($this->at(2))->method('outputPasswords')->with(); $encryptAll->expects($this->at(2))->method('outputPasswords')->with();
@ -145,6 +153,36 @@ class EncryptAllTest extends TestCase {
} }
public function testEncryptAllWithMasterKey() {
/** @var EncryptAll | \PHPUnit_Framework_MockObject_MockObject $encryptAll */
$encryptAll = $this->getMockBuilder('OCA\Encryption\Crypto\EncryptAll')
->setConstructorArgs(
[
$this->setupUser,
$this->userManager,
$this->view,
$this->keyManager,
$this->util,
$this->config,
$this->mailer,
$this->l,
$this->questionHelper,
$this->secureRandom
]
)
->setMethods(['createKeyPairs', 'encryptAllUsersFiles', 'outputPasswords'])
->getMock();
$this->util->expects($this->any())->method('isMasterKeyEnabled')->willReturn(true);
$encryptAll->expects($this->never())->method('createKeyPairs');
$this->keyManager->expects($this->once())->method('validateMasterKey');
$encryptAll->expects($this->at(0))->method('encryptAllUsersFiles')->with();
$encryptAll->expects($this->never())->method('outputPasswords');
$encryptAll->encryptAll($this->inputInterface, $this->outputInterface);
}
public function testCreateKeyPairs() { public function testCreateKeyPairs() {
/** @var EncryptAll | \PHPUnit_Framework_MockObject_MockObject $encryptAll */ /** @var EncryptAll | \PHPUnit_Framework_MockObject_MockObject $encryptAll */
$encryptAll = $this->getMockBuilder('OCA\Encryption\Crypto\EncryptAll') $encryptAll = $this->getMockBuilder('OCA\Encryption\Crypto\EncryptAll')
@ -154,6 +192,7 @@ class EncryptAllTest extends TestCase {
$this->userManager, $this->userManager,
$this->view, $this->view,
$this->keyManager, $this->keyManager,
$this->util,
$this->config, $this->config,
$this->mailer, $this->mailer,
$this->l, $this->l,
@ -202,6 +241,7 @@ class EncryptAllTest extends TestCase {
$this->userManager, $this->userManager,
$this->view, $this->view,
$this->keyManager, $this->keyManager,
$this->util,
$this->config, $this->config,
$this->mailer, $this->mailer,
$this->l, $this->l,
@ -212,6 +252,8 @@ class EncryptAllTest extends TestCase {
->setMethods(['encryptUsersFiles']) ->setMethods(['encryptUsersFiles'])
->getMock(); ->getMock();
$this->util->expects($this->any())->method('isMasterKeyEnabled')->willReturn(false);
// set protected property $output // set protected property $output
$this->invokePrivate($encryptAll, 'output', [$this->outputInterface]); $this->invokePrivate($encryptAll, 'output', [$this->outputInterface]);
$this->invokePrivate($encryptAll, 'userPasswords', [['user1' => 'pwd1', 'user2' => 'pwd2']]); $this->invokePrivate($encryptAll, 'userPasswords', [['user1' => 'pwd1', 'user2' => 'pwd2']]);
@ -232,6 +274,7 @@ class EncryptAllTest extends TestCase {
$this->userManager, $this->userManager,
$this->view, $this->view,
$this->keyManager, $this->keyManager,
$this->util,
$this->config, $this->config,
$this->mailer, $this->mailer,
$this->l, $this->l,
@ -239,9 +282,10 @@ class EncryptAllTest extends TestCase {
$this->secureRandom $this->secureRandom
] ]
) )
->setMethods(['encryptFile']) ->setMethods(['encryptFile', 'setupUserFS'])
->getMock(); ->getMock();
$this->util->expects($this->any())->method('isMasterKeyEnabled')->willReturn(false);
$this->view->expects($this->at(0))->method('getDirectoryContent') $this->view->expects($this->at(0))->method('getDirectoryContent')
->with('/user1/files')->willReturn( ->with('/user1/files')->willReturn(
@ -268,8 +312,8 @@ class EncryptAllTest extends TestCase {
} }
); );
$encryptAll->expects($this->at(0))->method('encryptFile')->with('/user1/files/bar'); $encryptAll->expects($this->at(1))->method('encryptFile')->with('/user1/files/bar');
$encryptAll->expects($this->at(1))->method('encryptFile')->with('/user1/files/foo/subfile'); $encryptAll->expects($this->at(2))->method('encryptFile')->with('/user1/files/foo/subfile');
$progressBar = $this->getMockBuilder('Symfony\Component\Console\Helper\ProgressBar') $progressBar = $this->getMockBuilder('Symfony\Component\Console\Helper\ProgressBar')
->disableOriginalConstructor()->getMock(); ->disableOriginalConstructor()->getMock();