Skip to content
Snippets Groups Projects
Unverified Commit bfd61d84 authored by blizzz's avatar blizzz Committed by GitHub
Browse files

Merge pull request #14174 from nextcloud/feature/noid/extstorage-mountconfighandler

Mount configuration handlers for external storages
parents bf19431f 173836b9
No related branches found
No related tags found
No related merge requests found
Showing
with 602 additions and 37 deletions
......@@ -29,6 +29,7 @@
namespace OCA\Files_External\AppInfo;
use OCA\Files_External\Config\UserPlaceholderHandler;
use OCA\Files_External\Lib\Auth\PublicKey\RSAPrivateKey;
use OCA\Files_External\Lib\Auth\SMB\KerberosAuth;
use \OCP\AppFramework\App;
......@@ -67,7 +68,12 @@ use OCP\Files\Config\IUserMountCache;
*/
class Application extends App implements IBackendProvider, IAuthMechanismProvider {
public function __construct(array $urlParams = array()) {
/**
* Application constructor.
*
* @throws \OCP\AppFramework\QueryException
*/
public function __construct(array $urlParams = []) {
parent::__construct('files_external', $urlParams);
$container = $this->getContainer();
......@@ -76,15 +82,20 @@ class Application extends App implements IBackendProvider, IAuthMechanismProvide
return $c->getServer()->query('UserMountCache');
});
/** @var BackendService $backendService */
$backendService = $container->query(BackendService::class);
$backendService->registerBackendProvider($this);
$backendService->registerAuthMechanismProvider($this);
$backendService->registerConfigHandler('user', function() use ($container) {
return $container->query(UserPlaceholderHandler::class);
});
// force-load auth mechanisms since some will register hooks
// TODO: obsolete these and use the TokenProvider to get the user's password from the session
$this->getAuthMechanisms();
// app developers: do NOT depend on this! it will disappear with oC 9.0!
// don't remove this, as app loading order might be a side effect and
// querying the service from the server not reliable
\OC::$server->getEventDispatcher()->dispatch(
'OCA\\Files_External::loadAdditionalBackends'
);
......
......@@ -29,7 +29,6 @@ namespace OCA\Files_External\Config;
use OC\Files\Storage\Wrapper\Availability;
use OCA\Files_External\Migration\StorageMigrator;
use OCP\Files\Storage;
use OC\Files\Mount\MountPoint;
use OCP\Files\Storage\IStorageFactory;
use OCA\Files_External\Lib\PersonalMount;
use OCP\Files\Config\IMountProvider;
......@@ -73,12 +72,11 @@ class ConfigAdapter implements IMountProvider {
*
* @param StorageConfig $storage
* @param IUser $user
* @throws \OCP\AppFramework\QueryException
*/
private function prepareStorageConfig(StorageConfig &$storage, IUser $user) {
foreach ($storage->getBackendOptions() as $option => $value) {
$storage->setBackendOption($option, \OC_Mount_Config::setUserVars(
$user->getUID(), $value
));
$storage->setBackendOption($option, \OC_Mount_Config::substitutePlaceholdersInConfig($value));
}
$objectStore = $storage->getBackendOption('objectstore');
......
<?php
/**
* @copyright Copyright (c) 2019 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Files_External\Config;
/**
* Interface IConfigHandler
*
* @package OCA\Files_External\Config
* @since 16.0.0
*/
interface IConfigHandler {
/**
* @param mixed $optionValue
* @return mixed the same type as $optionValue
* @since 16.0.0
*/
public function handle($optionValue);
}
<?php
/**
* @copyright Copyright (c) 2019 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Files_External\Config;
/**
* Trait SimpleSubstitutionTrait
*
* @package OCA\Files_External\Config
* @since 16.0.0
*/
trait SimpleSubstitutionTrait {
/**
* @var string the placeholder without $ prefix
* @since 16.0.0
*/
private $placeholder;
/** @var string */
protected $sanitizedPlaceholder;
/**
* @param mixed $optionValue
* @param string $replacement
* @return mixed
* @since 16.0.0
*/
private function processInput($optionValue, string $replacement) {
$this->checkPlaceholder();
if (is_array($optionValue)) {
foreach ($optionValue as &$value) {
$value = $this->substituteIfString($value, $replacement);
}
} else {
$optionValue = $this->substituteIfString($optionValue, $replacement);
}
return $optionValue;
}
/**
* @throws \RuntimeException
*/
protected function checkPlaceholder(): void {
$this->sanitizedPlaceholder = trim(strtolower($this->placeholder));
if(!(bool)\preg_match('/^[a-z0-9]*$/', $this->sanitizedPlaceholder)) {
throw new \RuntimeException(sprintf(
'Invalid placeholder %s, only [a-z0-9] are allowed', $this->sanitizedPlaceholder
));
}
if($this->sanitizedPlaceholder === '') {
throw new \RuntimeException('Invalid empty placeholder');
}
}
/**
* @param mixed $value
* @param string $replacement
* @return mixed
*/
protected function substituteIfString($value, string $replacement) {
if(is_string($value)) {
return str_ireplace('$' . $this->sanitizedPlaceholder, $replacement, $value);
}
return $value;
}
}
<?php
/**
* @copyright Copyright (c) 2019 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Files_External\Config;
use OCP\IUserSession;
class UserPlaceholderHandler implements IConfigHandler {
use SimpleSubstitutionTrait;
/** @var IUserSession */
private $session;
public function __construct(IUserSession $session) {
$this->session = $session;
$this->placeholder = 'user';
}
/**
* @param mixed $optionValue
* @return mixed the same type as $optionValue
* @since 16.0.0
*/
public function handle($optionValue) {
$user = $this->session->getUser();
if($user === null) {
return $optionValue;
}
$uid = $user->getUID();
return $this->processInput($optionValue, $uid);
}
}
......@@ -44,8 +44,6 @@ class FTP extends StreamWrapper{
private $secure;
private $root;
private static $tempFiles=array();
public function __construct($params) {
if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
$this->host=$params['host'];
......
......@@ -4,6 +4,7 @@
*
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @license AGPL-3.0
*
......@@ -23,6 +24,7 @@
namespace OCA\Files_External\Service;
use OCA\Files_External\Config\IConfigHandler;
use \OCP\IConfig;
use \OCA\Files_External\Lib\Backend\Backend;
......@@ -67,6 +69,11 @@ class BackendService {
/** @var IAuthMechanismProvider[] */
private $authMechanismProviders = [];
/** @var callable[] */
private $configHandlerLoaders = [];
private $configHandlers = [];
/**
* @param IConfig $config
*/
......@@ -280,4 +287,66 @@ class BackendService {
protected function isAllowedAuthMechanism(AuthMechanism $authMechanism) {
return true; // not implemented
}
/**
* registers a configuration handler
*
* The function of the provided $placeholder is mostly to act a sorting
* criteria, so longer placeholders are replaced first. This avoids
* "$user" overwriting parts of "$userMail" and "$userLang", for example.
* The provided value should not contain the $ prefix, only a-z0-9 are
* allowed. Upper case letters are lower cased, the replacement is case-
* insensitive.
*
* The configHandlerLoader should just instantiate the handler on demand.
* For now all handlers are instantiated when a mount is loaded, independent
* of whether the placeholder is present or not. This may change in future.
*
* @since 16.0.0
*/
public function registerConfigHandler(string $placeholder, callable $configHandlerLoader) {
$placeholder = trim(strtolower($placeholder));
if(!(bool)\preg_match('/^[a-z0-9]*$/', $placeholder)) {
throw new \RuntimeException(sprintf(
'Invalid placeholder %s, only [a-z0-9] are allowed', $placeholder
));
}
if($placeholder === '') {
throw new \RuntimeException('Invalid empty placeholder');
}
if(isset($this->configHandlerLoaders[$placeholder]) || isset($this->configHandlers[$placeholder])) {
throw new \RuntimeException(sprintf('A handler is already registered for %s', $placeholder));
}
$this->configHandlerLoaders[$placeholder] = $configHandlerLoader;
}
protected function loadConfigHandlers():void {
$newLoaded = false;
foreach ($this->configHandlerLoaders as $placeholder => $loader) {
$handler = $loader();
if(!$handler instanceof IConfigHandler) {
throw new \RuntimeException(sprintf(
'Handler for %s is not an instance of IConfigHandler', $placeholder
));
}
$this->configHandlers[$placeholder] = $handler;
$newLoaded = true;
}
$this->configHandlerLoaders = [];
if($newLoaded) {
// ensure those with longest placeholders come first,
// to avoid substring matches
uksort($this->configHandlers, function ($phA, $phB) {
return strlen($phB) <=> strlen($phA);
});
}
}
/**
* @since 16.0.0
*/
public function getConfigHandlers() {
$this->loadConfigHandlers();
return $this->configHandlers;
}
}
......@@ -3,6 +3,7 @@
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Andreas Fischer <bantu@owncloud.com>
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Bart Visscher <bartv@thisnet.nl>
* @author Björn Schießle <bjoern@schiessle.org>
* @author Frank Karlitschek <frank@karlitschek.de>
......@@ -35,6 +36,8 @@
*
*/
use OCA\Files_External\Config\IConfigHandler;
use OCA\Files_External\Config\UserPlaceholderHandler;
use phpseclib\Crypt\AES;
use \OCA\Files_External\AppInfo\Application;
use \OCA\Files_External\Lib\Backend\LegacyBackend;
......@@ -104,7 +107,7 @@ class OC_Mount_Config {
$mountPoint = '/'.$uid.'/files'.$storage->getMountPoint();
$mountEntry = self::prepareMountPointEntry($storage, false);
foreach ($mountEntry['options'] as &$option) {
$option = self::setUserVars($uid, $option);
$option = self::substitutePlaceholdersInConfig($option);
}
$mountPoints[$mountPoint] = $mountEntry;
}
......@@ -113,7 +116,7 @@ class OC_Mount_Config {
$mountPoint = '/'.$uid.'/files'.$storage->getMountPoint();
$mountEntry = self::prepareMountPointEntry($storage, true);
foreach ($mountEntry['options'] as &$option) {
$option = self::setUserVars($uid, $option);
$option = self::substitutePlaceholdersInConfig($uid, $option);
}
$mountPoints[$mountPoint] = $mountEntry;
}
......@@ -199,18 +202,26 @@ class OC_Mount_Config {
* @param string $user user value
* @param string|array $input
* @return string
* @deprecated use self::substitutePlaceholdersInConfig($input)
*/
public static function setUserVars($user, $input) {
if (is_array($input)) {
foreach ($input as &$value) {
if (is_string($value)) {
$value = str_replace('$user', $user, $value);
}
}
} else {
if (is_string($input)) {
$input = str_replace('$user', $user, $input);
}
$handler = self::$app->getContainer()->query(UserPlaceholderHandler::class);
return $handler->handle($input);
}
/**
* @param mixed $input
* @return mixed
* @throws \OCP\AppFramework\QueryException
* @since 16.0.0
*/
public static function substitutePlaceholdersInConfig($input) {
/** @var BackendService $backendService */
$backendService = self::$app->getContainer()->query(BackendService::class);
/** @var IConfigHandler[] $handlers */
$handlers = $backendService->getConfigHandlers();
foreach ($handlers as $handler) {
$input = $handler->handle($input);
}
return $input;
}
......@@ -229,7 +240,21 @@ class OC_Mount_Config {
return StorageNotAvailableException::STATUS_SUCCESS;
}
foreach ($options as &$option) {
$option = self::setUserVars(OCP\User::getUser(), $option);
$option = self::substitutePlaceholdersInConfig($option);
if(!self::arePlaceholdersSubstituted($option)) {
\OC::$server->getLogger()->error(
'A placeholder was not substituted: {option} for mount type {class}',
[
'app' => 'files_external',
'option' => $option,
'class' => $class,
]
);
throw new StorageNotAvailableException(
'Mount configuration incomplete',
StorageNotAvailableException::STATUS_INCOMPLETE_CONF
);
}
}
if (class_exists($class)) {
try {
......@@ -254,6 +279,22 @@ class OC_Mount_Config {
return StorageNotAvailableException::STATUS_ERROR;
}
public static function arePlaceholdersSubstituted($option):bool {
$result = true;
if(is_array($option)) {
foreach ($option as $optionItem) {
if(is_array($optionItem)) {
$result = $result && self::arePlaceholdersSubstituted($option);
}
}
} else if (is_string($option)) {
if (strpos($option, '$') !== false) {
$result = false;
}
}
return $result;
}
/**
* Read the mount points in the config file into an array
*
......
<?php
/**
* @copyright Copyright (c) 2019 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\files_external\tests\Config;
use OCA\Files_External\Config\UserPlaceholderHandler;
use OCP\IUser;
use OCP\IUserSession;
class UserPlaceholderHandlerTest extends \Test\TestCase {
/** @var IUser|\PHPUnit_Framework_MockObject_MockObject */
protected $user;
/** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */
protected $session;
/** @var UserPlaceholderHandler */
protected $handler;
public function setUp() {
parent::setUp();
$this->user = $this->createMock(IUser::class);
$this->user->expects($this->any())
->method('getUid')
->willReturn('alice');
$this->session = $this->createMock(IUserSession::class);
$this->handler = new UserPlaceholderHandler($this->session);
}
protected function setUser() {
$this->session->expects($this->any())
->method('getUser')
->willReturn($this->user);
}
public function optionProvider() {
return [
['/foo/bar/$user/foobar', '/foo/bar/alice/foobar'],
[['/foo/bar/$user/foobar'], ['/foo/bar/alice/foobar']],
[['/FOO/BAR/$USER/FOOBAR'], ['/FOO/BAR/alice/FOOBAR']],
];
}
/**
* @dataProvider optionProvider
*/
public function testHandle($option, $expected) {
$this->setUser();
$this->assertSame($expected, $this->handler->handle($option));
}
/**
* @dataProvider optionProvider
*/
public function testHandleNoUser($option) {
$this->assertSame($option, $this->handler->handle($option));
}
}
......@@ -23,31 +23,27 @@
*/
namespace OCA\Files_External\Tests\Service;
use OCA\Files_External\Config\IConfigHandler;
use OCA\Files_External\Lib\Auth\AuthMechanism;
use OCA\Files_External\Lib\Backend\Backend;
use OCA\Files_External\Lib\Config\IAuthMechanismProvider;
use OCA\Files_External\Lib\Config\IBackendProvider;
use \OCA\Files_External\Service\BackendService;
use OCA\Files_External\Service\BackendService;
use OCP\IConfig;
use OCP\IL10N;
class BackendServiceTest extends \Test\TestCase {
/** @var \OCP\IConfig */
/** @var \OCP\IConfig|\PHPUnit_Framework_MockObject_MockObject */
protected $config;
/** @var \OCP\IL10N */
protected $l10n;
protected function setUp() {
$this->config = $this->createMock(IConfig::class);
$this->l10n = $this->createMock(IL10N::class);
}
/**
* @param string $class
*
* @return \OCA\Files_External\Lib\Backend\Backend
* @return \OCA\Files_External\Lib\Backend\Backend|\PHPUnit_Framework_MockObject_MockObject
*/
protected function getBackendMock($class) {
$backend = $this->getMockBuilder(Backend::class)
......@@ -61,7 +57,7 @@ class BackendServiceTest extends \Test\TestCase {
/**
* @param string $class
*
* @return \OCA\Files_External\Lib\Auth\AuthMechanism
* @return \OCA\Files_External\Lib\Auth\AuthMechanism|\PHPUnit_Framework_MockObject_MockObject
*/
protected function getAuthMechanismMock($class) {
$backend = $this->getMockBuilder(AuthMechanism::class)
......@@ -73,10 +69,11 @@ class BackendServiceTest extends \Test\TestCase {
}
public function testRegisterBackend() {
$service = new BackendService($this->config, $this->l10n);
$service = new BackendService($this->config);
$backend = $this->getBackendMock('\Foo\Bar');
/** @var \OCA\Files_External\Lib\Backend\Backend|\PHPUnit_Framework_MockObject_MockObject $backendAlias */
$backendAlias = $this->getMockBuilder(Backend::class)
->disableOriginalConstructor()
->getMock();
......@@ -100,11 +97,12 @@ class BackendServiceTest extends \Test\TestCase {
}
public function testBackendProvider() {
$service = new BackendService($this->config, $this->l10n);
$service = new BackendService($this->config);
$backend1 = $this->getBackendMock('\Foo\Bar');
$backend2 = $this->getBackendMock('\Bar\Foo');
/** @var IBackendProvider|\PHPUnit_Framework_MockObject_MockObject $providerMock */
$providerMock = $this->createMock(IBackendProvider::class);
$providerMock->expects($this->once())
->method('getBackends')
......@@ -118,11 +116,12 @@ class BackendServiceTest extends \Test\TestCase {
}
public function testAuthMechanismProvider() {
$service = new BackendService($this->config, $this->l10n);
$service = new BackendService($this->config);
$backend1 = $this->getAuthMechanismMock('\Foo\Bar');
$backend2 = $this->getAuthMechanismMock('\Bar\Foo');
/** @var IAuthMechanismProvider|\PHPUnit_Framework_MockObject_MockObject $providerMock */
$providerMock = $this->createMock(IAuthMechanismProvider::class);
$providerMock->expects($this->once())
->method('getAuthMechanisms')
......@@ -136,18 +135,20 @@ class BackendServiceTest extends \Test\TestCase {
}
public function testMultipleBackendProviders() {
$service = new BackendService($this->config, $this->l10n);
$service = new BackendService($this->config);
$backend1a = $this->getBackendMock('\Foo\Bar');
$backend1b = $this->getBackendMock('\Bar\Foo');
$backend2 = $this->getBackendMock('\Dead\Beef');
/** @var IBackendProvider|\PHPUnit_Framework_MockObject_MockObject $provider1Mock */
$provider1Mock = $this->createMock(IBackendProvider::class);
$provider1Mock->expects($this->once())
->method('getBackends')
->willReturn([$backend1a, $backend1b]);
$service->registerBackendProvider($provider1Mock);
/** @var IBackendProvider|\PHPUnit_Framework_MockObject_MockObject $provider2Mock */
$provider2Mock = $this->createMock(IBackendProvider::class);
$provider2Mock->expects($this->once())
->method('getBackends')
......@@ -169,7 +170,7 @@ class BackendServiceTest extends \Test\TestCase {
['files_external', 'user_mounting_backends', '', 'identifier:\User\Mount\Allowed,identifier_alias']
]));
$service = new BackendService($this->config, $this->l10n);
$service = new BackendService($this->config);
$backendAllowed = $this->getBackendMock('\User\Mount\Allowed');
$backendAllowed->expects($this->never())
......@@ -193,7 +194,7 @@ class BackendServiceTest extends \Test\TestCase {
}
public function testGetAvailableBackends() {
$service = new BackendService($this->config, $this->l10n);
$service = new BackendService($this->config);
$backendAvailable = $this->getBackendMock('\Backend\Available');
$backendAvailable->expects($this->once())
......@@ -216,5 +217,50 @@ class BackendServiceTest extends \Test\TestCase {
$this->assertArrayNotHasKey('identifier:\Backend\NotAvailable', $availableBackends);
}
public function invalidConfigPlaceholderProvider() {
return [
[['@user']],
[['$user']],
[['hællo']],
[['spa ce']],
[['yo\o']],
[['<script>…</script>']],
[['xxyoloxx', 'invÆlid']],
[['tautology', 'tautology']],
[['tautology2', 'TAUTOLOGY2']],
];
}
/**
* @dataProvider invalidConfigPlaceholderProvider
* @expectedException \RuntimeException
*/
public function testRegisterConfigHandlerInvalid(array $placeholders) {
$service = new BackendService($this->config);
$mock = $this->createMock(IConfigHandler::class);
$cb = function () use ($mock) { return $mock; };
foreach ($placeholders as $placeholder) {
$service->registerConfigHandler($placeholder, $cb);
}
}
public function testConfigHandlers() {
$service = new BackendService($this->config);
$mock = $this->createMock(IConfigHandler::class);
$mock->expects($this->exactly(3))
->method('handle');
$cb = function () use ($mock) { return $mock; };
$service->registerConfigHandler('one', $cb);
$service->registerConfigHandler('2', $cb);
$service->registerConfigHandler('Three', $cb);
/** @var IConfigHandler[] $handlers */
$handlers = $service->getConfigHandlers();
foreach ($handlers as $handler) {
$handler->handle('Something');
}
}
}
......@@ -34,6 +34,8 @@
return new OCA\User_LDAP\GroupPluginManager();
});
$app = new \OCA\User_LDAP\AppInfo\Application();
$helper = new \OCA\User_LDAP\Helper(\OC::$server->getConfig());
$configPrefixes = $helper->getServerConfigurationPrefixes(true);
if(count($configPrefixes) > 0) {
......@@ -67,6 +69,8 @@ if(count($configPrefixes) > 0) {
OC::$server->getEventDispatcher()->dispatch('OCA\\User_LDAP\\User\\User::postLDAPBackendAdded');
\OC::$server->getGroupManager()->addBackend($groupBackend);
$app->registerBackendDependents();
}
\OCP\Util::connectHook(
......
......@@ -23,12 +23,14 @@ return array(
'OCA\\User_LDAP\\ConnectionFactory' => $baseDir . '/../lib/ConnectionFactory.php',
'OCA\\User_LDAP\\Controller\\ConfigAPIController' => $baseDir . '/../lib/Controller/ConfigAPIController.php',
'OCA\\User_LDAP\\Controller\\RenewPasswordController' => $baseDir . '/../lib/Controller/RenewPasswordController.php',
'OCA\\User_LDAP\\Exceptions\\AttributeNotSet' => $baseDir . '/../lib/Exceptions/AttributeNotSet.php',
'OCA\\User_LDAP\\Exceptions\\ConstraintViolationException' => $baseDir . '/../lib/Exceptions/ConstraintViolationException.php',
'OCA\\User_LDAP\\Exceptions\\NotOnLDAP' => $baseDir . '/../lib/Exceptions/NotOnLDAP.php',
'OCA\\User_LDAP\\FilesystemHelper' => $baseDir . '/../lib/FilesystemHelper.php',
'OCA\\User_LDAP\\GroupPluginManager' => $baseDir . '/../lib/GroupPluginManager.php',
'OCA\\User_LDAP\\Group_LDAP' => $baseDir . '/../lib/Group_LDAP.php',
'OCA\\User_LDAP\\Group_Proxy' => $baseDir . '/../lib/Group_Proxy.php',
'OCA\\User_LDAP\\Handler\\ExtStorageConfigHandler' => $baseDir . '/../lib/Handler/ExtStorageConfigHandler.php',
'OCA\\User_LDAP\\Helper' => $baseDir . '/../lib/Helper.php',
'OCA\\User_LDAP\\IGroupLDAP' => $baseDir . '/../lib/IGroupLDAP.php',
'OCA\\User_LDAP\\ILDAPGroupPlugin' => $baseDir . '/../lib/ILDAPGroupPlugin.php',
......
......@@ -38,12 +38,14 @@ class ComposerStaticInitUser_LDAP
'OCA\\User_LDAP\\ConnectionFactory' => __DIR__ . '/..' . '/../lib/ConnectionFactory.php',
'OCA\\User_LDAP\\Controller\\ConfigAPIController' => __DIR__ . '/..' . '/../lib/Controller/ConfigAPIController.php',
'OCA\\User_LDAP\\Controller\\RenewPasswordController' => __DIR__ . '/..' . '/../lib/Controller/RenewPasswordController.php',
'OCA\\User_LDAP\\Exceptions\\AttributeNotSet' => __DIR__ . '/..' . '/../lib/Exceptions/AttributeNotSet.php',
'OCA\\User_LDAP\\Exceptions\\ConstraintViolationException' => __DIR__ . '/..' . '/../lib/Exceptions/ConstraintViolationException.php',
'OCA\\User_LDAP\\Exceptions\\NotOnLDAP' => __DIR__ . '/..' . '/../lib/Exceptions/NotOnLDAP.php',
'OCA\\User_LDAP\\FilesystemHelper' => __DIR__ . '/..' . '/../lib/FilesystemHelper.php',
'OCA\\User_LDAP\\GroupPluginManager' => __DIR__ . '/..' . '/../lib/GroupPluginManager.php',
'OCA\\User_LDAP\\Group_LDAP' => __DIR__ . '/..' . '/../lib/Group_LDAP.php',
'OCA\\User_LDAP\\Group_Proxy' => __DIR__ . '/..' . '/../lib/Group_Proxy.php',
'OCA\\User_LDAP\\Handler\\ExtStorageConfigHandler' => __DIR__ . '/..' . '/../lib/Handler/ExtStorageConfigHandler.php',
'OCA\\User_LDAP\\Helper' => __DIR__ . '/..' . '/../lib/Helper.php',
'OCA\\User_LDAP\\IGroupLDAP' => __DIR__ . '/..' . '/../lib/IGroupLDAP.php',
'OCA\\User_LDAP\\ILDAPGroupPlugin' => __DIR__ . '/..' . '/../lib/ILDAPGroupPlugin.php',
......
......@@ -120,7 +120,11 @@ OCA = OCA || {};
home_folder_naming_rule: {
$element: $('#home_folder_naming_rule'),
setMethod: 'setHomeFolderAttribute'
}
},
ldap_ext_storage_home_attribute: {
$element: $('#ldap_ext_storage_home_attribute'),
setMethod: 'setExternalStorageHomeAttribute'
},
};
this.setManagedItems(items);
},
......@@ -326,6 +330,15 @@ OCA = OCA || {};
this.setElementValue(this.managedItems.ldap_email_attr.$element, attribute);
},
/**
* sets the external storage home attribute
*
* @param {string} attribute
*/
setExternalStorageHomeAttribute: function(attribute) {
this.setElementValue(this.managedItems.ldap_ext_storage_home_attribute.$element, attribute);
},
/**
* sets the quota attribute
*
......
......@@ -23,7 +23,9 @@
namespace OCA\User_LDAP\AppInfo;
use OCA\Files_External\Service\BackendService;
use OCA\User_LDAP\Controller\RenewPasswordController;
use OCA\User_LDAP\Handler\ExtStorageConfigHandler;
use OCA\User_LDAP\ILDAPWrapper;
use OCA\User_LDAP\LDAP;
use OCP\AppFramework\App;
......@@ -57,4 +59,18 @@ class Application extends App {
return new LDAP();
});
}
public function registerBackendDependents() {
$container = $this->getContainer();
$container->getServer()->getEventDispatcher()->addListener(
'OCA\\Files_External::loadAdditionalBackends',
function() use ($container) {
$storagesBackendService = $container->query(BackendService::class);
$storagesBackendService->registerConfigHandler('home', function () use ($container) {
return $container->query(ExtStorageConfigHandler::class);
});
}
);
}
}
......@@ -106,6 +106,7 @@ class Configuration {
'turnOnPasswordChange' => false,
'ldapDynamicGroupMemberURL' => null,
'ldapDefaultPPolicyDN' => null,
'ldapExtStorageHomeAttribute' => null,
);
/**
......@@ -477,6 +478,7 @@ class Configuration {
'ldap_dynamic_group_member_url' => '',
'ldap_default_ppolicy_dn' => '',
'ldap_user_avatar_rule' => 'default',
'ldap_ext_storage_home_attribute' => '',
);
}
......@@ -537,6 +539,7 @@ class Configuration {
'ldap_experienced_admin' => 'ldapExperiencedAdmin',
'ldap_dynamic_group_member_url' => 'ldapDynamicGroupMemberURL',
'ldap_default_ppolicy_dn' => 'ldapDefaultPPolicyDN',
'ldap_ext_storage_home_attribute' => 'ldapExtStorageHomeAttribute',
'ldapIgnoreNamingRules' => 'ldapIgnoreNamingRules', // sysconfig
);
return $array;
......
......@@ -60,6 +60,8 @@ use OCP\ILogger;
* @property string ldapQuotaAttribute
* @property string ldapQuotaDefault
* @property string ldapEmailAttribute
* @property string ldapExtStorageHomeAttribute
* @property string homeFolderNamingRule
*/
class Connection extends LDAPUtility {
private $ldapConnectionRes = null;
......
<?php
/**
* @copyright Copyright (c) 2019 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\User_LDAP\Exceptions;
class AttributeNotSet extends \RuntimeException {}
<?php
/**
* @copyright Copyright (c) 2019 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\User_LDAP\Handler;
use OCA\Files_External\Config\IConfigHandler;
use OCA\Files_External\Config\SimpleSubstitutionTrait;
use OCA\User_LDAP\User_Proxy;
use OCP\IUserSession;
class ExtStorageConfigHandler implements IConfigHandler {
use SimpleSubstitutionTrait;
/** @var IUserSession */
private $session;
public function __construct(IUserSession $session) {
$this->placeholder = 'home';
$this->session = $session;
}
/**
* @param mixed $optionValue
* @return mixed the same type as $optionValue
* @since 16.0.0
* @throws \Exception
*/
public function handle($optionValue) {
$user = $this->session->getUser();
if($user === null) {
return $optionValue;
}
$backend = $user->getBackend();
if(!$backend instanceof User_Proxy) {
return $optionValue;
}
$access = $backend->getLDAPAccess($user->getUID());
if(!$access) {
return $optionValue;
}
$attribute = $access->connection->ldapExtStorageHomeAttribute;
if(empty($attribute)) {
return $optionValue;
}
$ldapUser = $access->userManager->get($user->getUID());
$extHome = $ldapUser->getExtStorageHome();
return $this->processInput($optionValue, $extHome);
}
}
......@@ -176,6 +176,7 @@ class Manager {
$this->access->getConnection()->ldapEmailAttribute,
$this->access->getConnection()->ldapUserDisplayName,
$this->access->getConnection()->ldapUserDisplayName2,
$this->access->getConnection()->ldapExtStorageHomeAttribute,
];
$homeRule = $this->access->getConnection()->homeFolderNamingRule;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment