Merge pull request #7794 from owncloud/extstorage-obfuscatepasswords
Obfuscate passwords in ext storage config
This commit is contained in:
commit
2c561c9c50
|
@ -25,5 +25,6 @@ if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == '
|
||||||
}
|
}
|
||||||
|
|
||||||
// connecting hooks
|
// connecting hooks
|
||||||
OCP\Util::connectHook( 'OC_User', 'post_login', 'OC\Files\Storage\iRODS', 'login' );
|
OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\OC_Mount_Config', 'initMountPointsHook');
|
||||||
|
OCP\Util::connectHook('OC_User', 'post_login', 'OC\Files\Storage\iRODS', 'login');
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
*
|
*
|
||||||
* @author Michael Gapczynski
|
* @author Michael Gapczynski
|
||||||
* @copyright 2012 Michael Gapczynski mtgap@owncloud.com
|
* @copyright 2012 Michael Gapczynski mtgap@owncloud.com
|
||||||
|
* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
@ -19,10 +20,16 @@
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
set_include_path(
|
||||||
|
get_include_path() . PATH_SEPARATOR .
|
||||||
|
\OC_App::getAppPath('files_external') . '/3rdparty/phpseclib/phpseclib'
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to configure the config/mount.php and data/$user/mount.php files
|
* Class to configure mount.json globally and for users
|
||||||
*/
|
*/
|
||||||
class OC_Mount_Config {
|
class OC_Mount_Config {
|
||||||
|
// TODO: make this class non-static and give it a proper namespace
|
||||||
|
|
||||||
const MOUNT_TYPE_GLOBAL = 'global';
|
const MOUNT_TYPE_GLOBAL = 'global';
|
||||||
const MOUNT_TYPE_GROUP = 'group';
|
const MOUNT_TYPE_GROUP = 'group';
|
||||||
|
@ -42,6 +49,7 @@ class OC_Mount_Config {
|
||||||
*/
|
*/
|
||||||
public static function getBackends() {
|
public static function getBackends() {
|
||||||
|
|
||||||
|
// FIXME: do not rely on php key order for the options order in the UI
|
||||||
$backends['\OC\Files\Storage\Local']=array(
|
$backends['\OC\Files\Storage\Local']=array(
|
||||||
'backend' => 'Local',
|
'backend' => 'Local',
|
||||||
'configuration' => array(
|
'configuration' => array(
|
||||||
|
@ -158,6 +166,96 @@ class OC_Mount_Config {
|
||||||
return($backends);
|
return($backends);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook that mounts the given user's visible mount points
|
||||||
|
* @param array $data
|
||||||
|
*/
|
||||||
|
public static function initMountPointsHook($data) {
|
||||||
|
$mountPoints = self::getAbsoluteMountPoints($data['user']);
|
||||||
|
foreach ($mountPoints as $mountPoint => $options) {
|
||||||
|
\OC\Files\Filesystem::mount($options['class'], $options['options'], $mountPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mount points for the given user.
|
||||||
|
* The mount point is relative to the data directory.
|
||||||
|
*
|
||||||
|
* @param string $user user
|
||||||
|
* @return array of mount point string as key, mountpoint config as value
|
||||||
|
*/
|
||||||
|
public static function getAbsoluteMountPoints($user) {
|
||||||
|
$mountPoints = array();
|
||||||
|
|
||||||
|
$datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
|
||||||
|
$mount_file = \OC_Config::getValue("mount_file", $datadir . "/mount.json");
|
||||||
|
|
||||||
|
//move config file to it's new position
|
||||||
|
if (is_file(\OC::$SERVERROOT . '/config/mount.json')) {
|
||||||
|
rename(\OC::$SERVERROOT . '/config/mount.json', $mount_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load system mount points
|
||||||
|
$mountConfig = self::readData(false);
|
||||||
|
if (isset($mountConfig[self::MOUNT_TYPE_GLOBAL])) {
|
||||||
|
foreach ($mountConfig[self::MOUNT_TYPE_GLOBAL] as $mountPoint => $options) {
|
||||||
|
$options['options'] = self::decryptPasswords($options['options']);
|
||||||
|
$mountPoints[$mountPoint] = $options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isset($mountConfig[self::MOUNT_TYPE_GROUP])) {
|
||||||
|
foreach ($mountConfig[self::MOUNT_TYPE_GROUP] as $group => $mounts) {
|
||||||
|
if (\OC_Group::inGroup($user, $group)) {
|
||||||
|
foreach ($mounts as $mountPoint => $options) {
|
||||||
|
$mountPoint = self::setUserVars($user, $mountPoint);
|
||||||
|
foreach ($options as &$option) {
|
||||||
|
$option = self::setUserVars($user, $option);
|
||||||
|
}
|
||||||
|
$options['options'] = self::decryptPasswords($options['options']);
|
||||||
|
$mountPoints[$mountPoint] = $options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isset($mountConfig[self::MOUNT_TYPE_USER])) {
|
||||||
|
foreach ($mountConfig[self::MOUNT_TYPE_USER] as $mountUser => $mounts) {
|
||||||
|
if ($mountUser === 'all' or strtolower($mountUser) === strtolower($user)) {
|
||||||
|
foreach ($mounts as $mountPoint => $options) {
|
||||||
|
$mountPoint = self::setUserVars($user, $mountPoint);
|
||||||
|
foreach ($options as &$option) {
|
||||||
|
$option = self::setUserVars($user, $option);
|
||||||
|
}
|
||||||
|
$options['options'] = self::decryptPasswords($options['options']);
|
||||||
|
$mountPoints[$mountPoint] = $options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load personal mount points
|
||||||
|
$mountConfig = self::readData(true);
|
||||||
|
if (isset($mountConfig[self::MOUNT_TYPE_USER][$user])) {
|
||||||
|
foreach ($mountConfig[self::MOUNT_TYPE_USER][$user] as $mountPoint => $options) {
|
||||||
|
$options['options'] = self::decryptPasswords($options['options']);
|
||||||
|
$mountPoints[$mountPoint] = $options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $mountPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill in the correct values for $user
|
||||||
|
*
|
||||||
|
* @param string $user
|
||||||
|
* @param string $input
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private static function setUserVars($user, $input) {
|
||||||
|
return str_replace('$user', $user, $input);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get details on each of the external storage backends, used for the mount config UI
|
* Get details on each of the external storage backends, used for the mount config UI
|
||||||
* Some backends are not available as a personal backend, f.e. Local and such that have
|
* Some backends are not available as a personal backend, f.e. Local and such that have
|
||||||
|
@ -203,6 +301,7 @@ class OC_Mount_Config {
|
||||||
if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
|
if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
|
||||||
$mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15);
|
$mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15);
|
||||||
}
|
}
|
||||||
|
$mount['options'] = self::decryptPasswords($mount['options']);
|
||||||
// Remove '/$user/files/' from mount point
|
// Remove '/$user/files/' from mount point
|
||||||
$mountPoint = substr($mountPoint, 13);
|
$mountPoint = substr($mountPoint, 13);
|
||||||
// Merge the mount point into the current mount points
|
// Merge the mount point into the current mount points
|
||||||
|
@ -228,6 +327,7 @@ class OC_Mount_Config {
|
||||||
if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
|
if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
|
||||||
$mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15);
|
$mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15);
|
||||||
}
|
}
|
||||||
|
$mount['options'] = self::decryptPasswords($mount['options']);
|
||||||
// Remove '/$user/files/' from mount point
|
// Remove '/$user/files/' from mount point
|
||||||
$mountPoint = substr($mountPoint, 13);
|
$mountPoint = substr($mountPoint, 13);
|
||||||
// Merge the mount point into the current mount points
|
// Merge the mount point into the current mount points
|
||||||
|
@ -265,6 +365,7 @@ class OC_Mount_Config {
|
||||||
if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
|
if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
|
||||||
$mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15);
|
$mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15);
|
||||||
}
|
}
|
||||||
|
$mount['options'] = self::decryptPasswords($mount['options']);
|
||||||
// Remove '/uid/files/' from mount point
|
// Remove '/uid/files/' from mount point
|
||||||
$personal[substr($mountPoint, strlen($uid) + 8)] = array(
|
$personal[substr($mountPoint, strlen($uid) + 8)] = array(
|
||||||
'class' => $mount['class'],
|
'class' => $mount['class'],
|
||||||
|
@ -277,12 +378,18 @@ class OC_Mount_Config {
|
||||||
return $personal;
|
return $personal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test connecting using the given backend configuration
|
||||||
|
* @param string $class backend class name
|
||||||
|
* @param array $options backend configuration options
|
||||||
|
* @return bool true if the connection succeeded, false otherwise
|
||||||
|
*/
|
||||||
private static function getBackendStatus($class, $options) {
|
private static function getBackendStatus($class, $options) {
|
||||||
if (self::$skipTest) {
|
if (self::$skipTest) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
foreach ($options as &$option) {
|
foreach ($options as &$option) {
|
||||||
$option = str_replace('$user', OCP\User::getUser(), $option);
|
$option = self::setUserVars(OCP\User::getUser(), $option);
|
||||||
}
|
}
|
||||||
if (class_exists($class)) {
|
if (class_exists($class)) {
|
||||||
try {
|
try {
|
||||||
|
@ -334,7 +441,13 @@ class OC_Mount_Config {
|
||||||
} else {
|
} else {
|
||||||
$mountPoint = '/$user/files/'.ltrim($mountPoint, '/');
|
$mountPoint = '/$user/files/'.ltrim($mountPoint, '/');
|
||||||
}
|
}
|
||||||
$mount = array($applicable => array($mountPoint => array('class' => $class, 'options' => $classOptions)));
|
|
||||||
|
$mount = array($applicable => array(
|
||||||
|
$mountPoint => array(
|
||||||
|
'class' => $class,
|
||||||
|
'options' => self::encryptPasswords($classOptions))
|
||||||
|
)
|
||||||
|
);
|
||||||
$mountPoints = self::readData($isPersonal);
|
$mountPoints = self::readData($isPersonal);
|
||||||
// Merge the new mount point into the current mount points
|
// Merge the new mount point into the current mount points
|
||||||
if (isset($mountPoints[$mountType])) {
|
if (isset($mountPoints[$mountType])) {
|
||||||
|
@ -527,4 +640,71 @@ class OC_Mount_Config {
|
||||||
|
|
||||||
return $txt;
|
return $txt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt passwords in the given config options
|
||||||
|
* @param array $options mount options
|
||||||
|
* @return array updated options
|
||||||
|
*/
|
||||||
|
private static function encryptPasswords($options) {
|
||||||
|
if (isset($options['password'])) {
|
||||||
|
$options['password_encrypted'] = self::encryptPassword($options['password']);
|
||||||
|
// do not unset the password, we want to keep the keys order
|
||||||
|
// on load... because that's how the UI currently works
|
||||||
|
$options['password'] = '';
|
||||||
|
}
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt passwords in the given config options
|
||||||
|
* @param array $options mount options
|
||||||
|
* @return array updated options
|
||||||
|
*/
|
||||||
|
private static function decryptPasswords($options) {
|
||||||
|
// note: legacy options might still have the unencrypted password in the "password" field
|
||||||
|
if (isset($options['password_encrypted'])) {
|
||||||
|
$options['password'] = self::decryptPassword($options['password_encrypted']);
|
||||||
|
unset($options['password_encrypted']);
|
||||||
|
}
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt a single password
|
||||||
|
* @param string $password plain text password
|
||||||
|
* @return encrypted password
|
||||||
|
*/
|
||||||
|
private static function encryptPassword($password) {
|
||||||
|
$cipher = self::getCipher();
|
||||||
|
$iv = \OCP\Util::generateRandomBytes(16);
|
||||||
|
$cipher->setIV($iv);
|
||||||
|
return base64_encode($iv . $cipher->encrypt($password));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts a single password
|
||||||
|
* @param string $encryptedPassword encrypted password
|
||||||
|
* @return plain text password
|
||||||
|
*/
|
||||||
|
private static function decryptPassword($encryptedPassword) {
|
||||||
|
$cipher = self::getCipher();
|
||||||
|
$binaryPassword = base64_decode($encryptedPassword);
|
||||||
|
$iv = substr($binaryPassword, 0, 16);
|
||||||
|
$cipher->setIV($iv);
|
||||||
|
$binaryPassword = substr($binaryPassword, 16);
|
||||||
|
return $cipher->decrypt($binaryPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the encryption cipher
|
||||||
|
*/
|
||||||
|
private static function getCipher() {
|
||||||
|
if (!class_exists('Crypt_AES', false)) {
|
||||||
|
include('Crypt/AES.php');
|
||||||
|
}
|
||||||
|
$cipher = new Crypt_AES(CRYPT_AES_MODE_CBC);
|
||||||
|
$cipher->setKey(\OCP\Config::getSystemValue('passwordsalt'));
|
||||||
|
return $cipher;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ class SMB extends \OC\Files\Storage\StreamWrapper{
|
||||||
$this->share = substr($this->share, 0, -1);
|
$this->share = substr($this->share, 0, -1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new \Exception();
|
throw new \Exception('Invalid configuration');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,9 +40,22 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
|
||||||
private $oldAllowedBackends;
|
private $oldAllowedBackends;
|
||||||
private $allBackends;
|
private $allBackends;
|
||||||
|
|
||||||
|
const TEST_USER1 = 'user1';
|
||||||
|
const TEST_USER2 = 'user2';
|
||||||
|
const TEST_GROUP1 = 'group1';
|
||||||
|
const TEST_GROUP2 = 'group2';
|
||||||
|
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
\OC_User::setUserId('test');
|
\OC_User::createUser(self::TEST_USER1, self::TEST_USER1);
|
||||||
$this->userHome = \OC_User::getHome('test');
|
\OC_User::createUser(self::TEST_USER2, self::TEST_USER2);
|
||||||
|
|
||||||
|
\OC_Group::createGroup(self::TEST_GROUP1);
|
||||||
|
\OC_Group::addToGroup(self::TEST_USER1, self::TEST_GROUP1);
|
||||||
|
\OC_Group::createGroup(self::TEST_GROUP2);
|
||||||
|
\OC_Group::addToGroup(self::TEST_USER2, self::TEST_GROUP2);
|
||||||
|
|
||||||
|
\OC_User::setUserId(self::TEST_USER1);
|
||||||
|
$this->userHome = \OC_User::getHome(self::TEST_USER1);
|
||||||
mkdir($this->userHome);
|
mkdir($this->userHome);
|
||||||
|
|
||||||
$this->dataDir = \OC_Config::getValue(
|
$this->dataDir = \OC_Config::getValue(
|
||||||
|
@ -67,9 +80,12 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
|
||||||
public function tearDown() {
|
public function tearDown() {
|
||||||
OC_Mount_Config::$skipTest = false;
|
OC_Mount_Config::$skipTest = false;
|
||||||
|
|
||||||
|
\OC_User::deleteUser(self::TEST_USER2);
|
||||||
|
\OC_User::deleteUser(self::TEST_USER1);
|
||||||
|
\OC_Group::deleteGroup(self::TEST_GROUP1);
|
||||||
|
\OC_Group::deleteGroup(self::TEST_GROUP2);
|
||||||
|
|
||||||
@unlink($this->dataDir . '/mount.json');
|
@unlink($this->dataDir . '/mount.json');
|
||||||
@unlink($this->userHome . '/mount.json');
|
|
||||||
rmdir($this->userHome);
|
|
||||||
|
|
||||||
OCP\Config::setAppValue(
|
OCP\Config::setAppValue(
|
||||||
'files_external',
|
'files_external',
|
||||||
|
@ -94,6 +110,14 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
|
||||||
return json_decode(file_get_contents($configFile), true);
|
return json_decode(file_get_contents($configFile), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the user config, to simulate existing files
|
||||||
|
*/
|
||||||
|
private function writeUserConfig($config) {
|
||||||
|
$configFile = $this->userHome . '/mount.json';
|
||||||
|
file_put_contents($configFile, json_encode($config));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test mount point validation
|
* Test mount point validation
|
||||||
*/
|
*/
|
||||||
|
@ -113,7 +137,7 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
|
||||||
* Test adding a global mount point
|
* Test adding a global mount point
|
||||||
*/
|
*/
|
||||||
public function testAddGlobalMountPoint() {
|
public function testAddGlobalMountPoint() {
|
||||||
$mountType = OC_Mount_Config::MOUNT_TYPE_GLOBAL;
|
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
|
||||||
$applicable = 'all';
|
$applicable = 'all';
|
||||||
$isPersonal = false;
|
$isPersonal = false;
|
||||||
|
|
||||||
|
@ -135,7 +159,7 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
|
||||||
*/
|
*/
|
||||||
public function testAddMountPointSingleUser() {
|
public function testAddMountPointSingleUser() {
|
||||||
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
|
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
|
||||||
$applicable = 'test';
|
$applicable = self::TEST_USER1;
|
||||||
$isPersonal = true;
|
$isPersonal = true;
|
||||||
|
|
||||||
$this->assertEquals(true, OC_Mount_Config::addMountPoint('/ext', '\OC\Files\Storage\SFTP', array(), $mountType, $applicable, $isPersonal));
|
$this->assertEquals(true, OC_Mount_Config::addMountPoint('/ext', '\OC\Files\Storage\SFTP', array(), $mountType, $applicable, $isPersonal));
|
||||||
|
@ -144,10 +168,10 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
|
||||||
$this->assertEquals(1, count($config));
|
$this->assertEquals(1, count($config));
|
||||||
$this->assertTrue(isset($config[$mountType]));
|
$this->assertTrue(isset($config[$mountType]));
|
||||||
$this->assertTrue(isset($config[$mountType][$applicable]));
|
$this->assertTrue(isset($config[$mountType][$applicable]));
|
||||||
$this->assertTrue(isset($config[$mountType][$applicable]['/test/files/ext']));
|
$this->assertTrue(isset($config[$mountType][$applicable]['/' . self::TEST_USER1 . '/files/ext']));
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'\OC\Files\Storage\SFTP',
|
'\OC\Files\Storage\SFTP',
|
||||||
$config[$mountType][$applicable]['/test/files/ext']['class']
|
$config[$mountType][$applicable]['/' . self::TEST_USER1 . '/files/ext']['class']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +180,7 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
|
||||||
*/
|
*/
|
||||||
public function testAddDisallowedBackendMountPointSingleUser() {
|
public function testAddDisallowedBackendMountPointSingleUser() {
|
||||||
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
|
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
|
||||||
$applicable = 'test';
|
$applicable = self::TEST_USER1;
|
||||||
$isPersonal = true;
|
$isPersonal = true;
|
||||||
|
|
||||||
// local
|
// local
|
||||||
|
@ -181,9 +205,274 @@ class Test_Mount_Config extends \PHPUnit_Framework_TestCase {
|
||||||
public function testAddMountPointUnexistClass() {
|
public function testAddMountPointUnexistClass() {
|
||||||
$storageClass = 'Unexist_Storage';
|
$storageClass = 'Unexist_Storage';
|
||||||
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
|
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
|
||||||
$applicable = 'test';
|
$applicable = self::TEST_USER1;
|
||||||
$isPersonal = false;
|
$isPersonal = false;
|
||||||
$this->assertFalse(OC_Mount_Config::addMountPoint('/ext', $storageClass, array(), $mountType, $applicable, $isPersonal));
|
$this->assertFalse(OC_Mount_Config::addMountPoint('/ext', $storageClass, array(), $mountType, $applicable, $isPersonal));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test reading and writing global config
|
||||||
|
*/
|
||||||
|
public function testReadWriteGlobalConfig() {
|
||||||
|
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
|
||||||
|
$applicable = 'all';
|
||||||
|
$isPersonal = false;
|
||||||
|
$mountConfig = array(
|
||||||
|
'host' => 'smbhost',
|
||||||
|
'user' => 'smbuser',
|
||||||
|
'password' => 'smbpassword',
|
||||||
|
'share' => 'smbshare',
|
||||||
|
'root' => 'smbroot'
|
||||||
|
);
|
||||||
|
|
||||||
|
// write config
|
||||||
|
$this->assertTrue(
|
||||||
|
OC_Mount_Config::addMountPoint(
|
||||||
|
'/ext',
|
||||||
|
'\OC\Files\Storage\SMB',
|
||||||
|
$mountConfig,
|
||||||
|
$mountType,
|
||||||
|
$applicable,
|
||||||
|
$isPersonal
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// re-read config
|
||||||
|
$config = OC_Mount_Config::getSystemMountPoints();
|
||||||
|
$this->assertEquals(1, count($config));
|
||||||
|
$this->assertTrue(isset($config['ext']));
|
||||||
|
$this->assertEquals('\OC\Files\Storage\SMB', $config['ext']['class']);
|
||||||
|
$savedMountConfig = $config['ext']['configuration'];
|
||||||
|
$this->assertEquals($mountConfig, $savedMountConfig);
|
||||||
|
// key order needs to be preserved for the UI...
|
||||||
|
$this->assertEquals(array_keys($mountConfig), array_keys($savedMountConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test reading and writing config
|
||||||
|
*/
|
||||||
|
public function testReadWritePersonalConfig() {
|
||||||
|
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
|
||||||
|
$applicable = self::TEST_USER1;
|
||||||
|
$isPersonal = true;
|
||||||
|
$mountConfig = array(
|
||||||
|
'host' => 'smbhost',
|
||||||
|
'user' => 'smbuser',
|
||||||
|
'password' => 'smbpassword',
|
||||||
|
'share' => 'smbshare',
|
||||||
|
'root' => 'smbroot'
|
||||||
|
);
|
||||||
|
|
||||||
|
// write config
|
||||||
|
$this->assertTrue(
|
||||||
|
OC_Mount_Config::addMountPoint(
|
||||||
|
'/ext',
|
||||||
|
'\OC\Files\Storage\SMB',
|
||||||
|
$mountConfig,
|
||||||
|
$mountType,
|
||||||
|
$applicable,
|
||||||
|
$isPersonal
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// re-read config
|
||||||
|
$config = OC_Mount_Config::getPersonalMountPoints();
|
||||||
|
$this->assertEquals(1, count($config));
|
||||||
|
$this->assertTrue(isset($config['ext']));
|
||||||
|
$this->assertEquals('\OC\Files\Storage\SMB', $config['ext']['class']);
|
||||||
|
$savedMountConfig = $config['ext']['configuration'];
|
||||||
|
$this->assertEquals($mountConfig, $savedMountConfig);
|
||||||
|
// key order needs to be preserved for the UI...
|
||||||
|
$this->assertEquals(array_keys($mountConfig), array_keys($savedMountConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test password obfuscation
|
||||||
|
*/
|
||||||
|
public function testPasswordObfuscation() {
|
||||||
|
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
|
||||||
|
$applicable = self::TEST_USER1;
|
||||||
|
$isPersonal = true;
|
||||||
|
$mountConfig = array(
|
||||||
|
'host' => 'smbhost',
|
||||||
|
'user' => 'smbuser',
|
||||||
|
'password' => 'smbpassword',
|
||||||
|
'share' => 'smbshare',
|
||||||
|
'root' => 'smbroot'
|
||||||
|
);
|
||||||
|
|
||||||
|
// write config
|
||||||
|
$this->assertTrue(
|
||||||
|
OC_Mount_Config::addMountPoint(
|
||||||
|
'/ext',
|
||||||
|
'\OC\Files\Storage\SMB',
|
||||||
|
$mountConfig,
|
||||||
|
$mountType,
|
||||||
|
$applicable,
|
||||||
|
$isPersonal
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// note: password re-reading is covered by testReadWritePersonalConfig
|
||||||
|
|
||||||
|
// check that password inside the file is NOT in plain text
|
||||||
|
$config = $this->readUserConfig();
|
||||||
|
$savedConfig = $config[$mountType][$applicable]['/' . self::TEST_USER1 . '/files/ext']['options'];
|
||||||
|
|
||||||
|
// no more clear text password in file (kept because of key order)
|
||||||
|
$this->assertEquals('', $savedConfig['password']);
|
||||||
|
|
||||||
|
// encrypted password is present
|
||||||
|
$this->assertNotEquals($mountConfig['password'], $savedConfig['password_encrypted']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test read legacy passwords
|
||||||
|
*/
|
||||||
|
public function testReadLegacyPassword() {
|
||||||
|
$mountType = OC_Mount_Config::MOUNT_TYPE_USER;
|
||||||
|
$applicable = self::TEST_USER1;
|
||||||
|
$isPersonal = true;
|
||||||
|
$mountConfig = array(
|
||||||
|
'host' => 'smbhost',
|
||||||
|
'user' => 'smbuser',
|
||||||
|
'password' => 'smbpassword',
|
||||||
|
'share' => 'smbshare',
|
||||||
|
'root' => 'smbroot'
|
||||||
|
);
|
||||||
|
|
||||||
|
// write config
|
||||||
|
$this->assertTrue(
|
||||||
|
OC_Mount_Config::addMountPoint(
|
||||||
|
'/ext',
|
||||||
|
'\OC\Files\Storage\SMB',
|
||||||
|
$mountConfig,
|
||||||
|
$mountType,
|
||||||
|
$applicable,
|
||||||
|
$isPersonal
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$config = $this->readUserConfig();
|
||||||
|
// simulate non-encrypted password situation
|
||||||
|
$config[$mountType][$applicable]['/' . self::TEST_USER1 . '/files/ext']['options']['password'] = 'smbpasswd';
|
||||||
|
|
||||||
|
$this->writeUserConfig($config);
|
||||||
|
|
||||||
|
// re-read config, password was read correctly
|
||||||
|
$config = OC_Mount_Config::getPersonalMountPoints();
|
||||||
|
$savedMountConfig = $config['ext']['configuration'];
|
||||||
|
$this->assertEquals($mountConfig, $savedMountConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mountDataProvider() {
|
||||||
|
return array(
|
||||||
|
// Tests for visible mount points
|
||||||
|
// system mount point for all users
|
||||||
|
array(
|
||||||
|
false,
|
||||||
|
OC_Mount_Config::MOUNT_TYPE_USER,
|
||||||
|
'all',
|
||||||
|
self::TEST_USER1,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
// system mount point for a specific user
|
||||||
|
array(
|
||||||
|
false,
|
||||||
|
OC_Mount_Config::MOUNT_TYPE_USER,
|
||||||
|
self::TEST_USER1,
|
||||||
|
self::TEST_USER1,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
// system mount point for a specific group
|
||||||
|
array(
|
||||||
|
false,
|
||||||
|
OC_Mount_Config::MOUNT_TYPE_GROUP,
|
||||||
|
self::TEST_GROUP1,
|
||||||
|
self::TEST_USER1,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
// user mount point
|
||||||
|
array(
|
||||||
|
true,
|
||||||
|
OC_Mount_Config::MOUNT_TYPE_USER,
|
||||||
|
self::TEST_USER1,
|
||||||
|
self::TEST_USER1,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
|
||||||
|
// Tests for non-visible mount points
|
||||||
|
// system mount point for another user
|
||||||
|
array(
|
||||||
|
false,
|
||||||
|
OC_Mount_Config::MOUNT_TYPE_USER,
|
||||||
|
self::TEST_USER2,
|
||||||
|
self::TEST_USER1,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
// system mount point for a specific group
|
||||||
|
array(
|
||||||
|
false,
|
||||||
|
OC_Mount_Config::MOUNT_TYPE_GROUP,
|
||||||
|
self::TEST_GROUP2,
|
||||||
|
self::TEST_USER1,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
// user mount point
|
||||||
|
array(
|
||||||
|
true,
|
||||||
|
OC_Mount_Config::MOUNT_TYPE_USER,
|
||||||
|
self::TEST_USER1,
|
||||||
|
self::TEST_USER2,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test mount points used at mount time, making sure
|
||||||
|
* the configuration is prepared properly.
|
||||||
|
*
|
||||||
|
* @dataProvider mountDataProvider
|
||||||
|
* @param bool $isPersonal true for personal mount point, false for system mount point
|
||||||
|
* @param string $mountType mount type
|
||||||
|
* @param string $applicable target user/group or "all"
|
||||||
|
* @param string $testUser user for which to retrieve the mount points
|
||||||
|
* @param bool $expectVisible whether to expect the mount point to be visible for $testUser
|
||||||
|
*/
|
||||||
|
public function testMount($isPersonal, $mountType, $applicable, $testUser, $expectVisible) {
|
||||||
|
$mountConfig = array(
|
||||||
|
'host' => 'someost',
|
||||||
|
'user' => 'someuser',
|
||||||
|
'password' => 'somepassword',
|
||||||
|
'root' => 'someroot'
|
||||||
|
);
|
||||||
|
|
||||||
|
// add mount point as "test" user
|
||||||
|
$this->assertTrue(
|
||||||
|
OC_Mount_Config::addMountPoint(
|
||||||
|
'/ext',
|
||||||
|
'\OC\Files\Storage\SMB',
|
||||||
|
$mountConfig,
|
||||||
|
$mountType,
|
||||||
|
$applicable,
|
||||||
|
$isPersonal
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// check mount points in the perspective of user $testUser
|
||||||
|
\OC_User::setUserId($testUser);
|
||||||
|
|
||||||
|
$mountPoints = OC_Mount_Config::getAbsoluteMountPoints($testUser);
|
||||||
|
if ($expectVisible) {
|
||||||
|
$this->assertEquals(1, count($mountPoints));
|
||||||
|
$this->assertTrue(isset($mountPoints['/' . self::TEST_USER1 . '/files/ext']));
|
||||||
|
$this->assertEquals('\OC\Files\Storage\SMB', $mountPoints['/' . self::TEST_USER1 . '/files/ext']['class']);
|
||||||
|
$this->assertEquals($mountConfig, $mountPoints['/' . self::TEST_USER1 . '/files/ext']['options']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->assertEquals(0, count($mountPoints));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,81 +320,11 @@ class Filesystem {
|
||||||
else {
|
else {
|
||||||
self::mount('\OC\Files\Storage\Local', array('datadir' => $root), $user);
|
self::mount('\OC\Files\Storage\Local', array('datadir' => $root), $user);
|
||||||
}
|
}
|
||||||
$datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
|
|
||||||
$mount_file = \OC_Config::getValue("mount_file", $datadir . "/mount.json");
|
|
||||||
|
|
||||||
//move config file to it's new position
|
|
||||||
if (is_file(\OC::$SERVERROOT . '/config/mount.json')) {
|
|
||||||
rename(\OC::$SERVERROOT . '/config/mount.json', $mount_file);
|
|
||||||
}
|
|
||||||
// Load system mount points
|
|
||||||
if (is_file(\OC::$SERVERROOT . '/config/mount.php') or is_file($mount_file)) {
|
|
||||||
if (is_file($mount_file)) {
|
|
||||||
$mountConfig = json_decode(file_get_contents($mount_file), true);
|
|
||||||
} elseif (is_file(\OC::$SERVERROOT . '/config/mount.php')) {
|
|
||||||
$mountConfig = $parser->parsePHP(file_get_contents(\OC::$SERVERROOT . '/config/mount.php'));
|
|
||||||
}
|
|
||||||
if (isset($mountConfig['global'])) {
|
|
||||||
foreach ($mountConfig['global'] as $mountPoint => $options) {
|
|
||||||
self::mount($options['class'], $options['options'], $mountPoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isset($mountConfig['group'])) {
|
|
||||||
foreach ($mountConfig['group'] as $group => $mounts) {
|
|
||||||
if (\OC_Group::inGroup($user, $group)) {
|
|
||||||
foreach ($mounts as $mountPoint => $options) {
|
|
||||||
$mountPoint = self::setUserVars($user, $mountPoint);
|
|
||||||
foreach ($options as &$option) {
|
|
||||||
$option = self::setUserVars($user, $option);
|
|
||||||
}
|
|
||||||
self::mount($options['class'], $options['options'], $mountPoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isset($mountConfig['user'])) {
|
|
||||||
foreach ($mountConfig['user'] as $mountUser => $mounts) {
|
|
||||||
if ($mountUser === 'all' or strtolower($mountUser) === strtolower($user)) {
|
|
||||||
foreach ($mounts as $mountPoint => $options) {
|
|
||||||
$mountPoint = self::setUserVars($user, $mountPoint);
|
|
||||||
foreach ($options as &$option) {
|
|
||||||
$option = self::setUserVars($user, $option);
|
|
||||||
}
|
|
||||||
self::mount($options['class'], $options['options'], $mountPoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Load personal mount points
|
|
||||||
if (is_file($root . '/mount.php') or is_file($root . '/mount.json')) {
|
|
||||||
if (is_file($root . '/mount.json')) {
|
|
||||||
$mountConfig = json_decode(file_get_contents($root . '/mount.json'), true);
|
|
||||||
} elseif (is_file($root . '/mount.php')) {
|
|
||||||
$mountConfig = $parser->parsePHP(file_get_contents($root . '/mount.php'));
|
|
||||||
}
|
|
||||||
if (isset($mountConfig['user'][$user])) {
|
|
||||||
foreach ($mountConfig['user'][$user] as $mountPoint => $options) {
|
|
||||||
self::mount($options['class'], $options['options'], $mountPoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chance to mount for other storages
|
// Chance to mount for other storages
|
||||||
\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user, 'user_dir' => $root));
|
\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user, 'user_dir' => $root));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* fill in the correct values for $user
|
|
||||||
*
|
|
||||||
* @param string $user
|
|
||||||
* @param string $input
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private static function setUserVars($user, $input) {
|
|
||||||
return str_replace('$user', $user, $input);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the default filesystem view
|
* get the default filesystem view
|
||||||
*
|
*
|
||||||
|
|
|
@ -492,4 +492,13 @@ class Util {
|
||||||
public static function isValidFileName($file) {
|
public static function isValidFileName($file) {
|
||||||
return \OC_Util::isValidFileName($file);
|
return \OC_Util::isValidFileName($file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generates a cryptographic secure pseudo-random string
|
||||||
|
* @param Int $length of the random string
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static function generateRandomBytes($length = 30) {
|
||||||
|
return \OC_Util::generateRandomBytes($length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue