Merge pull request #22791 from owncloud/enc_master_key_improvements

Enc master key improvements
This commit is contained in:
Vincent Petry 2016-04-21 11:48:26 +02:00
commit b50d3255fb
7 changed files with 119 additions and 76 deletions

View File

@ -66,6 +66,11 @@ class Application extends \OCP\AppFramework\App {
$session = $this->getContainer()->query('Session'); $session = $this->getContainer()->query('Session');
$session->setStatus(Session::RUN_MIGRATION); $session->setStatus(Session::RUN_MIGRATION);
} }
if ($this->encryptionManager->isEnabled() && $encryptionSystemReady) {
/** @var Setup $setup */
$setup = $this->getContainer()->query('UserSetup');
$setup->setupSystem();
}
} }
/** /**

View File

@ -118,22 +118,29 @@ class UserHooks implements IHook {
public function addHooks() { public function addHooks() {
OCUtil::connectHook('OC_User', 'post_login', $this, 'login'); OCUtil::connectHook('OC_User', 'post_login', $this, 'login');
OCUtil::connectHook('OC_User', 'logout', $this, 'logout'); OCUtil::connectHook('OC_User', 'logout', $this, 'logout');
OCUtil::connectHook('OC_User',
'post_setPassword', // this hooks only make sense if no master key is used
$this, if ($this->util->isMasterKeyEnabled() === false) {
'setPassphrase'); OCUtil::connectHook('OC_User',
OCUtil::connectHook('OC_User', 'post_setPassword',
'pre_setPassword', $this,
$this, 'setPassphrase');
'preSetPassphrase');
OCUtil::connectHook('OC_User', OCUtil::connectHook('OC_User',
'post_createUser', 'pre_setPassword',
$this, $this,
'postCreateUser'); 'preSetPassphrase');
OCUtil::connectHook('OC_User',
'post_deleteUser', OCUtil::connectHook('OC_User',
$this, 'post_createUser',
'postDeleteUser'); $this,
'postCreateUser');
OCUtil::connectHook('OC_User',
'post_deleteUser',
$this,
'postDeleteUser');
}
} }
@ -152,12 +159,10 @@ class UserHooks implements IHook {
// ensure filesystem is loaded // ensure filesystem is loaded
if (!\OC\Files\Filesystem::$loaded) { if (!\OC\Files\Filesystem::$loaded) {
\OC_Util::setupFS($params['uid']); $this->setupFS($params['uid']);
} }
if ($this->util->isMasterKeyEnabled() === false) {
// setup user, if user not ready force relogin $this->userSetup->setupUser($params['uid'], $params['password']);
if (!$this->userSetup->setupUser($params['uid'], $params['password'])) {
return false;
} }
$this->keyManager->init($params['uid'], $params['password']); $this->keyManager->init($params['uid'], $params['password']);
@ -302,7 +307,16 @@ class UserHooks implements IHook {
public function postPasswordReset($params) { public function postPasswordReset($params) {
$password = $params['password']; $password = $params['password'];
$this->keyManager->replaceUserKeys($params['uid']); $this->keyManager->deleteUserKeys($params['uid']);
$this->userSetup->setupServerSide($params['uid'], $password); $this->userSetup->setupUser($params['uid'], $password);
}
/**
* setup file system for user
*
* @param string $uid user id
*/
protected function setupFS($uid) {
\OC_Util::setupFS($uid);
} }
} }

View File

