Skip to content

Commit

Permalink
Setupfs before access a users keys (#26917)
Browse files Browse the repository at this point in the history
* The file system of a user has to be properly setup before accessing the keys

* Fix unit test execution

* Init mount points for user in more places in Keys\Storage

* Fix encryption key storage tests to properly create required users

* Added test that check if user home is mounted after resolving key
  • Loading branch information
Vincent Petry authored Jan 13, 2017
1 parent b51da5a commit a4883ae
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 7 deletions.
33 changes: 30 additions & 3 deletions lib/private/Encryption/Keys/Storage.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use OC\Files\Filesystem;
use OC\Files\View;
use OCP\Encryption\Keys\IStorage;
use OCP\IUserSession;

class Storage implements IStorage {

Expand All @@ -53,17 +54,25 @@ class Storage implements IStorage {
/** @var array */
private $keyCache = [];

/** @var string */
private $currentUser = null;

/**
* @param View $view
* @param Util $util
* @param View $view view
* @param Util $util encryption util class
* @param IUserSession $session user session
*/
public function __construct(View $view, Util $util) {
public function __construct(View $view, Util $util, IUserSession $session) {
$this->view = $view;
$this->util = $util;

$this->encryption_base_dir = '/files_encryption';
$this->keys_base_dir = $this->encryption_base_dir .'/keys';
$this->root_dir = $this->util->getKeyStorageRoot();

if (!is_null($session) && !is_null($session->getUser())) {
$this->currentUser = $session->getUser()->getUID();
}
}

/**
Expand Down Expand Up @@ -170,6 +179,7 @@ protected function constructUserKeyPath($encryptionModuleId, $keyId, $uid) {
if ($uid === null) {
$path = $this->root_dir . '/' . $this->encryption_base_dir . '/' . $encryptionModuleId . '/' . $keyId;
} else {
$this->setupUserMounts($uid);
$path = $this->root_dir . '/' . $uid . $this->encryption_base_dir . '/'
. $encryptionModuleId . '/' . $uid . '.' . $keyId;
}
Expand Down Expand Up @@ -235,6 +245,7 @@ private function getFileKeyDir($encryptionModuleId, $path) {
if ($this->util->isSystemWideMountPoint($filename, $owner)) {
$keyPath = $this->root_dir . '/' . $this->keys_base_dir . $filename . '/';
} else {
$this->setupUserMounts($owner);
$keyPath = $this->root_dir . '/' . $owner . $this->keys_base_dir . $filename . '/';
}

Expand Down Expand Up @@ -298,6 +309,7 @@ protected function getPathToKeys($path) {
if ($systemWideMountPoint) {
$systemPath = $this->root_dir . '/' . $this->keys_base_dir . $relativePath . '/';
} else {
$this->setupUserMounts($owner);
$systemPath = $this->root_dir . '/' . $owner . $this->keys_base_dir . $relativePath . '/';
}

Expand All @@ -323,4 +335,19 @@ protected function keySetPreparation($path) {
}
}

/**
* Setup the mounts of the given user if different than
* the current user.
*
* This is needed because in many cases the keys are stored
* within the user's home storage.
*
* @param string $uid user id
*/
protected function setupUserMounts($uid) {
if (!is_null($uid) && $uid !== '' && $uid !== $this->currentUser) {
\OC\Files\Filesystem::initMountPoints($uid);
}
}

}
6 changes: 5 additions & 1 deletion lib/private/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,11 @@ public function __construct($webRoot, \OC\Config $config) {
$c->getConfig()
);

return new Encryption\Keys\Storage($view, $util);
return new Encryption\Keys\Storage(
$view,
$util,
$c->getUserSession()
);
});
$this->registerService('TagMapper', function (Server $c) {
return new TagMapper($c->getDatabaseConnection());
Expand Down
63 changes: 60 additions & 3 deletions tests/lib/Encryption/Keys/StorageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,31 @@
namespace Test\Encryption\Keys;

use OC\Encryption\Keys\Storage;
use OC\Encryption\Util;
use OC\Files\View;
use Test\TestCase;
use Test\Traits\UserTrait;
use OCP\IUser;
use OCP\IUserSession;

/**
* Class StorageTest
*
* @group DB
*
* @package Test\Encryption\Keys
*/
class StorageTest extends TestCase {

use UserTrait;

/** @var Storage */
protected $storage;

/** @var \PHPUnit_Framework_MockObject_MockObject */
/** @var \PHPUnit_Framework_MockObject_MockObject | Util */
protected $util;

/** @var \PHPUnit_Framework_MockObject_MockObject */
/** @var \PHPUnit_Framework_MockObject_MockObject | View */
protected $view;

/** @var \PHPUnit_Framework_MockObject_MockObject */
Expand All @@ -55,7 +69,14 @@ public function setUp() {
->disableOriginalConstructor()
->getMock();

$this->storage = new Storage($this->view, $this->util);
$user = $this->createMock(IUser::class);
$user->method('getUID')->willReturn('user1');
$userSession = $this->createMock(IUserSession::class);
$userSession->method('getUser')->willReturn($user);

$this->createUser('user1', '123456');
$this->createUser('user2', '123456');
$this->storage = new Storage($this->view, $this->util, $userSession);
}

public function testSetFileKey() {
Expand Down Expand Up @@ -237,6 +258,42 @@ public function testGetUserKey() {
);
}

public function testGetUserKeyShared() {
$this->view->expects($this->once())
->method('file_get_contents')
->with($this->equalTo('/user2/files_encryption/encModule/user2.publicKey'))
->willReturn('key');
$this->view->expects($this->once())
->method('file_exists')
->with($this->equalTo('/user2/files_encryption/encModule/user2.publicKey'))
->willReturn(true);

$this->assertFalse($this->isUserHomeMounted('user2'));

$this->assertSame('key',
$this->storage->getUserKey('user2', 'publicKey', 'encModule')
);

$this->assertTrue($this->isUserHomeMounted('user2'));
}

/**
* Returns whether the home of the given user was mounted
*
* @param string $userId
* @return boolean true if mounted, false otherwise
*/
private function isUserHomeMounted($userId) {
// verify that user2's FS got mounted when retrieving the key
$mountManager = \OC::$server->getMountManager();
$mounts = $mountManager->getAll();
$mounts = array_filter($mounts, function($mount) use ($userId) {
return ($mount->getMountPoint() === "/$userId/");
});

return !empty($mounts);
}

public function testDeleteUserKey() {
$this->view->expects($this->once())
->method('file_exists')
Expand Down

0 comments on commit a4883ae

Please sign in to comment.