summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/files_external/appinfo/application.php14
-rw-r--r--apps/files_external/controller/globalstoragescontroller.php6
-rw-r--r--apps/files_external/controller/storagescontroller.php20
-rw-r--r--apps/files_external/controller/userstoragescontroller.php6
-rw-r--r--apps/files_external/js/settings.js107
-rw-r--r--apps/files_external/lib/auth/authmechanism.php120
-rw-r--r--apps/files_external/lib/auth/nullmechanism.php40
-rw-r--r--apps/files_external/lib/backend/backend.php76
-rw-r--r--apps/files_external/lib/config.php16
-rw-r--r--apps/files_external/lib/config/configadapter.php3
-rw-r--r--apps/files_external/lib/storageconfig.php23
-rw-r--r--apps/files_external/lib/storagemodifiertrait.php10
-rw-r--r--apps/files_external/lib/visibilitytrait.php7
-rw-r--r--apps/files_external/personal.php1
-rw-r--r--apps/files_external/service/backendservice.php91
-rw-r--r--apps/files_external/service/storagesservice.php23
-rw-r--r--apps/files_external/settings.php1
-rw-r--r--apps/files_external/templates/settings.php127
-rw-r--r--apps/files_external/tests/controller/storagescontrollertest.php38
-rw-r--r--apps/files_external/tests/controller/userstoragescontrollertest.php4
-rw-r--r--apps/files_external/tests/js/settingsSpec.js22
-rw-r--r--apps/files_external/tests/service/globalstoragesservicetest.php13
-rw-r--r--apps/files_external/tests/service/storagesservicetest.php44
-rw-r--r--apps/files_external/tests/service/userstoragesservicetest.php6
-rw-r--r--apps/files_external/tests/storageconfigtest.php8
25 files changed, 740 insertions, 86 deletions
diff --git a/apps/files_external/appinfo/application.php b/apps/files_external/appinfo/application.php
index b8b1fdaa27e..19da1f724ba 100644
--- a/apps/files_external/appinfo/application.php
+++ b/apps/files_external/appinfo/application.php
@@ -51,6 +51,7 @@ class Application extends App {
});
$this->loadBackends();
+ $this->loadAuthMechanisms();
}
/**
@@ -61,4 +62,17 @@ class Application extends App {
$service = $container->query('OCA\\Files_External\\Service\\BackendService');
}
+ /**
+ * Load authentication mechanisms provided by this app
+ */
+ protected function loadAuthMechanisms() {
+ $container = $this->getContainer();
+ $service = $container->query('OCA\\Files_External\\Service\\BackendService');
+
+ $service->registerAuthMechanisms([
+ // AuthMechanism::SCHEME_NULL mechanism
+ $container->query('OCA\Files_External\Lib\Auth\NullMechanism'),
+ ]);
+ }
+
}
diff --git a/apps/files_external/controller/globalstoragescontroller.php b/apps/files_external/controller/globalstoragescontroller.php
index 11f7fd6afa5..2c7b6af4192 100644
--- a/apps/files_external/controller/globalstoragescontroller.php
+++ b/apps/files_external/controller/globalstoragescontroller.php
@@ -64,6 +64,7 @@ class GlobalStoragesController extends StoragesController {
*
* @param string $mountPoint storage mount point
* @param string $backendClass backend class name
+ * @param string $authMechanismClass authentication mechanism class
* @param array $backendOptions backend-specific options
* @param array $mountOptions mount-specific options
* @param array $applicableUsers users for which to mount the storage
@@ -75,6 +76,7 @@ class GlobalStoragesController extends StoragesController {
public function create(
$mountPoint,
$backendClass,
+ $authMechanismClass,
$backendOptions,
$mountOptions,
$applicableUsers,
@@ -84,6 +86,7 @@ class GlobalStoragesController extends StoragesController {
$newStorage = $this->createStorage(
$mountPoint,
$backendClass,
+ $authMechanismClass,
$backendOptions,
$mountOptions,
$applicableUsers,
@@ -115,6 +118,7 @@ class GlobalStoragesController extends StoragesController {
* @param int $id storage id
* @param string $mountPoint storage mount point
* @param string $backendClass backend class name
+ * @param string $authMechanismClass authentication mechansim class
* @param array $backendOptions backend-specific options
* @param array $mountOptions mount-specific options
* @param array $applicableUsers users for which to mount the storage
@@ -127,6 +131,7 @@ class GlobalStoragesController extends StoragesController {
$id,
$mountPoint,
$backendClass,
+ $authMechanismClass,
$backendOptions,
$mountOptions,
$applicableUsers,
@@ -136,6 +141,7 @@ class GlobalStoragesController extends StoragesController {
$storage = $this->createStorage(
$mountPoint,
$backendClass,
+ $authMechanismClass,
$backendOptions,
$mountOptions,
$applicableUsers,
diff --git a/apps/files_external/controller/storagescontroller.php b/apps/files_external/controller/storagescontroller.php
index c653b51bf89..5f3779dc8b9 100644
--- a/apps/files_external/controller/storagescontroller.php
+++ b/apps/files_external/controller/storagescontroller.php
@@ -33,6 +33,7 @@ use \OCA\Files_external\Service\StoragesService;
use \OCA\Files_external\NotFoundException;
use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_External\Lib\Backend\Backend;
+use \OCA\Files_External\Lib\Auth\AuthMechanism;
/**
* Base class for storages controllers
@@ -77,6 +78,7 @@ abstract class StoragesController extends Controller {
*
* @param string $mountPoint storage mount point
* @param string $backendClass backend class name
+ * @param string $authMechanismClass authentication mechanism class name
* @param array $backendOptions backend-specific options
* @param array|null $mountOptions mount-specific options
* @param array|null $applicableUsers users for which to mount the storage
@@ -88,6 +90,7 @@ abstract class StoragesController extends Controller {
protected function createStorage(
$mountPoint,
$backendClass,
+ $authMechanismClass,
$backendOptions,
$mountOptions = null,
$applicableUsers = null,
@@ -98,6 +101,7 @@ abstract class StoragesController extends Controller {
return $this->service->createStorage(
$mountPoint,
$backendClass,
+ $authMechanismClass,
$backendOptions,
$mountOptions,
$applicableUsers,
@@ -107,7 +111,7 @@ abstract class StoragesController extends Controller {
} catch (\InvalidArgumentException $e) {
return new DataResponse(
[
- 'message' => (string)$this->l10n->t('Invalid backend class "%s"', [$backendClass])
+ 'message' => (string)$this->l10n->t('Invalid backend or authentication mechanism class')
],
Http::STATUS_UNPROCESSABLE_ENTITY
);
@@ -134,6 +138,8 @@ abstract class StoragesController extends Controller {
/** @var Backend */
$backend = $storage->getBackend();
+ /** @var AuthMechanism */
+ $authMechanism = $storage->getAuthMechanism();
if (!$backend || $backend->checkDependencies()) {
// invalid backend
return new DataResponse(
@@ -154,6 +160,15 @@ abstract class StoragesController extends Controller {
Http::STATUS_UNPROCESSABLE_ENTITY
);
}
+ if (!$authMechanism->validateStorage($storage)) {
+ // unsatisfied parameters
+ return new DataResponse(
+ [
+ 'message' => (string)$this->l10n->t('Unsatisfied authentication mechanism parameters')
+ ],
+ Http::STATUS_UNPROCESSABLE_ENTITY
+ );
+ }
return null;
}
@@ -167,6 +182,9 @@ abstract class StoragesController extends Controller {
* @param StorageConfig $storage storage configuration
*/
protected function updateStorageStatus(StorageConfig &$storage) {
+ /** @var AuthMechanism */
+ $authMechanism = $storage->getAuthMechanism();
+ $authMechanism->manipulateStorageConfig($storage);
/** @var Backend */
$backend = $storage->getBackend();
$backend->manipulateStorageConfig($storage);
diff --git a/apps/files_external/controller/userstoragescontroller.php b/apps/files_external/controller/userstoragescontroller.php
index 5a5bff7ba70..e72b51ff653 100644
--- a/apps/files_external/controller/userstoragescontroller.php
+++ b/apps/files_external/controller/userstoragescontroller.php
@@ -109,6 +109,7 @@ class UserStoragesController extends StoragesController {
*
* @param string $mountPoint storage mount point
* @param string $backendClass backend class name
+ * @param string $authMechanismClass authentication mechanism class
* @param array $backendOptions backend-specific options
* @param array $mountOptions backend-specific mount options
*
@@ -119,12 +120,14 @@ class UserStoragesController extends StoragesController {
public function create(
$mountPoint,
$backendClass,
+ $authMechanismClass,
$backendOptions,
$mountOptions
) {
$newStorage = $this->createStorage(
$mountPoint,
$backendClass,
+ $authMechanismClass,
$backendOptions,
$mountOptions
);
@@ -152,6 +155,7 @@ class UserStoragesController extends StoragesController {
* @param int $id storage id
* @param string $mountPoint storage mount point
* @param string $backendClass backend class name
+ * @param string $authMechanismClass authentication mechanism class
* @param array $backendOptions backend-specific options
* @param array $mountOptions backend-specific mount options
*
@@ -163,12 +167,14 @@ class UserStoragesController extends StoragesController {
$id,
$mountPoint,
$backendClass,
+ $authMechanismClass,
$backendOptions,
$mountOptions
) {
$storage = $this->createStorage(
$mountPoint,
$backendClass,
+ $authMechanismClass,
$backendOptions,
$mountOptions
);
diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js
index 287b4664541..7240c246ea7 100644
--- a/apps/files_external/js/settings.js
+++ b/apps/files_external/js/settings.js
@@ -221,6 +221,13 @@ StorageConfig.prototype = {
backendClass: null,
/**
+ * Authentication mechanism class name
+ *
+ * @type string
+ */
+ authMechanismClass: null,
+
+ /**
* Backend-specific configuration
*
* @type Object.<string,object>
@@ -273,6 +280,7 @@ StorageConfig.prototype = {
var data = {
mountPoint: this.mountPoint,
backendClass: this.backendClass,
+ authMechanismClass: this.authMechanismClass,
backendOptions: this.backendOptions
};
if (this.id) {
@@ -579,6 +587,13 @@ MountConfigListView.prototype = {
*/
_allBackends: null,
+ /**
+ * List of all supported authentication mechanisms
+ *
+ * @type Object.<string,Object>
+ */
+ _allAuthMechanisms: null,
+
_encryptionEnabled: false,
/**
@@ -605,6 +620,7 @@ MountConfigListView.prototype = {
// read the backend config that was carefully crammed
// into the data-configurations attribute of the select
this._allBackends = this.$el.find('.selectBackend').data('configurations');
+ this._allAuthMechanisms = this.$el.find('#addMountPoint .authentication').data('mechanisms');
//initialize hidden input field with list of users and groups
this.$el.find('tr:not(#addMountPoint)').each(function(i,tr) {
@@ -660,6 +676,7 @@ MountConfigListView.prototype = {
});
this.$el.on('change', '.selectBackend', _.bind(this._onSelectBackend, this));
+ this.$el.on('change', '.selectAuthMechanism', _.bind(this._onSelectAuthMechanism, this));
},
_onChange: function(event) {
@@ -694,40 +711,30 @@ MountConfigListView.prototype = {
}
$tr.addClass(backendClass);
$tr.find('.backend').data('class', backendClass);
- var configurations = this._allBackends;
- var $td = $tr.find('td.configuration');
- $.each(configurations, function(backend, parameters) {
- if (backend === backendClass) {
- $.each(parameters['configuration'], function(parameter, placeholder) {
- var is_optional = false;
- if (placeholder.indexOf('&') === 0) {
- is_optional = true;
- placeholder = placeholder.substring(1);
- }
- var newElement;
- if (placeholder.indexOf('*') === 0) {
- var class_string = is_optional ? ' optional' : '';
- newElement = $('<input type="password" class="added' + class_string + '" data-parameter="'+parameter+'" placeholder="'+placeholder.substring(1)+'" />');
- } else if (placeholder.indexOf('!') === 0) {
- newElement = $('<label><input type="checkbox" class="added" data-parameter="'+parameter+'" />'+placeholder.substring(1)+'</label>');
- } else if (placeholder.indexOf('#') === 0) {
- newElement = $('<input type="hidden" class="added" data-parameter="'+parameter+'" />');
- } else {
- var class_string = is_optional ? ' optional' : '';
- newElement = $('<input type="text" class="added' + class_string + '" data-parameter="'+parameter+'" placeholder="'+placeholder+'" />');
- }
- highlightInput(newElement);
- $td.append(newElement);
- });
- var priorityEl = $('<input type="hidden" class="priority" value="' + parameters['priority'] + '" />');
- $tr.append(priorityEl);
- if (parameters['custom'] && $el.find('tbody tr.'+backendClass.replace(/\\/g, '\\\\')).length === 1) {
- OC.addScript('files_external', parameters['custom']);
- }
- $td.children().not('[type=hidden]').first().focus();
- return false;
+ var backendConfiguration = this._allBackends[backendClass];
+
+ var selectAuthMechanism = $('<select class="selectAuthMechanism"></select>');
+ $.each(this._allAuthMechanisms, function(authClass, authMechanism) {
+ if (backendConfiguration['authSchemes'][authMechanism['scheme']]) {
+ selectAuthMechanism.append(
+ $('<option value="'+authClass+'" data-scheme="'+authMechanism['scheme']+'">'+authMechanism['name']+'</option>')
+ );
}
});
+ $tr.find('td.authentication').append(selectAuthMechanism);
+
+ var $td = $tr.find('td.configuration');
+ $.each(backendConfiguration['configuration'], _.partial(this.writeParameterInput, $td));
+
+ selectAuthMechanism.trigger('change'); // generate configuration parameters for auth mechanism
+
+ var priorityEl = $('<input type="hidden" class="priority" value="' + backendConfiguration['priority'] + '" />');
+ $tr.append(priorityEl);
+ if (backendConfiguration['custom'] && $el.find('tbody tr.'+backendClass.replace(/\\/g, '\\\\')).length === 1) {
+ OC.addScript('files_external', backendConfiguration['custom']);
+ }
+ $td.children().not('[type=hidden]').first().focus();
+
$tr.find('td').last().attr('class', 'remove');
$tr.find('td.mountOptionsToggle').removeClass('hidden');
$tr.find('td').last().removeAttr('style');
@@ -736,6 +743,41 @@ MountConfigListView.prototype = {
addSelect2($tr.find('.applicableUsers'), this._userListLimit);
},
+ _onSelectAuthMechanism: function(event) {
+ var $target = $(event.target);
+ var $tr = $target.closest('tr');
+
+ var authMechanismClass = $target.val();
+ var authMechanism = this._allAuthMechanisms[authMechanismClass];
+ var $td = $tr.find('td.configuration');
+ $td.find('.auth-param').remove();
+
+ $.each(authMechanism['configuration'], _.partial(
+ this.writeParameterInput, $td, _, _, ['auth-param']
+ ));
+ },
+
+ writeParameterInput: function($td, parameter, placeholder, classes) {
+ classes = $.isArray(classes) ? classes : [];
+ classes.push('added');
+ if (placeholder.indexOf('&') === 0) {
+ classes.push('optional');
+ placeholder = placeholder.substring(1);
+ }
+ var newElement;
+ if (placeholder.indexOf('*') === 0) {
+ newElement = $('<input type="password" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" placeholder="'+placeholder.substring(1)+'" />');
+ } else if (placeholder.indexOf('!') === 0) {
+ newElement = $('<label><input type="checkbox" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" />'+placeholder.substring(1)+'</label>');
+ } else if (placeholder.indexOf('#') === 0) {
+ newElement = $('<input type="hidden" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" />');
+ } else {
+ newElement = $('<input type="text" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" placeholder="'+placeholder+'" />');
+ }
+ highlightInput(newElement);
+ $td.append(newElement);
+ },
+
/**
* Gets the storage model from the given row
*
@@ -751,6 +793,7 @@ MountConfigListView.prototype = {
var storage = new this._storageConfigClass(storageId);
storage.mountPoint = $tr.find('.mountPoint input').val();
storage.backendClass = $tr.find('.backend').data('class');
+ storage.authMechanismClass = $tr.find('.selectAuthMechanism').val();
var classOptions = {};
var configuration = $tr.find('.configuration input');
diff --git a/apps/files_external/lib/auth/authmechanism.php b/apps/files_external/lib/auth/authmechanism.php
new file mode 100644
index 00000000000..7da57662db8
--- /dev/null
+++ b/apps/files_external/lib/auth/authmechanism.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib\Auth;
+
+use \OCA\Files_External\Lib\StorageConfig;
+use \OCA\Files_External\Lib\VisibilityTrait;
+use \OCA\Files_External\Lib\FrontendDefinitionTrait;
+use \OCA\Files_External\Lib\StorageModifierTrait;
+
+/**
+ * Authentication mechanism
+ *
+ * An authentication mechanism can have services injected during construction,
+ * such as \OCP\IDB for database operations. This allows an authentication
+ * mechanism to perform advanced operations based on provided information.
+ *
+ * An authenication scheme defines the parameter interface, common to the
+ * storage implementation, the backend and the authentication mechanism.
+ * A storage implementation expects parameters according to the authentication
+ * scheme, which are provided from the authentication mechanism.
+ *
+ * This class uses the following traits:
+ * - VisibilityTrait
+ * Restrict usage to admin-only/none
+ * - FrontendDefinitionTrait
+ * Specify configuration parameters and other definitions
+ * - StorageModifierTrait
+ * Object can affect storage mounting
+ */
+class AuthMechanism implements \JsonSerializable {
+
+ /** Standard authentication schemes */
+ const SCHEME_NULL = 'null';
+ const SCHEME_PASSWORD = 'password';
+ const SCHEME_OAUTH1 = 'oauth1';
+ const SCHEME_OAUTH2 = 'oauth2';
+ const SCHEME_PUBLICKEY = 'publickey';
+ const SCHEME_OPENSTACK = 'openstack';
+
+ use VisibilityTrait;
+ use FrontendDefinitionTrait;
+ use StorageModifierTrait;
+
+ /** @var string */
+ protected $scheme;
+
+ /**
+ * @return string
+ */
+ public function getClass() {
+ return '\\'.get_class($this);
+ }
+
+ /**
+ * Get the authentication scheme implemented
+ * See self::SCHEME_* constants
+ *
+ * @return string
+ */
+ public function getScheme() {
+ return $this->scheme;
+ }
+
+ /**
+ * @param string $scheme
+ * @return self
+ */
+ public function setScheme($scheme) {
+ $this->scheme = $scheme;
+ return $this;
+ }
+
+ /**
+ * Serialize into JSON for client-side JS
+ *
+ * @return array
+ */
+ public function jsonSerialize() {
+ $data = $this->jsonSerializeDefinition();
+ $data['scheme'] = $this->getScheme();
+
+ return $data;
+ }
+
+ /**
+ * Check if parameters are satisfied in a StorageConfig
+ *
+ * @param StorageConfig $storage
+ * @return bool
+ */
+ public function validateStorage(StorageConfig $storage) {
+ // does the backend actually support this scheme
+ $supportedSchemes = $storage->getBackend()->getAuthSchemes();
+ if (!isset($supportedSchemes[$this->getScheme()])) {
+ return false;
+ }
+
+ return $this->validateStorageDefinition($storage);
+ }
+
+}
diff --git a/apps/files_external/lib/auth/nullmechanism.php b/apps/files_external/lib/auth/nullmechanism.php
new file mode 100644
index 00000000000..396649d7319
--- /dev/null
+++ b/apps/files_external/lib/auth/nullmechanism.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib\Auth;
+
+use \OCP\IL10N;
+use \OCA\Files_External\Lib\Auth\AuthMechanism;
+use \OCA\Files_external\Lib\StorageConfig;
+
+/**
+ * Null authentication mechanism
+ */
+class NullMechanism extends AuthMechanism {
+
+ public function __construct(IL10N $l) {
+ $this
+ ->setScheme(self::SCHEME_NULL)
+ ->setText($l->t('None'))
+ ;
+ }
+
+}
diff --git a/apps/files_external/lib/backend/backend.php b/apps/files_external/lib/backend/backend.php
index e7cd27a1d6c..634bcb7bfbd 100644
--- a/apps/files_external/lib/backend/backend.php
+++ b/apps/files_external/lib/backend/backend.php
@@ -27,9 +27,31 @@ use \OCA\Files_External\Lib\FrontendDefinitionTrait;
use \OCA\Files_External\Lib\PriorityTrait;
use \OCA\Files_External\Lib\DependencyTrait;
use \OCA\Files_External\Lib\StorageModifierTrait;
+use \OCA\Files_External\Lib\Auth\AuthMechanism;
/**
* Storage backend
+ *
+ * A backend can have services injected during construction,
+ * such as \OCP\IDB for database operations. This allows a backend
+ * to perform advanced operations based on provided information.
+ *
+ * An authenication scheme defines the parameter interface, common to the
+ * storage implementation, the backend and the authentication mechanism.
+ * A storage implementation expects parameters according to the authentication
+ * scheme, which are provided from the authentication mechanism.
+ *
+ * This class uses the following traits:
+ * - VisibilityTrait
+ * Restrict usage to admin-only/none
+ * - FrontendDefinitionTrait
+ * Specify configuration parameters and other definitions
+ * - PriorityTrait
+ * Allow objects to prioritize over others with the same mountpoint
+ * - DependencyTrait
+ * The object requires certain dependencies to be met
+ * - StorageModifierTrait
+ * Object can affect storage mounting
*/
class Backend implements \JsonSerializable {
@@ -42,6 +64,12 @@ class Backend implements \JsonSerializable {
/** @var string storage class */
private $storageClass;
+ /** @var array 'scheme' => true, supported authentication schemes */
+ private $authSchemes = [];
+
+ /** @var AuthMechanism|callable authentication mechanism fallback */
+ private $legacyAuthMechanism;
+
/**
* @return string
*/
@@ -67,6 +95,53 @@ class Backend implements \JsonSerializable {
}
/**
+ * @return array
+ */
+ public function getAuthSchemes() {
+ if (empty($this->authSchemes)) {
+ return [AuthMechanism::SCHEME_NULL => true];
+ }
+ return $this->authSchemes;
+ }
+
+ /**
+ * @param string $scheme
+ * @return self
+ */
+ public function addAuthScheme($scheme) {
+ $this->authSchemes[$scheme] = true;
+ return $this;
+ }
+
+ /**
+ * @param array $parameters storage parameters, for dynamic mechanism selection
+ * @return AuthMechanism
+ */
+ public function getLegacyAuthMechanism(array $parameters = []) {
+ if (is_callable($this->legacyAuthMechanism)) {
+ return call_user_func($this->legacyAuthMechanism, $parameters);
+ }
+ return $this->legacyAuthMechanism;
+ }
+
+ /**
+ * @param AuthMechanism $authMechanism
+ * @return self
+ */
+ public function setLegacyAuthMechanism(AuthMechanism $authMechanism) {
+ $this->legacyAuthMechanism = $authMechanism;
+ return $this;
+ }
+
+ /**
+ * @param callable $callback dynamic auth mechanism selection
+ * @return self
+ */
+ public function setLegacyAuthMechanismCallback(callable $callback) {
+ $this->legacyAuthMechanism = $callback;
+ }
+
+ /**
* Serialize into JSON for client-side JS
*
* @return array
@@ -76,6 +151,7 @@ class Backend implements \JsonSerializable {
$data['backend'] = $data['name']; // legacy compat
$data['priority'] = $this->getPriority();
+ $data['authSchemes'] = $this->getAuthSchemes();
return $data;
}
diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php
index 11dec94621a..e720677480f 100644
--- a/apps/files_external/lib/config.php
+++ b/apps/files_external/lib/config.php
@@ -123,7 +123,9 @@ class OC_Mount_Config {
if (!isset($options['priority'])) {
$options['priority'] = $backend->getPriority();
}
-
+ if (!isset($options['authMechanism'])) {
+ $options['authMechanism'] = $backend->getLegacyAuthMechanism($options['options'])->getClass();
+ }
// Override if priority greater
if ((!isset($mountPoints[$mountPoint]))
@@ -149,6 +151,9 @@ class OC_Mount_Config {
if (!isset($options['priority'])) {
$options['priority'] = $backend->getPriority();
}
+ if (!isset($options['authMechanism'])) {
+ $options['authMechanism'] = $backend->getLegacyAuthMechanism($options['options'])->getClass();
+ }
// Override if priority greater
if ((!isset($mountPoints[$mountPoint]))
@@ -175,6 +180,9 @@ class OC_Mount_Config {
if (!isset($options['priority'])) {
$options['priority'] = $backend->getPriority();
}
+ if (!isset($options['authMechanism'])) {
+ $options['authMechanism'] = $backend->getLegacyAuthMechanism($options['options'])->getClass();
+ }
// Override if priority greater or if priority type different
if ((!isset($mountPoints[$mountPoint]))
@@ -204,6 +212,9 @@ class OC_Mount_Config {
if (!isset($options['priority'])) {
$options['priority'] = $backend->getPriority();
}
+ if (!isset($options['authMechanism'])) {
+ $options['authMechanism'] = $backend->getLegacyAuthMechanism($options['options'])->getClass();
+ }
// Override if priority greater or if priority type different
if ((!isset($mountPoints[$mountPoint]))
@@ -227,6 +238,9 @@ class OC_Mount_Config {
if ($backend->isVisibleFor(BackendService::VISIBILITY_PERSONAL)) {
$options['personal'] = true;
$options['options'] = self::decryptPasswords($options['options']);
+ if (!isset($options['authMechanism'])) {
+ $options['authMechanism'] = $backend->getLegacyAuthMechanism($options['options'])->getClass();
+ }
// Always override previous config
$options['priority_type'] = self::MOUNT_TYPE_PERSONAL;
diff --git a/apps/files_external/lib/config/configadapter.php b/apps/files_external/lib/config/configadapter.php
index 63615e716ae..9829629761c 100644
--- a/apps/files_external/lib/config/configadapter.php
+++ b/apps/files_external/lib/config/configadapter.php
@@ -68,6 +68,7 @@ class ConfigAdapter implements IMountProvider {
$storage->setBackendOption('objectstore', new $objectClass($objectStore));
}
+ $storage->getAuthMechanism()->manipulateStorageConfig($storage);
$storage->getBackend()->manipulateStorageConfig($storage);
}
@@ -81,7 +82,9 @@ class ConfigAdapter implements IMountProvider {
$class = $storageConfig->getBackend()->getStorageClass();
$storage = new $class($storageConfig->getBackendOptions());
+ // auth mechanism should fire first
$storage = $storageConfig->getBackend()->wrapStorage($storage);
+ $storage = $storageConfig->getAuthMechanism()->wrapStorage($storage);
return $storage;
}
diff --git a/apps/files_external/lib/storageconfig.php b/apps/files_external/lib/storageconfig.php
index cf8271ff4eb..96ba2f72ae6 100644
--- a/apps/files_external/lib/storageconfig.php
+++ b/apps/files_external/lib/storageconfig.php
@@ -22,6 +22,7 @@
namespace OCA\Files_external\Lib;
use \OCA\Files_External\Lib\Backend\Backend;
+use \OCA\Files_External\Lib\Auth\AuthMechanism;
/**
* External storage configuration
@@ -43,6 +44,13 @@ class StorageConfig implements \JsonSerializable {
private $backend;
/**
+ * Authentication mechanism
+ *
+ * @var AuthMechanism
+ */
+ private $authMechanism;
+
+ /**
* Backend options
*
* @var array
@@ -154,6 +162,20 @@ class StorageConfig implements \JsonSerializable {
}
/**
+ * @return AuthMechanism
+ */
+ public function getAuthMechanism() {
+ return $this->authMechanism;
+ }
+
+ /**
+ * @param AuthMechanism
+ */
+ public function setAuthMechanism(AuthMechanism $authMechanism) {
+ $this->authMechanism = $authMechanism;
+ }
+
+ /**
* Returns the external storage backend-specific options
*
* @return array backend options
@@ -301,6 +323,7 @@ class StorageConfig implements \JsonSerializable {
}
$result['mountPoint'] = $this->mountPoint;
$result['backendClass'] = $this->backend->getClass();
+ $result['authMechanismClass'] = $this->authMechanism->getClass();
$result['backendOptions'] = $this->backendOptions;
if (!is_null($this->priority)) {
$result['priority'] = $this->priority;
diff --git a/apps/files_external/lib/storagemodifiertrait.php b/apps/files_external/lib/storagemodifiertrait.php
index f78116103db..a11d265e841 100644
--- a/apps/files_external/lib/storagemodifiertrait.php
+++ b/apps/files_external/lib/storagemodifiertrait.php
@@ -26,6 +26,16 @@ use \OCA\Files_External\Lib\StorageConfig;
/**
* Trait for objects that can modify StorageConfigs and wrap Storages
+ *
+ * When a storage implementation is being prepared for use, the StorageConfig
+ * is passed through manipulateStorageConfig() to update any parameters as
+ * necessary. After the storage implementation has been constructed, it is
+ * passed through wrapStorage(), potentially replacing the implementation with
+ * a wrapped storage that changes its behaviour.
+ *
+ * Certain configuration options need to be set before the implementation is
+ * constructed, while others are retrieved directly from the storage
+ * implementation and so need a wrapper to be modified.
*/
trait StorageModifierTrait {
diff --git a/apps/files_external/lib/visibilitytrait.php b/apps/files_external/lib/visibilitytrait.php
index 06c95dd70c9..dfd2d323ca6 100644
--- a/apps/files_external/lib/visibilitytrait.php
+++ b/apps/files_external/lib/visibilitytrait.php
@@ -25,6 +25,13 @@ use \OCA\Files_External\Service\BackendService;
/**
* Trait to implement visibility mechanics for a configuration class
+ *
+ * The standard visibility defines which users/groups can use or see the
+ * object. The allowed visibility defines the maximum visibility allowed to be
+ * set on the object. The standard visibility is often set dynamically by
+ * stored configuration parameters that can be modified by the administrator,
+ * while the allowed visibility is set directly by the object and cannot be
+ * modified by the administrator.
*/
trait VisibilityTrait {
diff --git a/apps/files_external/personal.php b/apps/files_external/personal.php
index e204cdbeb99..fec1c195bba 100644
--- a/apps/files_external/personal.php
+++ b/apps/files_external/personal.php
@@ -40,4 +40,5 @@ $tmpl->assign('isAdminPage', false);
$tmpl->assign('storages', $userStoragesService->getAllStorages());
$tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends()));
$tmpl->assign('backends', $backendService->getBackendsVisibleFor(BackendService::VISIBILITY_PERSONAL));
+$tmpl->assign('authMechanisms', $backendService->getAuthMechanisms());
return $tmpl->fetchPage();
diff --git a/apps/files_external/service/backendservice.php b/apps/files_external/service/backendservice.php
index f5859bc7272..c1abbcf2b7c 100644
--- a/apps/files_external/service/backendservice.php
+++ b/apps/files_external/service/backendservice.php
@@ -24,6 +24,7 @@ namespace OCA\Files_External\Service;
use \OCP\IConfig;
use \OCA\Files_External\Lib\Backend\Backend;
+use \OCA\Files_External\Lib\Auth\AuthMechanism;
/**
* Service class to manage backend definitions
@@ -53,6 +54,9 @@ class BackendService {
/** @var Backend[] */
private $backends = [];
+ /** @var AuthMechanism[] */
+ private $authMechanisms = [];
+
/**
* @param IConfig $config
*/
@@ -90,6 +94,26 @@ class BackendService {
$this->registerBackend($backend);
}
}
+ /**
+ * Register an authentication mechanism
+ *
+ * @param AuthMechanism $authMech
+ */
+ public function registerAuthMechanism(AuthMechanism $authMech) {
+ if (!$this->isAllowedAuthMechanism($authMech)) {
+ $authMech->removeVisibility(BackendService::VISIBILITY_PERSONAL);
+ }
+ $this->authMechanisms[$authMech->getClass()] = $authMech;
+ }
+
+ /**
+ * @param AuthMechanism[] $mechanisms
+ */
+ public function registerAuthMechanisms(array $mechanisms) {
+ foreach ($mechanisms as $mechanism) {
+ $this->registerAuthMechanism($mechanism);
+ }
+ }
/**
* Get all backends
@@ -147,6 +171,63 @@ class BackendService {
}
/**
+ * Get all authentication mechanisms
+ *
+ * @return AuthMechanism[]
+ */
+ public function getAuthMechanisms() {
+ return $this->authMechanisms;
+ }
+
+ /**
+ * Get all authentication mechanisms for schemes
+ *
+ * @param string[] $schemes
+ * @return AuthMechanism[]
+ */
+ public function getAuthMechanismsByScheme(array $schemes) {
+ return array_filter($this->getAuthMechanisms(), function($authMech) use ($schemes) {
+ return in_array($authMech->getScheme(), $schemes, true);
+ });
+ }
+
+ /**
+ * Get authentication mechanisms visible for $visibleFor
+ *
+ * @param int $visibleFor
+ * @return AuthMechanism[]
+ */
+ public function getAuthMechanismsVisibleFor($visibleFor) {
+ return array_filter($this->getAuthMechanisms(), function($authMechanism) use ($visibleFor) {
+ return $authMechanism->isVisibleFor($visibleFor);
+ });
+ }
+
+ /**
+ * Get authentication mechanisms allowed to be visible for $visibleFor
+ *
+ * @param int $visibleFor
+ * @return AuthMechanism[]
+ */
+ public function getAuthMechanismsAllowedVisibleFor($visibleFor) {
+ return array_filter($this->getAuthMechanisms(), function($authMechanism) use ($visibleFor) {
+ return $authMechanism->isAllowedVisibleFor($visibleFor);
+ });
+ }
+
+
+ /**
+ * @param string $class
+ * @return AuthMechanism|null
+ */
+ public function getAuthMechanism($class) {
+ if (isset($this->authMechanisms[$class])) {
+ return $this->authMechanisms[$class];
+ }
+ return null;
+ }
+
+ /**
* @return bool
*/
public function isUserMountingAllowed() {
@@ -167,4 +248,14 @@ class BackendService {
}
return false;
}
+
+ /**
+ * Check an authentication mechanism if a user is allowed to use it
+ *
+ * @param AuthMechanism $authMechanism
+ * @return bool
+ */
+ protected function isAllowedAuthMechanism(AuthMechanism $authMechanism) {
+ return true; // not implemented
+ }
}
diff --git a/apps/files_external/service/storagesservice.php b/apps/files_external/service/storagesservice.php
index d3bde0ae96c..b8a1824ba23 100644
--- a/apps/files_external/service/storagesservice.php
+++ b/apps/files_external/service/storagesservice.php
@@ -82,8 +82,22 @@ abstract class StoragesService {
$storageOptions
) {
$backend = $this->backendService->getBackend($storageOptions['class']);
+ if (!$backend) {
+ throw new \UnexpectedValueException('Invalid backend class');
+ }
$storageConfig->setBackend($backend);
+ if (isset($storageOptions['authMechanism'])) {
+ $authMechanism = $this->backendService->getAuthMechanism($storageOptions['authMechanism']);
+ } else {
+ $authMechanism = $backend->getLegacyAuthMechanism($storageOptions);
+ $storageOptions['authMechanism'] = 'null'; // to make error handling easier
+ }
+ if (!$authMechanism) {
+ throw new \UnexpectedValueException('Invalid authentication mechanism class');
+ }
+ $storageConfig->setAuthMechanism($authMechanism);
+
$storageConfig->setBackendOptions($storageOptions['options']);
if (isset($storageOptions['mountOptions'])) {
$storageConfig->setMountOptions($storageOptions['mountOptions']);
@@ -128,6 +142,7 @@ abstract class StoragesService {
* - "priority": storage priority
* - "backend": backend class name
* - "options": backend-specific options
+ * - "authMechanism": authentication mechanism class name
* - "mountOptions": mount-specific options (ex: disable previews, scanner, etc)
*/
@@ -257,6 +272,7 @@ abstract class StoragesService {
$options = [
'id' => $storageConfig->getId(),
'class' => $storageConfig->getBackend()->getClass(),
+ 'authMechanism' => $storageConfig->getAuthMechanism()->getClass(),
'options' => $storageConfig->getBackendOptions(),
];
@@ -335,6 +351,7 @@ abstract class StoragesService {
*
* @param string $mountPoint storage mount point
* @param string $backendClass backend class name
+ * @param string $authMechanismClass authentication mechanism class
* @param array $backendOptions backend-specific options
* @param array|null $mountOptions mount-specific options
* @param array|null $applicableUsers users for which to mount the storage
@@ -346,6 +363,7 @@ abstract class StoragesService {
public function createStorage(
$mountPoint,
$backendClass,
+ $authMechanismClass,
$backendOptions,
$mountOptions = null,
$applicableUsers = null,
@@ -356,9 +374,14 @@ abstract class StoragesService {
if (!$backend) {
throw new \InvalidArgumentException('Unable to get backend for backend class '.$backendClass);
}
+ $authMechanism = $this->backendService->getAuthMechanism($authMechanismClass);
+ if (!$authMechanism) {
+ throw new \InvalidArgumentException('Unable to get authentication mechanism for class '.$authMechanismClass);
+ }
$newStorage = new StorageConfig();
$newStorage->setMountPoint($mountPoint);
$newStorage->setBackend($backend);
+ $newStorage->setAuthMechanism($authMechanism);
$newStorage->setBackendOptions($backendOptions);
if (isset($mountOptions)) {
$newStorage->setMountOptions($mountOptions);
diff --git a/apps/files_external/settings.php b/apps/files_external/settings.php
index 7c53db4c0dd..7e20af0c60d 100644
--- a/apps/files_external/settings.php
+++ b/apps/files_external/settings.php
@@ -46,6 +46,7 @@ $tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabl
$tmpl->assign('isAdminPage', true);
$tmpl->assign('storages', $globalStoragesService->getAllStorages());
$tmpl->assign('backends', $backendService->getBackendsVisibleFor(BackendService::VISIBILITY_ADMIN));
+$tmpl->assign('authMechanisms', $backendService->getAuthMechanisms());
$tmpl->assign('userBackends', $backendService->getBackendsAllowedVisibleFor(BackendService::VISIBILITY_PERSONAL));
$tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends()));
$tmpl->assign('allowUserMounting', $backendService->isUserMountingAllowed());
diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php
index f931c62eecd..2328ea9565d 100644
--- a/apps/files_external/templates/settings.php
+++ b/apps/files_external/templates/settings.php
@@ -2,6 +2,56 @@
use \OCA\Files_External\Lib\Backend\Backend;
use \OCA\Files_External\Lib\DefinitionParameter;
use \OCA\Files_External\Service\BackendService;
+
+ function writeParameterInput($parameter, $options, $classes = []) {
+ $value = '';
+ if (isset($options[$parameter->getName()])) {
+ $value = $options[$parameter->getName()];
+ }
+ $placeholder = $parameter->getText();
+ $is_optional = $parameter->isFlagSet(DefinitionParameter::FLAG_OPTIONAL);
+
+ switch ($parameter->getType()) {
+ case DefinitionParameter::VALUE_PASSWORD: ?>
+ <?php if ($is_optional) { $classes[] = 'optional'; } ?>
+ <input type="password"
+ <?php if (!empty($classes)): ?> class="<?php p(implode(' ', $classes)); ?>"<?php endif; ?>
+ data-parameter="<?php p($parameter->getName()); ?>"
+ value="<?php p($value); ?>"
+ placeholder="<?php p($placeholder); ?>"
+ />
+ <?php
+ break;
+ case DefinitionParameter::VALUE_BOOLEAN: ?>
+ <label>
+ <input type="checkbox"
+ <?php if (!empty($classes)): ?> class="<?php p(implode(' ', $classes)); ?>"<?php endif; ?>
+ data-parameter="<?php p($parameter->getName()); ?>"
+ <?php if ($value == 'true'): ?> checked="checked"<?php endif; ?>
+ />
+ <?php p($placeholder); ?>
+ </label>
+ <?php
+ break;
+ case DefinitionParameter::VALUE_HIDDEN: ?>
+ <input type="hidden"
+ <?php if (!empty($classes)): ?> class="<?php p(implode(' ', $classes)); ?>"<?php endif; ?>
+ data-parameter="<?php p($parameter->getName()); ?>"
+ value="<?php p($value); ?>"
+ />
+ <?php
+ break;
+ default: ?>
+ <?php if ($is_optional) { $classes[] = 'optional'; } ?>
+ <input type="text"
+ <?php if (!empty($classes)): ?> class="<?php p(implode(' ', $classes)); ?>"<?php endif; ?>
+ data-parameter="<?php p($parameter->getName()); ?>"
+ value="<?php p($value); ?>"
+ placeholder="<?php p($placeholder); ?>"
+ />
+ <?php
+ }
+ }
?>
<form id="files_external" class="section" data-encryption-enabled="<?php echo $_['encryptionEnabled']?'true': 'false'; ?>">
<h2><?php p($l->t('External Storage')); ?></h2>
@@ -12,6 +62,7 @@
<th></th>
<th><?php p($l->t('Folder name')); ?></th>
<th><?php p($l->t('External storage')); ?></th>
+ <th><?php p($l->t('Authentication')); ?></th>
<th><?php p($l->t('Configuration')); ?></th>
<?php if ($_['isAdminPage']) print_unescaped('<th>'.$l->t('Available for').'</th>'); ?>
<th>&nbsp;</th>
@@ -31,60 +82,39 @@
</td>
<td class="backend" data-class="<?php p($storage->getBackend()->getClass()); ?>"><?php p($storage->getBackend()->getText()); ?>
</td>
- <td class="configuration">
- <?php $options = $storage->getBackendOptions(); ?>
- <?php foreach ($storage->getBackend()->getParameters() as $parameter): ?>
+ <td class="authentication">
+ <select class="selectAuthMechanism">
<?php
- $value = '';
- if (isset($options[$parameter->getName()])) {
- $value = $options[$parameter->getName()];
- }
- $placeholder = $parameter->getText();
- $is_optional = $parameter->isFlagSet(DefinitionParameter::FLAG_OPTIONAL);
-
- switch ($parameter->getType()) {
- case DefinitionParameter::VALUE_PASSWORD: ?>
- <input type="password"
- <?php if ($is_optional): ?> class="optional"<?php endif; ?>
- data-parameter="<?php p($parameter->getName()); ?>"
- value="<?php p($value); ?>"
- placeholder="<?php p($placeholder); ?>"
- />
- <?php
- break;
- case DefinitionParameter::VALUE_BOOLEAN: ?>
- <label>
- <input type="checkbox"
- data-parameter="<?php p($parameter->getName()); ?>"
- <?php if ($value == 'true'): ?> checked="checked"<?php endif; ?>
- />
- <?php p($placeholder); ?>
- </label>
- <?php
- break;
- case DefinitionParameter::VALUE_HIDDEN: ?>
- <input type="hidden"
- data-parameter="<?php p($parameter->getName()); ?>"
- value="<?php p($value); ?>"
- />
- <?php
- break;
- default: ?>
- <input type="text"
- <?php if ($is_optional): ?> class="optional"<?php endif; ?>
- data-parameter="<?php p($parameter->getName()); ?>"
- value="<?php p($value); ?>"
- placeholder="<?php p($placeholder); ?>"
- />
- <?php
- }
+ $authSchemes = $storage->getBackend()->getAuthSchemes();
+ $authMechanisms = array_filter($_['authMechanisms'], function($mech) use ($authSchemes) {
+ return isset($authSchemes[$mech->getScheme()]);
+ });
?>
- <?php endforeach; ?>
+ <?php foreach ($authMechanisms as $mech): ?>
+ <option value="<?php p($mech->getClass()); ?>" data-scheme="<?php p($mech->getScheme());?>"
+ <?php if ($mech->getClass() === $storage->getAuthMechanism()->getClass()): ?>selected<?php endif; ?>
+ ><?php p($mech->getText()); ?></option>
+ <?php endforeach; ?>
+ </select>
+ </td>
+ <td class="configuration">
<?php
+ $options = $storage->getBackendOptions();
+ foreach ($storage->getBackend()->getParameters() as $parameter) {
+ writeParameterInput($parameter, $options);
+ }
+ foreach ($storage->getAuthMechanism()->getParameters() as $parameter) {
+ writeParameterInput($parameter, $options, ['auth-param']);
+ }
+
$customJs = $storage->getBackend()->getCustomJs();
if (isset($customJs)) {
\OCP\Util::addScript('files_external', $customJs);
}
+ $customJsAuth = $storage->getAuthMechanism()->getCustomJs();
+ if (isset($customJsAuth)) {
+ \OCP\Util::addScript('files_external', $customJsAuth);
+ }
?>
</td>
<?php if ($_['isAdminPage']): ?>
@@ -140,7 +170,8 @@
<?php endforeach; ?>
</select>
</td>
- <td class="configuration"</td>
+ <td class="authentication" data-mechanisms='<?php p(json_encode($_['authMechanisms'])); ?>'></td>
+ <td class="configuration"></td>
<?php if ($_['isAdminPage']): ?>
<td class="applicable" align="right">
<input type="hidden" class="applicableUsers" style="width:20em;" value="" />
diff --git a/apps/files_external/tests/controller/storagescontrollertest.php b/apps/files_external/tests/controller/storagescontrollertest.php
index f3e8c9afbac..735e760c098 100644
--- a/apps/files_external/tests/controller/storagescontrollertest.php
+++ b/apps/files_external/tests/controller/storagescontrollertest.php
@@ -58,7 +58,22 @@ abstract class StoragesControllerTest extends \Test\TestCase {
return $backend;
}
+ protected function getAuthMechMock($scheme = 'null', $class = '\OCA\Files_External\Lib\Auth\NullMechanism') {
+ $authMech = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $authMech->method('getScheme')
+ ->willReturn($scheme);
+ $authMech->method('getClass')
+ ->willReturn($class);
+
+ return $authMech;
+ }
+
public function testAddStorage() {
+ $authMech = $this->getAuthMechMock();
+ $authMech->method('validateStorage')
+ ->willReturn(true);
$backend = $this->getBackendMock();
$backend->method('validateStorage')
->willReturn(true);
@@ -68,6 +83,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('mount');
$storageConfig->setBackend($backend);
+ $storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions([]);
$this->service->expects($this->once())
@@ -80,6 +96,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$response = $this->controller->create(
'mount',
'\OC\Files\Storage\SMB',
+ '\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@@ -88,11 +105,14 @@ abstract class StoragesControllerTest extends \Test\TestCase {
);
$data = $response->getData();
- $this->assertEquals($storageConfig, $data);
$this->assertEquals(Http::STATUS_CREATED, $response->getStatus());
+ $this->assertEquals($storageConfig, $data);
}
public function testUpdateStorage() {
+ $authMech = $this->getAuthMechMock();
+ $authMech->method('validateStorage')
+ ->willReturn(true);
$backend = $this->getBackendMock();
$backend->method('validateStorage')
->willReturn(true);
@@ -102,6 +122,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('mount');
$storageConfig->setBackend($backend);
+ $storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions([]);
$this->service->expects($this->once())
@@ -115,6 +136,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
1,
'mount',
'\OC\Files\Storage\SMB',
+ '\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@@ -123,8 +145,8 @@ abstract class StoragesControllerTest extends \Test\TestCase {
);
$data = $response->getData();
- $this->assertEquals($storageConfig, $data);
$this->assertEquals(Http::STATUS_OK, $response->getStatus());
+ $this->assertEquals($storageConfig, $data);
}
function mountPointNamesProvider() {
@@ -142,6 +164,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint($mountPoint);
$storageConfig->setBackend($this->getBackendMock());
+ $storageConfig->setAuthMechanism($this->getAuthMechMock());
$storageConfig->setBackendOptions([]);
$this->service->expects($this->exactly(2))
@@ -155,6 +178,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$response = $this->controller->create(
$mountPoint,
'\OC\Files\Storage\SMB',
+ '\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@@ -168,6 +192,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
1,
$mountPoint,
'\OC\Files\Storage\SMB',
+ '\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@@ -190,6 +215,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$response = $this->controller->create(
'mount',
'\OC\Files\Storage\InvalidStorage',
+ '\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@@ -203,6 +229,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
1,
'mount',
'\OC\Files\Storage\InvalidStorage',
+ '\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@@ -214,6 +241,9 @@ abstract class StoragesControllerTest extends \Test\TestCase {
}
public function testUpdateStorageNonExisting() {
+ $authMech = $this->getAuthMechMock();
+ $authMech->method('validateStorage')
+ ->willReturn(true);
$backend = $this->getBackendMock();
$backend->method('validateStorage')
->willReturn(true);
@@ -223,6 +253,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$storageConfig = new StorageConfig(255);
$storageConfig->setMountPoint('mount');
$storageConfig->setBackend($backend);
+ $storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions([]);
$this->service->expects($this->once())
@@ -236,6 +267,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
255,
'mount',
'\OC\Files\Storage\SMB',
+ '\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@@ -265,9 +297,11 @@ abstract class StoragesControllerTest extends \Test\TestCase {
public function testGetStorage() {
$backend = $this->getBackendMock();
+ $authMech = $this->getAuthMechMock();
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('test');
$storageConfig->setBackend($backend);
+ $storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions(['user' => 'test', 'password', 'password123']);
$storageConfig->setMountOptions(['priority' => false]);
diff --git a/apps/files_external/tests/controller/userstoragescontrollertest.php b/apps/files_external/tests/controller/userstoragescontrollertest.php
index 99825f26394..9f1a8df8d2e 100644
--- a/apps/files_external/tests/controller/userstoragescontrollertest.php
+++ b/apps/files_external/tests/controller/userstoragescontrollertest.php
@@ -53,10 +53,12 @@ class UserStoragesControllerTest extends StoragesControllerTest {
$backend->method('isVisibleFor')
->with(BackendService::VISIBILITY_PERSONAL)
->willReturn(false);
+ $authMech = $this->getAuthMechMock();
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('mount');
$storageConfig->setBackend($backend);
+ $storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions([]);
$this->service->expects($this->exactly(2))
@@ -70,6 +72,7 @@ class UserStoragesControllerTest extends StoragesControllerTest {
$response = $this->controller->create(
'mount',
'\OC\Files\Storage\SMB',
+ '\Auth\Mechanism',
array(),
[],
[],
@@ -83,6 +86,7 @@ class UserStoragesControllerTest extends StoragesControllerTest {
1,
'mount',
'\OC\Files\Storage\SMB',
+ '\Auth\Mechanism',
array(),
[],
[],
diff --git a/apps/files_external/tests/js/settingsSpec.js b/apps/files_external/tests/js/settingsSpec.js
index 7cb86d7270b..67a81277124 100644
--- a/apps/files_external/tests/js/settingsSpec.js
+++ b/apps/files_external/tests/js/settingsSpec.js
@@ -39,6 +39,7 @@ describe('OCA.External.Settings tests', function() {
'<option value="\\OC\\AnotherTestBackend">Another Test Backend</option>' +
'</select>' +
'</td>' +
+ '<td class="authentication"></td>' +
'<td class="configuration"></td>' +
'<td class="applicable">' +
'<input type="hidden" class="applicableUsers">' +
@@ -58,6 +59,9 @@ describe('OCA.External.Settings tests', function() {
'field1': 'Display Name 1',
'field2': '&Display Name 2'
},
+ 'authSchemes': {
+ 'builtin': true,
+ },
'priority': 11
},
'\\OC\\AnotherTestBackend': {
@@ -66,10 +70,23 @@ describe('OCA.External.Settings tests', function() {
'field1': 'Display Name 1',
'field2': '&Display Name 2'
},
+ 'authSchemes': {
+ 'builtin': true,
+ },
'priority': 12
}
}
);
+
+ $('#externalStorage #addMountPoint .authentication:first').data('mechanisms', {
+ 'mechanism1': {
+ 'name': 'Mechanism 1',
+ 'configuration': {
+ },
+ 'scheme': 'builtin',
+ },
+ });
+
});
afterEach(function() {
select2Stub.restore();
@@ -80,7 +97,7 @@ describe('OCA.External.Settings tests', function() {
var view;
function selectBackend(backendName) {
- view.$el.find('.selectBackend:first').val('\\OC\\TestBackend').trigger('change');
+ view.$el.find('.selectBackend:first').val(backendName).trigger('change');
}
beforeEach(function() {
@@ -139,7 +156,8 @@ describe('OCA.External.Settings tests', function() {
var request = fakeServer.requests[0];
expect(request.url).toEqual(OC.webroot + '/index.php/apps/files_external/globalstorages');
expect(JSON.parse(request.requestBody)).toEqual({
- backendClass: '\\OC\\TestBackend',
+ backend: '\\OC\\TestBackend',
+ authMechanism: 'mechanism1',
backendOptions: {
'field1': 'test',
'field2': ''
diff --git a/apps/files_external/tests/service/globalstoragesservicetest.php b/apps/files_external/tests/service/globalstoragesservicetest.php
index 422f3543f35..d5f99431a55 100644
--- a/apps/files_external/tests/service/globalstoragesservicetest.php
+++ b/apps/files_external/tests/service/globalstoragesservicetest.php
@@ -41,6 +41,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
return $this->makeStorageConfig([
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
+ 'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -62,6 +63,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
[
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
+ 'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -77,6 +79,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
[
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
+ 'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -92,6 +95,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
[
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
+ 'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -107,6 +111,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
[
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
+ 'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -134,6 +139,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint());
$this->assertEquals($storage->getBackend(), $newStorage->getBackend());
+ $this->assertEquals($storage->getAuthMechanism(), $newStorage->getAuthMechanism());
$this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions());
$this->assertEquals($storage->getApplicableUsers(), $newStorage->getApplicableUsers());
$this->assertEquals($storage->getApplicableGroups(), $newStorage->getApplicableGroups());
@@ -154,6 +160,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$storage = $this->makeStorageConfig([
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
+ 'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -641,6 +648,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$mountPointOptions = current($mountPointData);
$this->assertEquals(1, $mountPointOptions['id']);
$this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
+ $this->assertEquals('\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(15, $mountPointOptions['priority']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
@@ -681,6 +689,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$this->assertEquals(1, $mountPointOptions['id']);
$this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
+ $this->assertEquals('\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(15, $mountPointOptions['priority']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
@@ -698,6 +707,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$this->assertEquals(1, $mountPointOptions['id']);
$this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
+ $this->assertEquals('\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(15, $mountPointOptions['priority']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
@@ -723,12 +733,14 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$legacyConfig = [
'class' => '\OC\Files\Storage\SMB',
+ 'authMechanism' => '\Auth\Mechanism',
'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => false],
];
// different mount options
$legacyConfig2 = [
'class' => '\OC\Files\Storage\SMB',
+ 'authMechanism' => '\Auth\Mechanism',
'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => true],
];
@@ -740,6 +752,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
// different config
$legacyConfig3 = [
'class' => '\OC\Files\Storage\SMB',
+ 'authMechanism' => '\Auth\Mechanism',
'options' => $legacyBackendOptions2,
'mountOptions' => ['preview' => true],
];
diff --git a/apps/files_external/tests/service/storagesservicetest.php b/apps/files_external/tests/service/storagesservicetest.php
index 99e179cc93a..1429fb1818b 100644
--- a/apps/files_external/tests/service/storagesservicetest.php
+++ b/apps/files_external/tests/service/storagesservicetest.php
@@ -59,15 +59,39 @@ abstract class StoragesServiceTest extends \Test\TestCase {
);
\OC_Mount_Config::$skipTest = true;
+ // prepare BackendService mock
$this->backendService =
$this->getMockBuilder('\OCA\Files_External\Service\BackendService')
->disableOriginalConstructor()
->getMock();
+ $authMechanisms = [
+ '\Auth\Mechanism' => $this->getAuthMechMock('null', '\Auth\Mechanism'),
+ '\Other\Auth\Mechanism' => $this->getAuthMechMock('null', '\Other\Auth\Mechanism'),
+ '\OCA\Files_External\Lib\Auth\NullMechanism' => $this->getAuthMechMock(),
+ ];
+ $this->backendService->method('getAuthMechanism')
+ ->will($this->returnCallback(function($class) use ($authMechanisms) {
+ if (isset($authMechanisms[$class])) {
+ return $authMechanisms[$class];
+ }
+ return null;
+ }));
+ $this->backendService->method('getAuthMechanismsByScheme')
+ ->will($this->returnCallback(function($schemes) use ($authMechanisms) {
+ return array_filter($authMechanisms, function ($authMech) use ($schemes) {
+ return in_array($authMech->getScheme(), $schemes, true);
+ });
+ }));
+ $this->backendService->method('getAuthMechanisms')
+ ->will($this->returnValue($authMechanisms));
+
$backends = [
'\OC\Files\Storage\SMB' => $this->getBackendMock('\OCA\Files_External\Lib\Backend\SMB', '\OC\Files\Storage\SMB'),
'\OC\Files\Storage\SFTP' => $this->getBackendMock('\OCA\Files_External\Lib\Backend\SFTP', '\OC\Files\Storage\SFTP'),
];
+ $backends['\OC\Files\Storage\SFTP']->method('getLegacyAuthMechanism')
+ ->willReturn($authMechanisms['\Other\Auth\Mechanism']);
$this->backendService->method('getBackend')
->will($this->returnCallback(function($backendClass) use ($backends) {
if (isset($backends[$backendClass])) {
@@ -105,6 +129,18 @@ abstract class StoragesServiceTest extends \Test\TestCase {
return $backend;
}
+ protected function getAuthMechMock($scheme = 'null', $class = '\OCA\Files_External\Lib\Auth\NullMechanism') {
+ $authMech = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $authMech->method('getScheme')
+ ->willReturn($scheme);
+ $authMech->method('getClass')
+ ->willReturn($class);
+
+ return $authMech;
+ }
+
/**
* Creates a StorageConfig instance based on array data
*
@@ -123,7 +159,11 @@ abstract class StoragesServiceTest extends \Test\TestCase {
// so $data['backend'] can be specified directly
$data['backend'] = $this->backendService->getBackend($data['backendClass']);
}
+ if (!isset($data['authMechanism'])) {
+ $data['authMechanism'] = $this->backendService->getAuthMechanism($data['authMechanismClass']);
+ }
$storage->setBackend($data['backend']);
+ $storage->setAuthMechanism($data['authMechanism']);
$storage->setBackendOptions($data['backendOptions']);
if (isset($data['applicableUsers'])) {
$storage->setApplicableUsers($data['applicableUsers']);
@@ -146,17 +186,21 @@ abstract class StoragesServiceTest extends \Test\TestCase {
*/
public function testNonExistingStorage() {
$backend = $this->backendService->getBackend('\OC\Files\Storage\SMB');
+ $authMechanism = $this->backendService->getAuthMechanism('\Auth\Mechanism');
$storage = new StorageConfig(255);
$storage->setMountPoint('mountpoint');
$storage->setBackend($backend);
+ $storage->setAuthMechanism($authMechanism);
$this->service->updateStorage($storage);
}
public function testDeleteStorage() {
$backend = $this->backendService->getBackend('\OC\Files\Storage\SMB');
+ $authMechanism = $this->backendService->getAuthMechanism('\Auth\Mechanism');
$storage = new StorageConfig(255);
$storage->setMountPoint('mountpoint');
$storage->setBackend($backend);
+ $storage->setAuthMechanism($authMechanism);
$storage->setBackendOptions(['password' => 'testPassword']);
$newStorage = $this->service->addStorage($storage);
diff --git a/apps/files_external/tests/service/userstoragesservicetest.php b/apps/files_external/tests/service/userstoragesservicetest.php
index 98a9993918a..1e57eedd320 100644
--- a/apps/files_external/tests/service/userstoragesservicetest.php
+++ b/apps/files_external/tests/service/userstoragesservicetest.php
@@ -55,6 +55,7 @@ class UserStoragesServiceTest extends StoragesServiceTest {
return $this->makeStorageConfig([
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
+ 'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -77,6 +78,7 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint());
$this->assertEquals($storage->getBackend(), $newStorage->getBackend());
+ $this->assertEquals($storage->getAuthMechanism(), $newStorage->getAuthMechanism());
$this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions());
$this->assertEquals(1, $newStorage->getId());
$this->assertEquals(0, $newStorage->getStatus());
@@ -99,6 +101,7 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$storage = $this->makeStorageConfig([
'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB',
+ 'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -192,6 +195,7 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$mountPointOptions = current($mountPointData);
$this->assertEquals(1, $mountPointOptions['id']);
$this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
+ $this->assertEquals('\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
$backendOptions = $mountPointOptions['options'];
@@ -215,12 +219,14 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$legacyConfig = [
'class' => '\OC\Files\Storage\SMB',
+ 'authMechanism' => '\Auth\Mechanism',
'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => false],
];
// different mount options
$legacyConfig2 = [
'class' => '\OC\Files\Storage\SMB',
+ 'authMechanism' => '\Auth\Mechanism',
'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => true],
];
diff --git a/apps/files_external/tests/storageconfigtest.php b/apps/files_external/tests/storageconfigtest.php
index 69edb36e707..8039990999c 100644
--- a/apps/files_external/tests/storageconfigtest.php
+++ b/apps/files_external/tests/storageconfigtest.php
@@ -32,9 +32,16 @@ class StorageConfigTest extends \Test\TestCase {
$backend->method('getClass')
->willReturn('\OC\Files\Storage\SMB');
+ $authMech = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $authMech->method('getClass')
+ ->willReturn('\Auth\Mechanism');
+
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('test');
$storageConfig->setBackend($backend);
+ $storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions(['user' => 'test', 'password' => 'password123']);
$storageConfig->setPriority(128);
$storageConfig->setApplicableUsers(['user1', 'user2']);
@@ -46,6 +53,7 @@ class StorageConfigTest extends \Test\TestCase {
$this->assertEquals(1, $json['id']);
$this->assertEquals('/test', $json['mountPoint']);
$this->assertEquals('\OC\Files\Storage\SMB', $json['backendClass']);
+ $this->assertEquals('\Auth\Mechanism', $json['authMechanismClass']);
$this->assertEquals('test', $json['backendOptions']['user']);
$this->assertEquals('password123', $json['backendOptions']['password']);
$this->assertEquals(128, $json['priority']);