From af0930fe59971ce610270a873a4c2d70012a8534 Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Wed, 11 May 2016 19:29:10 +0100 Subject: [PATCH 1/3] Introduce backend/auth mechanism providers Direct registration of backends/auth mechanisms is now deprecated --- .../lib/config/iauthmechanismprovider.php | 38 ++++++++++++++ .../lib/config/ibackendprovider.php | 38 ++++++++++++++ .../files_external/service/backendservice.php | 50 +++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 apps/files_external/lib/config/iauthmechanismprovider.php create mode 100644 apps/files_external/lib/config/ibackendprovider.php diff --git a/apps/files_external/lib/config/iauthmechanismprovider.php b/apps/files_external/lib/config/iauthmechanismprovider.php new file mode 100644 index 0000000000..035b8e891f --- /dev/null +++ b/apps/files_external/lib/config/iauthmechanismprovider.php @@ -0,0 +1,38 @@ + + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see + * + */ + +namespace OCA\Files_External\Lib\Config; + +use \OCA\Files_External\Lib\Auth\AuthMechanism; + +/** + * Provider of external storage auth mechanisms + * @since 9.1.0 + */ +interface IAuthMechanismProvider { + + /** + * @since 9.1.0 + * @return AuthMechanism[] + */ + public function getAuthMechanisms(); + +} diff --git a/apps/files_external/lib/config/ibackendprovider.php b/apps/files_external/lib/config/ibackendprovider.php new file mode 100644 index 0000000000..2335e7133a --- /dev/null +++ b/apps/files_external/lib/config/ibackendprovider.php @@ -0,0 +1,38 @@ + + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see + * + */ + +namespace OCA\Files_External\Lib\Config; + +use \OCA\Files_External\Lib\Backend\Backend; + +/** + * Provider of external storage backends + * @since 9.1.0 + */ +interface IBackendProvider { + + /** + * @since 9.1.0 + * @return Backend[] + */ + public function getBackends(); + +} diff --git a/apps/files_external/service/backendservice.php b/apps/files_external/service/backendservice.php index 9b23a441c7..c3dc4da017 100644 --- a/apps/files_external/service/backendservice.php +++ b/apps/files_external/service/backendservice.php @@ -26,6 +26,8 @@ use \OCP\IConfig; use \OCA\Files_External\Lib\Backend\Backend; use \OCA\Files_External\Lib\Auth\AuthMechanism; +use \OCA\Files_External\Lib\Config\IBackendProvider; +use \OCA\Files_External\Lib\Config\IAuthMechanismProvider; /** * Service class to manage backend definitions @@ -55,9 +57,15 @@ class BackendService { /** @var Backend[] */ private $backends = []; + /** @var IBackendProvider[] */ + private $backendProviders = []; + /** @var AuthMechanism[] */ private $authMechanisms = []; + /** @var IAuthMechanismProvider[] */ + private $authMechanismProviders = []; + /** * @param IConfig $config */ @@ -80,9 +88,44 @@ class BackendService { } } + /** + * Register a backend provider + * + * @since 9.1.0 + * @param IBackendProvider $provider + */ + public function registerBackendProvider(IBackendProvider $provider) { + $this->backendProviders[] = $provider; + } + + private function loadBackendProviders() { + foreach ($this->backendProviders as $provider) { + $this->registerBackends($provider->getBackends()); + } + $this->backendProviders = []; + } + + /** + * Register an auth mechanism provider + * + * @since 9.1.0 + * @param IAuthMechanismProvider $provider + */ + public function registerAuthMechanismProvider(IAuthMechanismProvider $provider) { + $this->authMechanismProviders[] = $provider; + } + + private function loadAuthMechanismProviders() { + foreach ($this->authMechanismProviders as $provider) { + $this->registerAuthMechanisms($provider->getAuthMechanisms()); + } + $this->authMechanismProviders = []; + } + /** * Register a backend * + * @deprecated 9.1.0 use registerBackendProvider() * @param Backend $backend */ public function registerBackend(Backend $backend) { @@ -95,6 +138,7 @@ class BackendService { } /** + * @deprecated 9.1.0 use registerBackendProvider() * @param Backend[] $backends */ public function registerBackends(array $backends) { @@ -105,6 +149,7 @@ class BackendService { /** * Register an authentication mechanism * + * @deprecated 9.1.0 use registerAuthMechanismProvider() * @param AuthMechanism $authMech */ public function registerAuthMechanism(AuthMechanism $authMech) { @@ -117,6 +162,7 @@ class BackendService { } /** + * @deprecated 9.1.0 use registerAuthMechanismProvider() * @param AuthMechanism[] $mechanisms */ public function registerAuthMechanisms(array $mechanisms) { @@ -131,6 +177,7 @@ class BackendService { * @return Backend[] */ public function getBackends() { + $this->loadBackendProviders(); // only return real identifiers, no aliases $backends = []; foreach ($this->backends as $backend) { @@ -155,6 +202,7 @@ class BackendService { * @return Backend|null */ public function getBackend($identifier) { + $this->loadBackendProviders(); if (isset($this->backends[$identifier])) { return $this->backends[$identifier]; } @@ -167,6 +215,7 @@ class BackendService { * @return AuthMechanism[] */ public function getAuthMechanisms() { + $this->loadAuthMechanismProviders(); // only return real identifiers, no aliases $mechanisms = []; foreach ($this->authMechanisms as $mechanism) { @@ -192,6 +241,7 @@ class BackendService { * @return AuthMechanism|null */ public function getAuthMechanism($identifier) { + $this->loadAuthMechanismProviders(); if (isset($this->authMechanisms[$identifier])) { return $this->authMechanisms[$identifier]; } From 711bc7469ae3261e3813a82e3807691ec3904098 Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Wed, 11 May 2016 19:34:57 +0100 Subject: [PATCH 2/3] Use backend/auth mechanism providers in files_external --- apps/files_external/appinfo/application.php | 38 ++++++++++++--------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/apps/files_external/appinfo/application.php b/apps/files_external/appinfo/application.php index cdc58aed7e..5d490c6091 100644 --- a/apps/files_external/appinfo/application.php +++ b/apps/files_external/appinfo/application.php @@ -30,20 +30,26 @@ use \OCP\AppFramework\App; use OCP\AppFramework\IAppContainer; use \OCP\IContainer; use \OCA\Files_External\Service\BackendService; +use \OCA\Files_External\Lib\Config\IBackendProvider; +use \OCA\Files_External\Lib\Config\IAuthMechanismProvider; /** * @package OCA\Files_External\Appinfo */ -class Application extends App { +class Application extends App implements IBackendProvider, IAuthMechanismProvider { + public function __construct(array $urlParams = array()) { parent::__construct('files_external', $urlParams); - $this->getContainer()->registerService('OCP\Files\Config\IUserMountCache', function (IAppContainer $c) { + $container = $this->getContainer(); + + $container->registerService('OCP\Files\Config\IUserMountCache', function (IAppContainer $c) { return $c->getServer()->query('UserMountCache'); }); - $this->loadBackends(); - $this->loadAuthMechanisms(); + $backendService = $container->query('OCA\\Files_External\\Service\\BackendService'); + $backendService->registerBackendProvider($this); + $backendService->registerAuthMechanismProvider($this); // app developers: do NOT depend on this! it will disappear with oC 9.0! \OC::$server->getEventDispatcher()->dispatch( @@ -63,13 +69,12 @@ class Application extends App { } /** - * Load storage backends provided by this app + * @{inheritdoc} */ - protected function loadBackends() { + public function getBackends() { $container = $this->getContainer(); - $service = $container->query('OCA\\Files_External\\Service\\BackendService'); - $service->registerBackends([ + $backends = [ $container->query('OCA\Files_External\Lib\Backend\Local'), $container->query('OCA\Files_External\Lib\Backend\FTP'), $container->query('OCA\Files_External\Lib\Backend\DAV'), @@ -80,24 +85,25 @@ class Application extends App { $container->query('OCA\Files_External\Lib\Backend\Google'), $container->query('OCA\Files_External\Lib\Backend\Swift'), $container->query('OCA\Files_External\Lib\Backend\SFTP_Key'), - ]); + ]; if (!\OC_Util::runningOnWindows()) { - $service->registerBackends([ + $backends += [ $container->query('OCA\Files_External\Lib\Backend\SMB'), $container->query('OCA\Files_External\Lib\Backend\SMB_OC'), - ]); + ]; } + + return $backends; } /** - * Load authentication mechanisms provided by this app + * @{inheritdoc} */ - protected function loadAuthMechanisms() { + public function getAuthMechanisms() { $container = $this->getContainer(); - $service = $container->query('OCA\\Files_External\\Service\\BackendService'); - $service->registerAuthMechanisms([ + return [ // AuthMechanism::SCHEME_NULL mechanism $container->query('OCA\Files_External\Lib\Auth\NullMechanism'), @@ -123,7 +129,7 @@ class Application extends App { // Specialized mechanisms $container->query('OCA\Files_External\Lib\Auth\AmazonS3\AccessKey'), - ]); + ]; } } From 8f58b89c3f01c31cc7b6c59830741af048559e2e Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Wed, 11 May 2016 21:24:53 +0100 Subject: [PATCH 3/3] Add tests for backend/auth mechanism providers --- .../tests/service/backendservicetest.php | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/apps/files_external/tests/service/backendservicetest.php b/apps/files_external/tests/service/backendservicetest.php index 8621c98b9b..ba9a1f533f 100644 --- a/apps/files_external/tests/service/backendservicetest.php +++ b/apps/files_external/tests/service/backendservicetest.php @@ -49,6 +49,20 @@ class BackendServiceTest extends \Test\TestCase { return $backend; } + /** + * @param string $class + * + * @return \OCA\Files_External\Lib\Auth\AuthMechanism + */ + protected function getAuthMechanismMock($class) { + $backend = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism') + ->disableOriginalConstructor() + ->getMock(); + $backend->method('getIdentifier')->will($this->returnValue('identifier:'.$class)); + $backend->method('getIdentifierAliases')->will($this->returnValue(['identifier:'.$class])); + return $backend; + } + public function testRegisterBackend() { $service = new BackendService($this->config, $this->l10n); @@ -76,6 +90,68 @@ class BackendServiceTest extends \Test\TestCase { $this->assertArrayNotHasKey('identifier_alias', $backends); } + public function testBackendProvider() { + $service = new BackendService($this->config, $this->l10n); + + $backend1 = $this->getBackendMock('\Foo\Bar'); + $backend2 = $this->getBackendMock('\Bar\Foo'); + + $providerMock = $this->getMock('\OCA\Files_External\Lib\Config\IBackendProvider'); + $providerMock->expects($this->once()) + ->method('getBackends') + ->willReturn([$backend1, $backend2]); + $service->registerBackendProvider($providerMock); + + $this->assertEquals($backend1, $service->getBackend('identifier:\Foo\Bar')); + $this->assertEquals($backend2, $service->getBackend('identifier:\Bar\Foo')); + + $this->assertCount(2, $service->getBackends()); + } + + public function testAuthMechanismProvider() { + $service = new BackendService($this->config, $this->l10n); + + $backend1 = $this->getAuthMechanismMock('\Foo\Bar'); + $backend2 = $this->getAuthMechanismMock('\Bar\Foo'); + + $providerMock = $this->getMock('\OCA\Files_External\Lib\Config\IAuthMechanismProvider'); + $providerMock->expects($this->once()) + ->method('getAuthMechanisms') + ->willReturn([$backend1, $backend2]); + $service->registerAuthMechanismProvider($providerMock); + + $this->assertEquals($backend1, $service->getAuthMechanism('identifier:\Foo\Bar')); + $this->assertEquals($backend2, $service->getAuthMechanism('identifier:\Bar\Foo')); + + $this->assertCount(2, $service->getAuthMechanisms()); + } + + public function testMultipleBackendProviders() { + $service = new BackendService($this->config, $this->l10n); + + $backend1a = $this->getBackendMock('\Foo\Bar'); + $backend1b = $this->getBackendMock('\Bar\Foo'); + + $backend2 = $this->getBackendMock('\Dead\Beef'); + + $provider1Mock = $this->getMock('\OCA\Files_External\Lib\Config\IBackendProvider'); + $provider1Mock->expects($this->once()) + ->method('getBackends') + ->willReturn([$backend1a, $backend1b]); + $service->registerBackendProvider($provider1Mock); + $provider2Mock = $this->getMock('\OCA\Files_External\Lib\Config\IBackendProvider'); + $provider2Mock->expects($this->once()) + ->method('getBackends') + ->willReturn([$backend2]); + $service->registerBackendProvider($provider2Mock); + + $this->assertEquals($backend1a, $service->getBackend('identifier:\Foo\Bar')); + $this->assertEquals($backend1b, $service->getBackend('identifier:\Bar\Foo')); + $this->assertEquals($backend2, $service->getBackend('identifier:\Dead\Beef')); + + $this->assertCount(3, $service->getBackends()); + } + public function testUserMountingBackends() { $this->config->expects($this->exactly(2)) ->method('getAppValue')