Authentication mechanisms for external storage backends

A backend can now specify generic authentication schemes that it
supports, instead of specifying the parameters for its authentication
method directly. This allows multiple authentication mechanisms to be
implemented for a single scheme, providing altered functionality.

This commit introduces the backend framework for this feature, and so at
this point the UI will be broken as the frontend does not specify the
required information.

Terminology:
 - authentication scheme
    Parameter interface for the authentication method. A backend
    supporting the 'password' scheme accepts two parameters, 'user' and
    'password'.
 - authentication mechanism
    Specific mechanism implementing a scheme. Basic mechanisms may
    forward configuration options directly to the backend, more advanced
    ones may lookup parameters or retrieve them from the session

New dropdown selector for external storage configurations to select the
authentication mechanism to be used.

Authentication mechanisms can have visibilities, just like backends.
The API was extended too to make it easier to add/remove visibilities.
In addition, the concept of 'allowed visibility' has been introduced, so
a backend/auth mechanism can force a maximum visibility level (e.g.
Local storage type) that cannot be overridden by configuration in the
web UI.

An authentication mechanism is a fully instantiated implementation. This
allows an implementation to have dependencies injected into it, e.g. an
\OCP\IDB for database operations.

When a StorageConfig is being prepared for mounting, the authentication
mechanism implementation has manipulateStorage() called,
which inserts the relevant authentication method options into the
storage ready for mounting.
This commit is contained in:
Robin McCorkell 2015-08-12 10:54:03 +01:00
parent a6a69ef1df
commit 272a46ebe1
25 changed files with 740 additions and 86 deletions

View File