@ -174,6 +174,11 @@ class KeyManager {
* check if a key pair for the master key exists, if not we create one * check if a key pair for the master key exists, if not we create one
*/ */
public function validateMasterKey() { public function validateMasterKey() {
if ($this->util->isMasterKeyEnabled() === false) {
return;
}
$masterKey = $this->getPublicMasterKey(); $masterKey = $this->getPublicMasterKey();
if (empty($masterKey)) { if (empty($masterKey)) {
$keyPair = $this->crypt->createKeyPair(); $keyPair = $this->crypt->createKeyPair();
@ -334,7 +339,7 @@ class KeyManager {
/** /**
* Decrypt private key and store it * Decrypt private key and store it
* *
* @param string $uid userid * @param string $uid user id
* @param string $passPhrase users password * @param string $passPhrase users password
* @return boolean * @return boolean
*/ */
@ -342,7 +347,6 @@ class KeyManager {
$this->session->setStatus(Session::INIT_EXECUTED); $this->session->setStatus(Session::INIT_EXECUTED);
try { try {
if($this->util->isMasterKeyEnabled()) { if($this->util->isMasterKeyEnabled()) {
$uid = $this->getMasterKeyId(); $uid = $this->getMasterKeyId();
@ -554,9 +558,11 @@ class KeyManager {
} }
/** /**
* creat a backup of the users private and public key and then delete it
*
* @param string $uid * @param string $uid
*/ */
public function replaceUserKeys($uid) { public function deleteUserKeys($uid) {
$this->backupAllKeys('password_reset'); $this->backupAllKeys('password_reset');
$this->deletePublicKey($uid); $this->deletePublicKey($uid);
$this->deletePrivateKey($uid); $this->deletePrivateKey($uid);

View File

@ -66,29 +66,23 @@ class Setup {
} }
/** /**
* @param string $uid userid * @param string $uid user id
* @param string $password user password * @param string $password user password
* @return bool * @return bool
*/ */
public function setupUser($uid, $password) { public function setupUser($uid, $password) {
return $this->setupServerSide($uid, $password);
}
/**
* check if user has a key pair, if not we create one
*
* @param string $uid userid
* @param string $password user password
* @return bool
*/
public function setupServerSide($uid, $password) {
$this->keyManager->validateShareKey();
$this->keyManager->validateMasterKey();
// Check if user already has keys
if (!$this->keyManager->userHasKeys($uid)) { if (!$this->keyManager->userHasKeys($uid)) {
return $this->keyManager->storeKeyPair($uid, $password, return $this->keyManager->storeKeyPair($uid, $password,
$this->crypt->createKeyPair()); $this->crypt->createKeyPair());
} }
return true; return true;
} }
/**
* make sure that all system keys exists
*/
public function setupSystem() {
$this->keyManager->validateShareKey();
$this->keyManager->validateMasterKey();
}
} }

View File

@ -77,7 +77,7 @@ class UserHooksTest extends TestCase {
private $params = ['uid' => 'testUser', 'password' => 'password']; private $params = ['uid' => 'testUser', 'password' => 'password'];
public function testLogin() { public function testLogin() {
$this->userSetupMock->expects($this->exactly(2)) $this->userSetupMock->expects($this->once())
->method('setupUser') ->method('setupUser')
->willReturnOnConsecutiveCalls(true, false); ->willReturnOnConsecutiveCalls(true, false);
@ -86,7 +86,6 @@ class UserHooksTest extends TestCase {
->with('testUser', 'password'); ->with('testUser', 'password');
$this->assertNull($this->instance->login($this->params)); $this->assertNull($this->instance->login($this->params));
$this->assertFalse($this->instance->login($this->params));
} }
public function testLogout() { public function testLogout() {
@ -279,11 +278,11 @@ class UserHooksTest extends TestCase {
public function testPostPasswordReset() { public function testPostPasswordReset() {
$this->keyManagerMock->expects($this->once()) $this->keyManagerMock->expects($this->once())
->method('replaceUserKeys') ->method('deleteUserKeys')
->with('testUser'); ->with('testUser');
$this->userSetupMock->expects($this->once()) $this->userSetupMock->expects($this->once())
->method('setupServerSide') ->method('setupUser')
->with('testUser', 'password'); ->with('testUser', 'password');
$this->assertNull($this->instance->postPasswordReset($this->params)); $this->assertNull($this->instance->postPasswordReset($this->params));
@ -339,16 +338,22 @@ class UserHooksTest extends TestCase {
$this->sessionMock = $sessionMock; $this->sessionMock = $sessionMock;
$this->recoveryMock = $recoveryMock; $this->recoveryMock = $recoveryMock;
$this->utilMock = $utilMock; $this->utilMock = $utilMock;
$this->instance = new UserHooks($this->keyManagerMock, $this->utilMock->expects($this->any())->method('isMasterKeyEnabled')->willReturn(false);
$this->userManagerMock,
$this->loggerMock, $this->instance = $this->getMockBuilder('OCA\Encryption\Hooks\UserHooks')
$this->userSetupMock, ->setConstructorArgs(
$this->userSessionMock, [
$this->utilMock, $this->keyManagerMock,
$this->sessionMock, $this->userManagerMock,
$this->cryptMock, $this->loggerMock,
$this->recoveryMock $this->userSetupMock,
); $this->userSessionMock,
$this->utilMock,
$this->sessionMock,
$this->cryptMock,
$this->recoveryMock
]
)->setMethods(['setupFS'])->getMock();
} }

View File

@ -41,26 +41,6 @@ class SetupTest extends TestCase {
*/ */
private $instance; private $instance;
public function testSetupServerSide() {
$this->keyManagerMock->expects($this->exactly(2))->method('validateShareKey');
$this->keyManagerMock->expects($this->exactly(2))->method('validateMasterKey');
$this->keyManagerMock->expects($this->exactly(2))
->method('userHasKeys')
->with('admin')
->willReturnOnConsecutiveCalls(true, false);
$this->assertTrue($this->instance->setupServerSide('admin',
'password'));
$this->keyManagerMock->expects($this->once())
->method('storeKeyPair')
->with('admin', 'password')
->willReturn(false);
$this->assertFalse($this->instance->setupServerSide('admin',
'password'));
}
protected function setUp() { protected function setUp() {
parent::setUp(); parent::setUp();
$logMock = $this->getMock('OCP\ILogger'); $logMock = $this->getMock('OCP\ILogger');
@ -81,4 +61,43 @@ class SetupTest extends TestCase {
$this->keyManagerMock); $this->keyManagerMock);
} }
public function testSetupSystem() {
$this->keyManagerMock->expects($this->once())->method('validateShareKey');
$this->keyManagerMock->expects($this->once())->method('validateMasterKey');
$this->instance->setupSystem();
}
/**
* @dataProvider dataTestSetupUser
*
* @param bool $hasKeys
* @param bool $expected
*/
public function testSetupUser($hasKeys, $expected) {
$this->keyManagerMock->expects($this->once())->method('userHasKeys')
->with('uid')->willReturn($hasKeys);
if ($hasKeys) {
$this->keyManagerMock->expects($this->never())->method('storeKeyPair');
} else {
$this->cryptMock->expects($this->once())->method('createKeyPair')->willReturn('keyPair');
$this->keyManagerMock->expects($this->once())->method('storeKeyPair')
->with('uid', 'password', 'keyPair')->willReturn(true);
}
$this->assertSame($expected,
$this->instance->setupUser('uid', 'password')
);
}
public function dataTestSetupUser() {
return [
[true, true],
[false, true]
];
}
} }

View File

@ -63,7 +63,7 @@ trait EncryptionTrait {
$keyManager = $container->query('KeyManager'); $keyManager = $container->query('KeyManager');
/** @var Setup $userSetup */ /** @var Setup $userSetup */
$userSetup = $container->query('UserSetup'); $userSetup = $container->query('UserSetup');
$userSetup->setupServerSide($name, $password); $userSetup->setupUser($name, $password);
$keyManager->init($name, $password); $keyManager->init($name, $password);
} }