@ -51,6 +51,7 @@ class Application extends App {
}); });
$this->loadBackends(); $this->loadBackends();
$this->loadAuthMechanisms();
} }
/** /**
@ -61,4 +62,17 @@ class Application extends App {
$service = $container->query('OCA\\Files_External\\Service\\BackendService'); $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'),
]);
}
} }

View File

@ -64,6 +64,7 @@ class GlobalStoragesController extends StoragesController {
* *
* @param string $mountPoint storage mount point * @param string $mountPoint storage mount point
* @param string $backendClass backend class name * @param string $backendClass backend class name
* @param string $authMechanismClass authentication mechanism class
* @param array $backendOptions backend-specific options * @param array $backendOptions backend-specific options
* @param array $mountOptions mount-specific options * @param array $mountOptions mount-specific options
* @param array $applicableUsers users for which to mount the storage * @param array $applicableUsers users for which to mount the storage
@ -75,6 +76,7 @@ class GlobalStoragesController extends StoragesController {
public function create( public function create(
$mountPoint, $mountPoint,
$backendClass, $backendClass,
$authMechanismClass,
$backendOptions, $backendOptions,
$mountOptions, $mountOptions,
$applicableUsers, $applicableUsers,
@ -84,6 +86,7 @@ class GlobalStoragesController extends StoragesController {
$newStorage = $this->createStorage( $newStorage = $this->createStorage(
$mountPoint, $mountPoint,
$backendClass, $backendClass,
$authMechanismClass,
$backendOptions, $backendOptions,
$mountOptions, $mountOptions,
$applicableUsers, $applicableUsers,
@ -115,6 +118,7 @@ class GlobalStoragesController extends StoragesController {
* @param int $id storage id * @param int $id storage id
* @param string $mountPoint storage mount point * @param string $mountPoint storage mount point
* @param string $backendClass backend class name * @param string $backendClass backend class name
* @param string $authMechanismClass authentication mechansim class
* @param array $backendOptions backend-specific options * @param array $backendOptions backend-specific options
* @param array $mountOptions mount-specific options * @param array $mountOptions mount-specific options
* @param array $applicableUsers users for which to mount the storage * @param array $applicableUsers users for which to mount the storage
@ -127,6 +131,7 @@ class GlobalStoragesController extends StoragesController {
$id, $id,
$mountPoint, $mountPoint,
$backendClass, $backendClass,
$authMechanismClass,
$backendOptions, $backendOptions,
$mountOptions, $mountOptions,
$applicableUsers, $applicableUsers,
@ -136,6 +141,7 @@ class GlobalStoragesController extends StoragesController {
$storage = $this->createStorage( $storage = $this->createStorage(
$mountPoint, $mountPoint,
$backendClass, $backendClass,
$authMechanismClass,
$backendOptions, $backendOptions,
$mountOptions, $mountOptions,
$applicableUsers, $applicableUsers,

View File

@ -33,6 +33,7 @@ use \OCA\Files_external\Service\StoragesService;
use \OCA\Files_external\NotFoundException; use \OCA\Files_external\NotFoundException;
use \OCA\Files_external\Lib\StorageConfig; use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_External\Lib\Backend\Backend; use \OCA\Files_External\Lib\Backend\Backend;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
/** /**
* Base class for storages controllers * Base class for storages controllers
@ -77,6 +78,7 @@ abstract class StoragesController extends Controller {
* *
* @param string $mountPoint storage mount point * @param string $mountPoint storage mount point
* @param string $backendClass backend class name * @param string $backendClass backend class name
* @param string $authMechanismClass authentication mechanism class name
* @param array $backendOptions backend-specific options * @param array $backendOptions backend-specific options
* @param array|null $mountOptions mount-specific options * @param array|null $mountOptions mount-specific options
* @param array|null $applicableUsers users for which to mount the storage * @param array|null $applicableUsers users for which to mount the storage
@ -88,6 +90,7 @@ abstract class StoragesController extends Controller {
protected function createStorage( protected function createStorage(
$mountPoint, $mountPoint,
$backendClass, $backendClass,
$authMechanismClass,
$backendOptions, $backendOptions,
$mountOptions = null, $mountOptions = null,
$applicableUsers = null, $applicableUsers = null,
@ -98,6 +101,7 @@ abstract class StoragesController extends Controller {
return $this->service->createStorage( return $this->service->createStorage(
$mountPoint, $mountPoint,
$backendClass, $backendClass,
$authMechanismClass,
$backendOptions, $backendOptions,
$mountOptions, $mountOptions,
$applicableUsers, $applicableUsers,
@ -107,7 +111,7 @@ abstract class StoragesController extends Controller {
} catch (\InvalidArgumentException $e) { } catch (\InvalidArgumentException $e) {
return new DataResponse( 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 Http::STATUS_UNPROCESSABLE_ENTITY
); );
@ -134,6 +138,8 @@ abstract class StoragesController extends Controller {
/** @var Backend */ /** @var Backend */
$backend = $storage->getBackend(); $backend = $storage->getBackend();
/** @var AuthMechanism */
$authMechanism = $storage->getAuthMechanism();
if (!$backend || $backend->checkDependencies()) { if (!$backend || $backend->checkDependencies()) {
// invalid backend // invalid backend
return new DataResponse( return new DataResponse(
@ -154,6 +160,15 @@ abstract class StoragesController extends Controller {
Http::STATUS_UNPROCESSABLE_ENTITY 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; return null;
} }
@ -167,6 +182,9 @@ abstract class StoragesController extends Controller {
* @param StorageConfig $storage storage configuration * @param StorageConfig $storage storage configuration
*/ */
protected function updateStorageStatus(StorageConfig &$storage) { protected function updateStorageStatus(StorageConfig &$storage) {
/** @var AuthMechanism */
$authMechanism = $storage->getAuthMechanism();
$authMechanism->manipulateStorageConfig($storage);
/** @var Backend */ /** @var Backend */
$backend = $storage->getBackend(); $backend = $storage->getBackend();
$backend->manipulateStorageConfig($storage); $backend->manipulateStorageConfig($storage);

View File

@ -109,6 +109,7 @@ class UserStoragesController extends StoragesController {
* *
* @param string $mountPoint storage mount point * @param string $mountPoint storage mount point
* @param string $backendClass backend class name * @param string $backendClass backend class name
* @param string $authMechanismClass authentication mechanism class
* @param array $backendOptions backend-specific options * @param array $backendOptions backend-specific options
* @param array $mountOptions backend-specific mount options * @param array $mountOptions backend-specific mount options
* *
@ -119,12 +120,14 @@ class UserStoragesController extends StoragesController {
public function create( public function create(
$mountPoint, $mountPoint,
$backendClass, $backendClass,
$authMechanismClass,
$backendOptions, $backendOptions,
$mountOptions $mountOptions
) { ) {
$newStorage = $this->createStorage( $newStorage = $this->createStorage(
$mountPoint, $mountPoint,
$backendClass, $backendClass,
$authMechanismClass,
$backendOptions, $backendOptions,
$mountOptions $mountOptions
); );
@ -152,6 +155,7 @@ class UserStoragesController extends StoragesController {
* @param int $id storage id * @param int $id storage id
* @param string $mountPoint storage mount point * @param string $mountPoint storage mount point
* @param string $backendClass backend class name * @param string $backendClass backend class name
* @param string $authMechanismClass authentication mechanism class
* @param array $backendOptions backend-specific options * @param array $backendOptions backend-specific options
* @param array $mountOptions backend-specific mount options * @param array $mountOptions backend-specific mount options
* *
@ -163,12 +167,14 @@ class UserStoragesController extends StoragesController {
$id, $id,
$mountPoint, $mountPoint,
$backendClass, $backendClass,
$authMechanismClass,
$backendOptions, $backendOptions,
$mountOptions $mountOptions
) { ) {
$storage = $this->createStorage( $storage = $this->createStorage(
$mountPoint, $mountPoint,
$backendClass, $backendClass,
$authMechanismClass,
$backendOptions, $backendOptions,
$mountOptions $mountOptions
); );

View File

@ -220,6 +220,13 @@ StorageConfig.prototype = {
*/ */
backendClass: null, backendClass: null,
/**
* Authentication mechanism class name
*
* @type string
*/
authMechanismClass: null,
/** /**
* Backend-specific configuration * Backend-specific configuration
* *
@ -273,6 +280,7 @@ StorageConfig.prototype = {
var data = { var data = {
mountPoint: this.mountPoint, mountPoint: this.mountPoint,
backendClass: this.backendClass, backendClass: this.backendClass,
authMechanismClass: this.authMechanismClass,
backendOptions: this.backendOptions backendOptions: this.backendOptions
}; };
if (this.id) { if (this.id) {
@ -579,6 +587,13 @@ MountConfigListView.prototype = {
*/ */
_allBackends: null, _allBackends: null,
/**
* List of all supported authentication mechanisms
*
* @type Object.<string,Object>
*/
_allAuthMechanisms: null,
_encryptionEnabled: false, _encryptionEnabled: false,
/** /**
@ -605,6 +620,7 @@ MountConfigListView.prototype = {
// read the backend config that was carefully crammed // read the backend config that was carefully crammed
// into the data-configurations attribute of the select // into the data-configurations attribute of the select
this._allBackends = this.$el.find('.selectBackend').data('configurations'); 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 //initialize hidden input field with list of users and groups
this.$el.find('tr:not(#addMountPoint)').each(function(i,tr) { 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', '.selectBackend', _.bind(this._onSelectBackend, this));
this.$el.on('change', '.selectAuthMechanism', _.bind(this._onSelectAuthMechanism, this));
}, },
_onChange: function(event) { _onChange: function(event) {
@ -694,40 +711,30 @@ MountConfigListView.prototype = {
} }
$tr.addClass(backendClass); $tr.addClass(backendClass);
$tr.find('.backend').data('class', backendClass); $tr.find('.backend').data('class', backendClass);
var configurations = this._allBackends; var backendConfiguration = this._allBackends[backendClass];
var $td = $tr.find('td.configuration');
$.each(configurations, function(backend, parameters) { var selectAuthMechanism = $('<select class="selectAuthMechanism"></select>');
if (backend === backendClass) { $.each(this._allAuthMechanisms, function(authClass, authMechanism) {
$.each(parameters['configuration'], function(parameter, placeholder) { if (backendConfiguration['authSchemes'][authMechanism['scheme']]) {
var is_optional = false; selectAuthMechanism.append(
if (placeholder.indexOf('&') === 0) { $('<option value="'+authClass+'" data-scheme="'+authMechanism['scheme']+'">'+authMechanism['name']+'</option>')
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.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); $tr.append(priorityEl);
if (parameters['custom'] && $el.find('tbody tr.'+backendClass.replace(/\\/g, '\\\\')).length === 1) { if (backendConfiguration['custom'] && $el.find('tbody tr.'+backendClass.replace(/\\/g, '\\\\')).length === 1) {
OC.addScript('files_external', parameters['custom']); OC.addScript('files_external', backendConfiguration['custom']);
} }
$td.children().not('[type=hidden]').first().focus(); $td.children().not('[type=hidden]').first().focus();
return false;
}
});
$tr.find('td').last().attr('class', 'remove'); $tr.find('td').last().attr('class', 'remove');
$tr.find('td.mountOptionsToggle').removeClass('hidden'); $tr.find('td.mountOptionsToggle').removeClass('hidden');
$tr.find('td').last().removeAttr('style'); $tr.find('td').last().removeAttr('style');
@ -736,6 +743,41 @@ MountConfigListView.prototype = {
addSelect2($tr.find('.applicableUsers'), this._userListLimit); 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 * Gets the storage model from the given row
* *
@ -751,6 +793,7 @@ MountConfigListView.prototype = {
var storage = new this._storageConfigClass(storageId); var storage = new this._storageConfigClass(storageId);
storage.mountPoint = $tr.find('.mountPoint input').val(); storage.mountPoint = $tr.find('.mountPoint input').val();
storage.backendClass = $tr.find('.backend').data('class'); storage.backendClass = $tr.find('.backend').data('class');
storage.authMechanismClass = $tr.find('.selectAuthMechanism').val();
var classOptions = {}; var classOptions = {};
var configuration = $tr.find('.configuration input'); var configuration = $tr.find('.configuration input');

View File

@ -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);
}
}

View File

@ -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'))
;
}
}

View File

@ -27,9 +27,31 @@ use \OCA\Files_External\Lib\FrontendDefinitionTrait;
use \OCA\Files_External\Lib\PriorityTrait; use \OCA\Files_External\Lib\PriorityTrait;
use \OCA\Files_External\Lib\DependencyTrait; use \OCA\Files_External\Lib\DependencyTrait;
use \OCA\Files_External\Lib\StorageModifierTrait; use \OCA\Files_External\Lib\StorageModifierTrait;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
/** /**
* Storage backend * 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 { class Backend implements \JsonSerializable {
@ -42,6 +64,12 @@ class Backend implements \JsonSerializable {
/** @var string storage class */ /** @var string storage class */
private $storageClass; private $storageClass;
/** @var array 'scheme' => true, supported authentication schemes */
private $authSchemes = [];
/** @var AuthMechanism|callable authentication mechanism fallback */
private $legacyAuthMechanism;
/** /**
* @return string * @return string
*/ */
@ -66,6 +94,53 @@ class Backend implements \JsonSerializable {
return $this; return $this;
} }
/**
* @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 * Serialize into JSON for client-side JS
* *
@ -76,6 +151,7 @@ class Backend implements \JsonSerializable {
$data['backend'] = $data['name']; // legacy compat $data['backend'] = $data['name']; // legacy compat
$data['priority'] = $this->getPriority(); $data['priority'] = $this->getPriority();
$data['authSchemes'] = $this->getAuthSchemes();
return $data; return $data;
} }

View File

@ -123,7 +123,9 @@ class OC_Mount_Config {
if (!isset($options['priority'])) { if (!isset($options['priority'])) {
$options['priority'] = $backend->getPriority(); $options['priority'] = $backend->getPriority();
} }
if (!isset($options['authMechanism'])) {
$options['authMechanism'] = $backend->getLegacyAuthMechanism($options['options'])->getClass();
}
// Override if priority greater // Override if priority greater
if ((!isset($mountPoints[$mountPoint])) if ((!isset($mountPoints[$mountPoint]))
@ -149,6 +151,9 @@ class OC_Mount_Config {
if (!isset($options['priority'])) { if (!isset($options['priority'])) {
$options['priority'] = $backend->getPriority(); $options['priority'] = $backend->getPriority();
} }
if (!isset($options['authMechanism'])) {
$options['authMechanism'] = $backend->getLegacyAuthMechanism($options['options'])->getClass();
}
// Override if priority greater // Override if priority greater
if ((!isset($mountPoints[$mountPoint])) if ((!isset($mountPoints[$mountPoint]))
@ -175,6 +180,9 @@ class OC_Mount_Config {
if (!isset($options['priority'])) { if (!isset($options['priority'])) {
$options['priority'] = $backend->getPriority(); $options['priority'] = $backend->getPriority();
} }
if (!isset($options['authMechanism'])) {
$options['authMechanism'] = $backend->getLegacyAuthMechanism($options['options'])->getClass();
}
// Override if priority greater or if priority type different // Override if priority greater or if priority type different
if ((!isset($mountPoints[$mountPoint])) if ((!isset($mountPoints[$mountPoint]))
@ -204,6 +212,9 @@ class OC_Mount_Config {
if (!isset($options['priority'])) { if (!isset($options['priority'])) {
$options['priority'] = $backend->getPriority(); $options['priority'] = $backend->getPriority();
} }
if (!isset($options['authMechanism'])) {
$options['authMechanism'] = $backend->getLegacyAuthMechanism($options['options'])->getClass();
}
// Override if priority greater or if priority type different // Override if priority greater or if priority type different
if ((!isset($mountPoints[$mountPoint])) if ((!isset($mountPoints[$mountPoint]))
@ -227,6 +238,9 @@ class OC_Mount_Config {
if ($backend->isVisibleFor(BackendService::VISIBILITY_PERSONAL)) { if ($backend->isVisibleFor(BackendService::VISIBILITY_PERSONAL)) {
$options['personal'] = true; $options['personal'] = true;
$options['options'] = self::decryptPasswords($options['options']); $options['options'] = self::decryptPasswords($options['options']);
if (!isset($options['authMechanism'])) {
$options['authMechanism'] = $backend->getLegacyAuthMechanism($options['options'])->getClass();
}
// Always override previous config // Always override previous config
$options['priority_type'] = self::MOUNT_TYPE_PERSONAL; $options['priority_type'] = self::MOUNT_TYPE_PERSONAL;

View File

@ -68,6 +68,7 @@ class ConfigAdapter implements IMountProvider {
$storage->setBackendOption('objectstore', new $objectClass($objectStore)); $storage->setBackendOption('objectstore', new $objectClass($objectStore));
} }
$storage->getAuthMechanism()->manipulateStorageConfig($storage);
$storage->getBackend()->manipulateStorageConfig($storage); $storage->getBackend()->manipulateStorageConfig($storage);
} }
@ -81,7 +82,9 @@ class ConfigAdapter implements IMountProvider {
$class = $storageConfig->getBackend()->getStorageClass(); $class = $storageConfig->getBackend()->getStorageClass();
$storage = new $class($storageConfig->getBackendOptions()); $storage = new $class($storageConfig->getBackendOptions());
// auth mechanism should fire first
$storage = $storageConfig->getBackend()->wrapStorage($storage); $storage = $storageConfig->getBackend()->wrapStorage($storage);
$storage = $storageConfig->getAuthMechanism()->wrapStorage($storage);
return $storage; return $storage;
} }

View File

@ -22,6 +22,7 @@
namespace OCA\Files_external\Lib; namespace OCA\Files_external\Lib;
use \OCA\Files_External\Lib\Backend\Backend; use \OCA\Files_External\Lib\Backend\Backend;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
/** /**
* External storage configuration * External storage configuration
@ -42,6 +43,13 @@ class StorageConfig implements \JsonSerializable {
*/ */
private $backend; private $backend;
/**
* Authentication mechanism
*
* @var AuthMechanism
*/
private $authMechanism;
/** /**
* Backend options * Backend options
* *
@ -153,6 +161,20 @@ class StorageConfig implements \JsonSerializable {
$this->backend= $backend; $this->backend= $backend;
} }
/**
* @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 * Returns the external storage backend-specific options
* *
@ -301,6 +323,7 @@ class StorageConfig implements \JsonSerializable {
} }
$result['mountPoint'] = $this->mountPoint; $result['mountPoint'] = $this->mountPoint;
$result['backendClass'] = $this->backend->getClass(); $result['backendClass'] = $this->backend->getClass();
$result['authMechanismClass'] = $this->authMechanism->getClass();
$result['backendOptions'] = $this->backendOptions; $result['backendOptions'] = $this->backendOptions;
if (!is_null($this->priority)) { if (!is_null($this->priority)) {
$result['priority'] = $this->priority; $result['priority'] = $this->priority;

View File

@ -26,6 +26,16 @@ use \OCA\Files_External\Lib\StorageConfig;
/** /**
* Trait for objects that can modify StorageConfigs and wrap Storages * 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 { trait StorageModifierTrait {

View File

@ -25,6 +25,13 @@ use \OCA\Files_External\Service\BackendService;
/** /**
* Trait to implement visibility mechanics for a configuration class * 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 { trait VisibilityTrait {

View File

@ -40,4 +40,5 @@ $tmpl->assign('isAdminPage', false);
$tmpl->assign('storages', $userStoragesService->getAllStorages()); $tmpl->assign('storages', $userStoragesService->getAllStorages());
$tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends())); $tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends()));
$tmpl->assign('backends', $backendService->getBackendsVisibleFor(BackendService::VISIBILITY_PERSONAL)); $tmpl->assign('backends', $backendService->getBackendsVisibleFor(BackendService::VISIBILITY_PERSONAL));
$tmpl->assign('authMechanisms', $backendService->getAuthMechanisms());
return $tmpl->fetchPage(); return $tmpl->fetchPage();

View File

@ -24,6 +24,7 @@ namespace OCA\Files_External\Service;
use \OCP\IConfig; use \OCP\IConfig;
use \OCA\Files_External\Lib\Backend\Backend; use \OCA\Files_External\Lib\Backend\Backend;
use \OCA\Files_External\Lib\Auth\AuthMechanism;
/** /**
* Service class to manage backend definitions * Service class to manage backend definitions
@ -53,6 +54,9 @@ class BackendService {
/** @var Backend[] */ /** @var Backend[] */
private $backends = []; private $backends = [];
/** @var AuthMechanism[] */
private $authMechanisms = [];
/** /**
* @param IConfig $config * @param IConfig $config
*/ */
@ -90,6 +94,26 @@ class BackendService {
$this->registerBackend($backend); $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 * Get all backends
@ -146,6 +170,63 @@ class BackendService {
return null; return null;
} }
/**
* 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 * @return bool
*/ */
@ -167,4 +248,14 @@ class BackendService {
} }
return false; 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
}
} }

View File

@ -82,8 +82,22 @@ abstract class StoragesService {
$storageOptions $storageOptions
) { ) {
$backend = $this->backendService->getBackend($storageOptions['class']); $backend = $this->backendService->getBackend($storageOptions['class']);
if (!$backend) {
throw new \UnexpectedValueException('Invalid backend class');
}
$storageConfig->setBackend($backend); $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']); $storageConfig->setBackendOptions($storageOptions['options']);
if (isset($storageOptions['mountOptions'])) { if (isset($storageOptions['mountOptions'])) {
$storageConfig->setMountOptions($storageOptions['mountOptions']); $storageConfig->setMountOptions($storageOptions['mountOptions']);
@ -128,6 +142,7 @@ abstract class StoragesService {
* - "priority": storage priority * - "priority": storage priority
* - "backend": backend class name * - "backend": backend class name
* - "options": backend-specific options * - "options": backend-specific options
* - "authMechanism": authentication mechanism class name
* - "mountOptions": mount-specific options (ex: disable previews, scanner, etc) * - "mountOptions": mount-specific options (ex: disable previews, scanner, etc)
*/ */
@ -257,6 +272,7 @@ abstract class StoragesService {
$options = [ $options = [
'id' => $storageConfig->getId(), 'id' => $storageConfig->getId(),
'class' => $storageConfig->getBackend()->getClass(), 'class' => $storageConfig->getBackend()->getClass(),
'authMechanism' => $storageConfig->getAuthMechanism()->getClass(),
'options' => $storageConfig->getBackendOptions(), 'options' => $storageConfig->getBackendOptions(),
]; ];
@ -335,6 +351,7 @@ abstract class StoragesService {
* *
* @param string $mountPoint storage mount point * @param string $mountPoint storage mount point
* @param string $backendClass backend class name * @param string $backendClass backend class name
* @param string $authMechanismClass authentication mechanism class
* @param array $backendOptions backend-specific options * @param array $backendOptions backend-specific options
* @param array|null $mountOptions mount-specific options * @param array|null $mountOptions mount-specific options
* @param array|null $applicableUsers users for which to mount the storage * @param array|null $applicableUsers users for which to mount the storage
@ -346,6 +363,7 @@ abstract class StoragesService {
public function createStorage( public function createStorage(
$mountPoint, $mountPoint,
$backendClass, $backendClass,
$authMechanismClass,
$backendOptions, $backendOptions,
$mountOptions = null, $mountOptions = null,
$applicableUsers = null, $applicableUsers = null,
@ -356,9 +374,14 @@ abstract class StoragesService {
if (!$backend) { if (!$backend) {
throw new \InvalidArgumentException('Unable to get backend for backend class '.$backendClass); 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 = new StorageConfig();
$newStorage->setMountPoint($mountPoint); $newStorage->setMountPoint($mountPoint);
$newStorage->setBackend($backend); $newStorage->setBackend($backend);
$newStorage->setAuthMechanism($authMechanism);
$newStorage->setBackendOptions($backendOptions); $newStorage->setBackendOptions($backendOptions);
if (isset($mountOptions)) { if (isset($mountOptions)) {
$newStorage->setMountOptions($mountOptions); $newStorage->setMountOptions($mountOptions);

View File

@ -46,6 +46,7 @@ $tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabl
$tmpl->assign('isAdminPage', true); $tmpl->assign('isAdminPage', true);
$tmpl->assign('storages', $globalStoragesService->getAllStorages()); $tmpl->assign('storages', $globalStoragesService->getAllStorages());
$tmpl->assign('backends', $backendService->getBackendsVisibleFor(BackendService::VISIBILITY_ADMIN)); $tmpl->assign('backends', $backendService->getBackendsVisibleFor(BackendService::VISIBILITY_ADMIN));
$tmpl->assign('authMechanisms', $backendService->getAuthMechanisms());
$tmpl->assign('userBackends', $backendService->getBackendsAllowedVisibleFor(BackendService::VISIBILITY_PERSONAL)); $tmpl->assign('userBackends', $backendService->getBackendsAllowedVisibleFor(BackendService::VISIBILITY_PERSONAL));
$tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends())); $tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends()));
$tmpl->assign('allowUserMounting', $backendService->isUserMountingAllowed()); $tmpl->assign('allowUserMounting', $backendService->isUserMountingAllowed());

View File

@ -2,6 +2,56 @@
use \OCA\Files_External\Lib\Backend\Backend; use \OCA\Files_External\Lib\Backend\Backend;
use \OCA\Files_External\Lib\DefinitionParameter; use \OCA\Files_External\Lib\DefinitionParameter;
use \OCA\Files_External\Service\BackendService; 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'; ?>"> <form id="files_external" class="section" data-encryption-enabled="<?php echo $_['encryptionEnabled']?'true': 'false'; ?>">
<h2><?php p($l->t('External Storage')); ?></h2> <h2><?php p($l->t('External Storage')); ?></h2>
@ -12,6 +62,7 @@
<th></th> <th></th>
<th><?php p($l->t('Folder name')); ?></th> <th><?php p($l->t('Folder name')); ?></th>
<th><?php p($l->t('External storage')); ?></th> <th><?php p($l->t('External storage')); ?></th>
<th><?php p($l->t('Authentication')); ?></th>
<th><?php p($l->t('Configuration')); ?></th> <th><?php p($l->t('Configuration')); ?></th>
<?php if ($_['isAdminPage']) print_unescaped('<th>'.$l->t('Available for').'</th>'); ?> <?php if ($_['isAdminPage']) print_unescaped('<th>'.$l->t('Available for').'</th>'); ?>
<th>&nbsp;</th> <th>&nbsp;</th>
@ -31,60 +82,39 @@
</td> </td>
<td class="backend" data-class="<?php p($storage->getBackend()->getClass()); ?>"><?php p($storage->getBackend()->getText()); ?> <td class="backend" data-class="<?php p($storage->getBackend()->getClass()); ?>"><?php p($storage->getBackend()->getText()); ?>
</td> </td>
<td class="configuration"> <td class="authentication">
<?php $options = $storage->getBackendOptions(); ?> <select class="selectAuthMechanism">
<?php foreach ($storage->getBackend()->getParameters() as $parameter): ?>
<?php <?php
$value = ''; $authSchemes = $storage->getBackend()->getAuthSchemes();
if (isset($options[$parameter->getName()])) { $authMechanisms = array_filter($_['authMechanisms'], function($mech) use ($authSchemes) {
$value = $options[$parameter->getName()]; return isset($authSchemes[$mech->getScheme()]);
} });
$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
}
?> ?>
<?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; ?> <?php endforeach; ?>
</select>
</td>
<td class="configuration">
<?php <?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(); $customJs = $storage->getBackend()->getCustomJs();
if (isset($customJs)) { if (isset($customJs)) {
\OCP\Util::addScript('files_external', $customJs); \OCP\Util::addScript('files_external', $customJs);
} }
$customJsAuth = $storage->getAuthMechanism()->getCustomJs();
if (isset($customJsAuth)) {
\OCP\Util::addScript('files_external', $customJsAuth);
}
?> ?>
</td> </td>
<?php if ($_['isAdminPage']): ?> <?php if ($_['isAdminPage']): ?>
@ -140,7 +170,8 @@
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
</td> </td>
<td class="configuration"</td> <td class="authentication" data-mechanisms='<?php p(json_encode($_['authMechanisms'])); ?>'></td>
<td class="configuration"></td>
<?php if ($_['isAdminPage']): ?> <?php if ($_['isAdminPage']): ?>
<td class="applicable" align="right"> <td class="applicable" align="right">
<input type="hidden" class="applicableUsers" style="width:20em;" value="" /> <input type="hidden" class="applicableUsers" style="width:20em;" value="" />

View File

@ -58,7 +58,22 @@ abstract class StoragesControllerTest extends \Test\TestCase {
return $backend; 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() { public function testAddStorage() {
$authMech = $this->getAuthMechMock();
$authMech->method('validateStorage')
->willReturn(true);
$backend = $this->getBackendMock(); $backend = $this->getBackendMock();
$backend->method('validateStorage') $backend->method('validateStorage')
->willReturn(true); ->willReturn(true);
@ -68,6 +83,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$storageConfig = new StorageConfig(1); $storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('mount'); $storageConfig->setMountPoint('mount');
$storageConfig->setBackend($backend); $storageConfig->setBackend($backend);
$storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions([]); $storageConfig->setBackendOptions([]);
$this->service->expects($this->once()) $this->service->expects($this->once())
@ -80,6 +96,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$response = $this->controller->create( $response = $this->controller->create(
'mount', 'mount',
'\OC\Files\Storage\SMB', '\OC\Files\Storage\SMB',
'\OCA\Files_External\Lib\Auth\NullMechanism',
array(), array(),
[], [],
[], [],
@ -88,11 +105,14 @@ abstract class StoragesControllerTest extends \Test\TestCase {
); );
$data = $response->getData(); $data = $response->getData();
$this->assertEquals($storageConfig, $data);
$this->assertEquals(Http::STATUS_CREATED, $response->getStatus()); $this->assertEquals(Http::STATUS_CREATED, $response->getStatus());
$this->assertEquals($storageConfig, $data);
} }
public function testUpdateStorage() { public function testUpdateStorage() {
$authMech = $this->getAuthMechMock();
$authMech->method('validateStorage')
->willReturn(true);
$backend = $this->getBackendMock(); $backend = $this->getBackendMock();
$backend->method('validateStorage') $backend->method('validateStorage')
->willReturn(true); ->willReturn(true);
@ -102,6 +122,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$storageConfig = new StorageConfig(1); $storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('mount'); $storageConfig->setMountPoint('mount');
$storageConfig->setBackend($backend); $storageConfig->setBackend($backend);
$storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions([]); $storageConfig->setBackendOptions([]);
$this->service->expects($this->once()) $this->service->expects($this->once())
@ -115,6 +136,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
1, 1,
'mount', 'mount',
'\OC\Files\Storage\SMB', '\OC\Files\Storage\SMB',
'\OCA\Files_External\Lib\Auth\NullMechanism',
array(), array(),
[], [],
[], [],
@ -123,8 +145,8 @@ abstract class StoragesControllerTest extends \Test\TestCase {
); );
$data = $response->getData(); $data = $response->getData();
$this->assertEquals($storageConfig, $data);
$this->assertEquals(Http::STATUS_OK, $response->getStatus()); $this->assertEquals(Http::STATUS_OK, $response->getStatus());
$this->assertEquals($storageConfig, $data);
} }
function mountPointNamesProvider() { function mountPointNamesProvider() {
@ -142,6 +164,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$storageConfig = new StorageConfig(1); $storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint($mountPoint); $storageConfig->setMountPoint($mountPoint);
$storageConfig->setBackend($this->getBackendMock()); $storageConfig->setBackend($this->getBackendMock());
$storageConfig->setAuthMechanism($this->getAuthMechMock());
$storageConfig->setBackendOptions([]); $storageConfig->setBackendOptions([]);
$this->service->expects($this->exactly(2)) $this->service->expects($this->exactly(2))
@ -155,6 +178,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$response = $this->controller->create( $response = $this->controller->create(
$mountPoint, $mountPoint,
'\OC\Files\Storage\SMB', '\OC\Files\Storage\SMB',
'\OCA\Files_External\Lib\Auth\NullMechanism',
array(), array(),
[], [],
[], [],
@ -168,6 +192,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
1, 1,
$mountPoint, $mountPoint,
'\OC\Files\Storage\SMB', '\OC\Files\Storage\SMB',
'\OCA\Files_External\Lib\Auth\NullMechanism',
array(), array(),
[], [],
[], [],
@ -190,6 +215,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$response = $this->controller->create( $response = $this->controller->create(
'mount', 'mount',
'\OC\Files\Storage\InvalidStorage', '\OC\Files\Storage\InvalidStorage',
'\OCA\Files_External\Lib\Auth\NullMechanism',
array(), array(),
[], [],
[], [],
@ -203,6 +229,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
1, 1,
'mount', 'mount',
'\OC\Files\Storage\InvalidStorage', '\OC\Files\Storage\InvalidStorage',
'\OCA\Files_External\Lib\Auth\NullMechanism',
array(), array(),
[], [],
[], [],
@ -214,6 +241,9 @@ abstract class StoragesControllerTest extends \Test\TestCase {
} }
public function testUpdateStorageNonExisting() { public function testUpdateStorageNonExisting() {
$authMech = $this->getAuthMechMock();
$authMech->method('validateStorage')
->willReturn(true);
$backend = $this->getBackendMock(); $backend = $this->getBackendMock();
$backend->method('validateStorage') $backend->method('validateStorage')
->willReturn(true); ->willReturn(true);
@ -223,6 +253,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$storageConfig = new StorageConfig(255); $storageConfig = new StorageConfig(255);
$storageConfig->setMountPoint('mount'); $storageConfig->setMountPoint('mount');
$storageConfig->setBackend($backend); $storageConfig->setBackend($backend);
$storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions([]); $storageConfig->setBackendOptions([]);
$this->service->expects($this->once()) $this->service->expects($this->once())
@ -236,6 +267,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
255, 255,
'mount', 'mount',
'\OC\Files\Storage\SMB', '\OC\Files\Storage\SMB',
'\OCA\Files_External\Lib\Auth\NullMechanism',
array(), array(),
[], [],
[], [],
@ -265,9 +297,11 @@ abstract class StoragesControllerTest extends \Test\TestCase {
public function testGetStorage() { public function testGetStorage() {
$backend = $this->getBackendMock(); $backend = $this->getBackendMock();
$authMech = $this->getAuthMechMock();
$storageConfig = new StorageConfig(1); $storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('test'); $storageConfig->setMountPoint('test');
$storageConfig->setBackend($backend); $storageConfig->setBackend($backend);
$storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions(['user' => 'test', 'password', 'password123']); $storageConfig->setBackendOptions(['user' => 'test', 'password', 'password123']);
$storageConfig->setMountOptions(['priority' => false]); $storageConfig->setMountOptions(['priority' => false]);

View File

@ -53,10 +53,12 @@ class UserStoragesControllerTest extends StoragesControllerTest {
$backend->method('isVisibleFor') $backend->method('isVisibleFor')
->with(BackendService::VISIBILITY_PERSONAL) ->with(BackendService::VISIBILITY_PERSONAL)
->willReturn(false); ->willReturn(false);
$authMech = $this->getAuthMechMock();
$storageConfig = new StorageConfig(1); $storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('mount'); $storageConfig->setMountPoint('mount');
$storageConfig->setBackend($backend); $storageConfig->setBackend($backend);
$storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions([]); $storageConfig->setBackendOptions([]);
$this->service->expects($this->exactly(2)) $this->service->expects($this->exactly(2))
@ -70,6 +72,7 @@ class UserStoragesControllerTest extends StoragesControllerTest {
$response = $this->controller->create( $response = $this->controller->create(
'mount', 'mount',
'\OC\Files\Storage\SMB', '\OC\Files\Storage\SMB',
'\Auth\Mechanism',
array(), array(),
[], [],
[], [],
@ -83,6 +86,7 @@ class UserStoragesControllerTest extends StoragesControllerTest {
1, 1,
'mount', 'mount',
'\OC\Files\Storage\SMB', '\OC\Files\Storage\SMB',
'\Auth\Mechanism',
array(), array(),
[], [],
[], [],

View File

@ -39,6 +39,7 @@ describe('OCA.External.Settings tests', function() {
'<option value="\\OC\\AnotherTestBackend">Another Test Backend</option>' + '<option value="\\OC\\AnotherTestBackend">Another Test Backend</option>' +
'</select>' + '</select>' +
'</td>' + '</td>' +
'<td class="authentication"></td>' +
'<td class="configuration"></td>' + '<td class="configuration"></td>' +
'<td class="applicable">' + '<td class="applicable">' +
'<input type="hidden" class="applicableUsers">' + '<input type="hidden" class="applicableUsers">' +
@ -58,6 +59,9 @@ describe('OCA.External.Settings tests', function() {
'field1': 'Display Name 1', 'field1': 'Display Name 1',
'field2': '&Display Name 2' 'field2': '&Display Name 2'
}, },
'authSchemes': {
'builtin': true,
},
'priority': 11 'priority': 11
}, },
'\\OC\\AnotherTestBackend': { '\\OC\\AnotherTestBackend': {
@ -66,10 +70,23 @@ describe('OCA.External.Settings tests', function() {
'field1': 'Display Name 1', 'field1': 'Display Name 1',
'field2': '&Display Name 2' 'field2': '&Display Name 2'
}, },
'authSchemes': {
'builtin': true,
},
'priority': 12 'priority': 12
} }
} }
); );
$('#externalStorage #addMountPoint .authentication:first').data('mechanisms', {
'mechanism1': {
'name': 'Mechanism 1',
'configuration': {
},
'scheme': 'builtin',
},
});
}); });
afterEach(function() { afterEach(function() {
select2Stub.restore(); select2Stub.restore();
@ -80,7 +97,7 @@ describe('OCA.External.Settings tests', function() {
var view; var view;
function selectBackend(backendName) { function selectBackend(backendName) {
view.$el.find('.selectBackend:first').val('\\OC\\TestBackend').trigger('change'); view.$el.find('.selectBackend:first').val(backendName).trigger('change');
} }
beforeEach(function() { beforeEach(function() {
@ -139,7 +156,8 @@ describe('OCA.External.Settings tests', function() {
var request = fakeServer.requests[0]; var request = fakeServer.requests[0];
expect(request.url).toEqual(OC.webroot + '/index.php/apps/files_external/globalstorages'); expect(request.url).toEqual(OC.webroot + '/index.php/apps/files_external/globalstorages');
expect(JSON.parse(request.requestBody)).toEqual({ expect(JSON.parse(request.requestBody)).toEqual({
backendClass: '\\OC\\TestBackend', backend: '\\OC\\TestBackend',
authMechanism: 'mechanism1',
backendOptions: { backendOptions: {
'field1': 'test', 'field1': 'test',
'field2': '' 'field2': ''

View File

@ -41,6 +41,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
return $this->makeStorageConfig([ return $this->makeStorageConfig([
'mountPoint' => 'mountpoint', 'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB', 'backendClass' => '\OC\Files\Storage\SMB',
'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [ 'backendOptions' => [
'option1' => 'value1', 'option1' => 'value1',
'option2' => 'value2', 'option2' => 'value2',
@ -62,6 +63,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
[ [
'mountPoint' => 'mountpoint', 'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB', 'backendClass' => '\OC\Files\Storage\SMB',
'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [ 'backendOptions' => [
'option1' => 'value1', 'option1' => 'value1',
'option2' => 'value2', 'option2' => 'value2',
@ -77,6 +79,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
[ [
'mountPoint' => 'mountpoint', 'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB', 'backendClass' => '\OC\Files\Storage\SMB',
'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [ 'backendOptions' => [
'option1' => 'value1', 'option1' => 'value1',
'option2' => 'value2', 'option2' => 'value2',
@ -92,6 +95,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
[ [
'mountPoint' => 'mountpoint', 'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB', 'backendClass' => '\OC\Files\Storage\SMB',
'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [ 'backendOptions' => [
'option1' => 'value1', 'option1' => 'value1',
'option2' => 'value2', 'option2' => 'value2',
@ -107,6 +111,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
[ [
'mountPoint' => 'mountpoint', 'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB', 'backendClass' => '\OC\Files\Storage\SMB',
'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [ 'backendOptions' => [
'option1' => 'value1', 'option1' => 'value1',
'option2' => 'value2', 'option2' => 'value2',
@ -134,6 +139,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint()); $this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint());
$this->assertEquals($storage->getBackend(), $newStorage->getBackend()); $this->assertEquals($storage->getBackend(), $newStorage->getBackend());
$this->assertEquals($storage->getAuthMechanism(), $newStorage->getAuthMechanism());
$this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions()); $this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions());
$this->assertEquals($storage->getApplicableUsers(), $newStorage->getApplicableUsers()); $this->assertEquals($storage->getApplicableUsers(), $newStorage->getApplicableUsers());
$this->assertEquals($storage->getApplicableGroups(), $newStorage->getApplicableGroups()); $this->assertEquals($storage->getApplicableGroups(), $newStorage->getApplicableGroups());
@ -154,6 +160,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$storage = $this->makeStorageConfig([ $storage = $this->makeStorageConfig([
'mountPoint' => 'mountpoint', 'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB', 'backendClass' => '\OC\Files\Storage\SMB',
'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [ 'backendOptions' => [
'option1' => 'value1', 'option1' => 'value1',
'option2' => 'value2', 'option2' => 'value2',
@ -641,6 +648,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$mountPointOptions = current($mountPointData); $mountPointOptions = current($mountPointData);
$this->assertEquals(1, $mountPointOptions['id']); $this->assertEquals(1, $mountPointOptions['id']);
$this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']); $this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
$this->assertEquals('\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(15, $mountPointOptions['priority']); $this->assertEquals(15, $mountPointOptions['priority']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']); $this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
@ -681,6 +689,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$this->assertEquals(1, $mountPointOptions['id']); $this->assertEquals(1, $mountPointOptions['id']);
$this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']); $this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
$this->assertEquals('\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(15, $mountPointOptions['priority']); $this->assertEquals(15, $mountPointOptions['priority']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']); $this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
@ -698,6 +707,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$this->assertEquals(1, $mountPointOptions['id']); $this->assertEquals(1, $mountPointOptions['id']);
$this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']); $this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
$this->assertEquals('\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(15, $mountPointOptions['priority']); $this->assertEquals(15, $mountPointOptions['priority']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']); $this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
@ -723,12 +733,14 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$legacyConfig = [ $legacyConfig = [
'class' => '\OC\Files\Storage\SMB', 'class' => '\OC\Files\Storage\SMB',
'authMechanism' => '\Auth\Mechanism',
'options' => $legacyBackendOptions, 'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => false], 'mountOptions' => ['preview' => false],
]; ];
// different mount options // different mount options
$legacyConfig2 = [ $legacyConfig2 = [
'class' => '\OC\Files\Storage\SMB', 'class' => '\OC\Files\Storage\SMB',
'authMechanism' => '\Auth\Mechanism',
'options' => $legacyBackendOptions, 'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => true], 'mountOptions' => ['preview' => true],
]; ];
@ -740,6 +752,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
// different config // different config
$legacyConfig3 = [ $legacyConfig3 = [
'class' => '\OC\Files\Storage\SMB', 'class' => '\OC\Files\Storage\SMB',
'authMechanism' => '\Auth\Mechanism',
'options' => $legacyBackendOptions2, 'options' => $legacyBackendOptions2,
'mountOptions' => ['preview' => true], 'mountOptions' => ['preview' => true],
]; ];

View File

@ -59,15 +59,39 @@ abstract class StoragesServiceTest extends \Test\TestCase {
); );
\OC_Mount_Config::$skipTest = true; \OC_Mount_Config::$skipTest = true;
// prepare BackendService mock
$this->backendService = $this->backendService =
$this->getMockBuilder('\OCA\Files_External\Service\BackendService') $this->getMockBuilder('\OCA\Files_External\Service\BackendService')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->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 = [ $backends = [
'\OC\Files\Storage\SMB' => $this->getBackendMock('\OCA\Files_External\Lib\Backend\SMB', '\OC\Files\Storage\SMB'), '\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'), '\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') $this->backendService->method('getBackend')
->will($this->returnCallback(function($backendClass) use ($backends) { ->will($this->returnCallback(function($backendClass) use ($backends) {
if (isset($backends[$backendClass])) { if (isset($backends[$backendClass])) {
@ -105,6 +129,18 @@ abstract class StoragesServiceTest extends \Test\TestCase {
return $backend; 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 * 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 // so $data['backend'] can be specified directly
$data['backend'] = $this->backendService->getBackend($data['backendClass']); $data['backend'] = $this->backendService->getBackend($data['backendClass']);
} }
if (!isset($data['authMechanism'])) {
$data['authMechanism'] = $this->backendService->getAuthMechanism($data['authMechanismClass']);
}
$storage->setBackend($data['backend']); $storage->setBackend($data['backend']);
$storage->setAuthMechanism($data['authMechanism']);
$storage->setBackendOptions($data['backendOptions']); $storage->setBackendOptions($data['backendOptions']);
if (isset($data['applicableUsers'])) { if (isset($data['applicableUsers'])) {
$storage->setApplicableUsers($data['applicableUsers']); $storage->setApplicableUsers($data['applicableUsers']);
@ -146,17 +186,21 @@ abstract class StoragesServiceTest extends \Test\TestCase {
*/ */
public function testNonExistingStorage() { public function testNonExistingStorage() {
$backend = $this->backendService->getBackend('\OC\Files\Storage\SMB'); $backend = $this->backendService->getBackend('\OC\Files\Storage\SMB');
$authMechanism = $this->backendService->getAuthMechanism('\Auth\Mechanism');
$storage = new StorageConfig(255); $storage = new StorageConfig(255);
$storage->setMountPoint('mountpoint'); $storage->setMountPoint('mountpoint');
$storage->setBackend($backend); $storage->setBackend($backend);
$storage->setAuthMechanism($authMechanism);
$this->service->updateStorage($storage); $this->service->updateStorage($storage);
} }
public function testDeleteStorage() { public function testDeleteStorage() {
$backend = $this->backendService->getBackend('\OC\Files\Storage\SMB'); $backend = $this->backendService->getBackend('\OC\Files\Storage\SMB');
$authMechanism = $this->backendService->getAuthMechanism('\Auth\Mechanism');
$storage = new StorageConfig(255); $storage = new StorageConfig(255);
$storage->setMountPoint('mountpoint'); $storage->setMountPoint('mountpoint');
$storage->setBackend($backend); $storage->setBackend($backend);
$storage->setAuthMechanism($authMechanism);
$storage->setBackendOptions(['password' => 'testPassword']); $storage->setBackendOptions(['password' => 'testPassword']);
$newStorage = $this->service->addStorage($storage); $newStorage = $this->service->addStorage($storage);

View File

@ -55,6 +55,7 @@ class UserStoragesServiceTest extends StoragesServiceTest {
return $this->makeStorageConfig([ return $this->makeStorageConfig([
'mountPoint' => 'mountpoint', 'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB', 'backendClass' => '\OC\Files\Storage\SMB',
'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [ 'backendOptions' => [
'option1' => 'value1', 'option1' => 'value1',
'option2' => 'value2', 'option2' => 'value2',
@ -77,6 +78,7 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint()); $this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint());
$this->assertEquals($storage->getBackend(), $newStorage->getBackend()); $this->assertEquals($storage->getBackend(), $newStorage->getBackend());
$this->assertEquals($storage->getAuthMechanism(), $newStorage->getAuthMechanism());
$this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions()); $this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions());
$this->assertEquals(1, $newStorage->getId()); $this->assertEquals(1, $newStorage->getId());
$this->assertEquals(0, $newStorage->getStatus()); $this->assertEquals(0, $newStorage->getStatus());
@ -99,6 +101,7 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$storage = $this->makeStorageConfig([ $storage = $this->makeStorageConfig([
'mountPoint' => 'mountpoint', 'mountPoint' => 'mountpoint',
'backendClass' => '\OC\Files\Storage\SMB', 'backendClass' => '\OC\Files\Storage\SMB',
'authMechanismClass' => '\Auth\Mechanism',
'backendOptions' => [ 'backendOptions' => [
'option1' => 'value1', 'option1' => 'value1',
'option2' => 'value2', 'option2' => 'value2',
@ -192,6 +195,7 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$mountPointOptions = current($mountPointData); $mountPointOptions = current($mountPointData);
$this->assertEquals(1, $mountPointOptions['id']); $this->assertEquals(1, $mountPointOptions['id']);
$this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']); $this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
$this->assertEquals('\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']); $this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
$backendOptions = $mountPointOptions['options']; $backendOptions = $mountPointOptions['options'];
@ -215,12 +219,14 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$legacyConfig = [ $legacyConfig = [
'class' => '\OC\Files\Storage\SMB', 'class' => '\OC\Files\Storage\SMB',
'authMechanism' => '\Auth\Mechanism',
'options' => $legacyBackendOptions, 'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => false], 'mountOptions' => ['preview' => false],
]; ];
// different mount options // different mount options
$legacyConfig2 = [ $legacyConfig2 = [
'class' => '\OC\Files\Storage\SMB', 'class' => '\OC\Files\Storage\SMB',
'authMechanism' => '\Auth\Mechanism',
'options' => $legacyBackendOptions, 'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => true], 'mountOptions' => ['preview' => true],
]; ];

View File

@ -32,9 +32,16 @@ class StorageConfigTest extends \Test\TestCase {
$backend->method('getClass') $backend->method('getClass')
->willReturn('\OC\Files\Storage\SMB'); ->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 = new StorageConfig(1);
$storageConfig->setMountPoint('test'); $storageConfig->setMountPoint('test');
$storageConfig->setBackend($backend); $storageConfig->setBackend($backend);
$storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions(['user' => 'test', 'password' => 'password123']); $storageConfig->setBackendOptions(['user' => 'test', 'password' => 'password123']);
$storageConfig->setPriority(128); $storageConfig->setPriority(128);
$storageConfig->setApplicableUsers(['user1', 'user2']); $storageConfig->setApplicableUsers(['user1', 'user2']);
@ -46,6 +53,7 @@ class StorageConfigTest extends \Test\TestCase {
$this->assertEquals(1, $json['id']); $this->assertEquals(1, $json['id']);
$this->assertEquals('/test', $json['mountPoint']); $this->assertEquals('/test', $json['mountPoint']);
$this->assertEquals('\OC\Files\Storage\SMB', $json['backendClass']); $this->assertEquals('\OC\Files\Storage\SMB', $json['backendClass']);
$this->assertEquals('\Auth\Mechanism', $json['authMechanismClass']);
$this->assertEquals('test', $json['backendOptions']['user']); $this->assertEquals('test', $json['backendOptions']['user']);
$this->assertEquals('password123', $json['backendOptions']['password']); $this->assertEquals('password123', $json['backendOptions']['password']);
$this->assertEquals(128, $json['priority']); $this->assertEquals(128, $json['priority']);