diff --git a/apps/files_external/appinfo/routes.php b/apps/files_external/appinfo/routes.php index 68924ba2c6bc0..1062ae524fffa 100644 --- a/apps/files_external/appinfo/routes.php +++ b/apps/files_external/appinfo/routes.php @@ -42,7 +42,12 @@ 'url' => '/ajax/public_key.php', 'verb' => 'POST', 'requirements' => array() - ) + ), + [ + 'name' => 'Ajax#saveGlobalCredentials', + 'url' => '/globalcredentials', + 'verb' => 'POST', + ], ) ) ); diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index d210c158ec125..921bf92e775ef 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -1347,6 +1347,33 @@ $(document).ready(function() { } }); + $('#global_credentials').on('submit', function() { + var $form = $(this); + var uid = $form.find('[name=uid]').val(); + var user = $form.find('[name=username]').val(); + var password = $form.find('[name=password]').val(); + var $submit = $form.find('[type=submit]'); + $submit.val(t('files_external', 'Saving...')); + $.ajax({ + type: 'POST', + contentType: 'application/json', + data: JSON.stringify({ + uid: uid, + user: user, + password: password + }), + url: OC.generateUrl('apps/files_external/globalcredentials'), + dataType: 'json', + success: function() { + $submit.val(t('files_external', 'Saved')); + setTimeout(function(){ + $submit.val(t('files_external', 'Save')); + }, 2500); + } + }); + return false; + }); + // global instance OCA.External.Settings.mountConfig = mountConfigListView; diff --git a/apps/files_external/lib/AppInfo/Application.php b/apps/files_external/lib/AppInfo/Application.php index f78411038fa77..ee773d03d8ca7 100644 --- a/apps/files_external/lib/AppInfo/Application.php +++ b/apps/files_external/lib/AppInfo/Application.php @@ -112,6 +112,7 @@ public function getAuthMechanisms() { // AuthMechanism::SCHEME_PASSWORD mechanisms $container->query('OCA\Files_External\Lib\Auth\Password\Password'), $container->query('OCA\Files_External\Lib\Auth\Password\SessionCredentials'), + $container->query('OCA\Files_External\Lib\Auth\Password\GlobalAuth'), // AuthMechanism::SCHEME_OAUTH1 mechanisms $container->query('OCA\Files_External\Lib\Auth\OAuth1\OAuth1'), diff --git a/apps/files_external/lib/Controller/AjaxController.php b/apps/files_external/lib/Controller/AjaxController.php index c3df3fa8522dd..8dcfb2a47eb8e 100644 --- a/apps/files_external/lib/Controller/AjaxController.php +++ b/apps/files_external/lib/Controller/AjaxController.php @@ -24,6 +24,7 @@ namespace OCA\Files_External\Controller; +use OCA\Files_External\Lib\Auth\Password\GlobalAuth; use OCP\AppFramework\Controller; use OCP\IRequest; use OCP\AppFramework\Http\JSONResponse; @@ -32,10 +33,16 @@ class AjaxController extends Controller { /** @var RSA */ private $rsaMechanism; + /** @var GlobalAuth */ + private $globalAuth; - public function __construct($appName, IRequest $request, RSA $rsaMechanism) { + public function __construct($appName, + IRequest $request, + RSA $rsaMechanism, + GlobalAuth $globalAuth) { parent::__construct($appName, $request); $this->rsaMechanism = $rsaMechanism; + $this->globalAuth = $globalAuth; } private function generateSshKeys() { @@ -61,4 +68,15 @@ public function getSshKeys() { 'status' => 'success' )); } + + /** + * @param string $uid + * @param string $user + * @param string $password + * @return bool + */ + public function saveGlobalCredentials($uid, $user, $password) { + $this->globalAuth->saveAuth($uid, $user, $password); + return true; + } } diff --git a/apps/files_external/lib/Lib/Auth/Password/GlobalAuth.php b/apps/files_external/lib/Lib/Auth/Password/GlobalAuth.php new file mode 100644 index 0000000000000..5fa4dc5d1d457 --- /dev/null +++ b/apps/files_external/lib/Lib/Auth/Password/GlobalAuth.php @@ -0,0 +1,88 @@ + + * + * @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 + * + */ + +namespace OCA\Files_External\Lib\Auth\Password; + +use OCA\Files_External\Service\BackendService; +use OCP\IL10N; +use OCP\IUser; +use OCA\Files_External\Lib\Auth\AuthMechanism; +use OCA\Files_External\Lib\StorageConfig; +use OCP\Security\ICredentialsManager; +use OCP\Files\Storage; +use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException; + +/** + * Global Username and Password + */ +class GlobalAuth extends AuthMechanism { + + const CREDENTIALS_IDENTIFIER = 'password::global'; + + /** @var ICredentialsManager */ + protected $credentialsManager; + + public function __construct(IL10N $l, ICredentialsManager $credentialsManager) { + $this->credentialsManager = $credentialsManager; + + $this + ->setIdentifier('password::global') + ->setVisibility(BackendService::VISIBILITY_DEFAULT) + ->setScheme(self::SCHEME_PASSWORD) + ->setText($l->t('Global Credentials')); + } + + public function getAuth($uid) { + $auth = $this->credentialsManager->retrieve($uid, self::CREDENTIALS_IDENTIFIER); + if (!is_array($auth)) { + return [ + 'user' => '', + 'password' => '' + ]; + } else { + return $auth; + } + } + + public function saveAuth($uid, $user, $password) { + $this->credentialsManager->store($uid, self::CREDENTIALS_IDENTIFIER, [ + 'user' => $user, + 'password' => $password + ]); + } + + public function manipulateStorageConfig(StorageConfig &$storage, IUser $user = null) { + if ($storage->getType() === StorageConfig::MOUNT_TYPE_ADMIN) { + $uid = ''; + } elseif (is_null($user)) { + throw new InsufficientDataForMeaningfulAnswerException('No credentials saved'); + } else { + $uid = $user->getUID(); + } + $credentials = $this->credentialsManager->retrieve($uid, self::CREDENTIALS_IDENTIFIER); + + if (is_array($credentials)) { + $storage->setBackendOption('user', $credentials['user']); + $storage->setBackendOption('password', $credentials['password']); + } + } + +} diff --git a/apps/files_external/personal.php b/apps/files_external/personal.php index 195b826a4c2a5..8c289f8e30f06 100644 --- a/apps/files_external/personal.php +++ b/apps/files_external/personal.php @@ -30,6 +30,7 @@ $appContainer = \OC_Mount_Config::$app->getContainer(); $backendService = $appContainer->query('OCA\Files_External\Service\BackendService'); $userStoragesService = $appContainer->query('OCA\Files_External\Service\UserStoragesService'); +$globalAuth = $appContainer->query('OCA\Files_External\Lib\Auth\Password\GlobalAuth'); $tmpl = new OCP\Template('files_external', 'settings'); $tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled()); @@ -38,5 +39,8 @@ $tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends())); $tmpl->assign('backends', $backendService->getAvailableBackends()); $tmpl->assign('authMechanisms', $backendService->getAuthMechanisms()); +$uid = \OC::$server->getUserSession()->getUser()->getUID(); +$tmpl->assign('globalCredentials', $globalAuth->getAuth($uid)); +$tmpl->assign('globalCredentialsUid', $uid); $tmpl->assign('allowUserMounting', $backendService->isUserMountingAllowed()); return $tmpl->fetchPage(); diff --git a/apps/files_external/settings.php b/apps/files_external/settings.php index dda715d7f3ef6..e2c70062bf39f 100644 --- a/apps/files_external/settings.php +++ b/apps/files_external/settings.php @@ -32,6 +32,7 @@ $appContainer = \OC_Mount_Config::$app->getContainer(); $backendService = $appContainer->query('OCA\Files_External\Service\BackendService'); $globalStoragesService = $appContainer->query('OCA\Files_External\Service\GlobalStoragesService'); +$globalAuth = $appContainer->query('OCA\Files_External\Lib\Auth\Password\GlobalAuth'); \OC_Util::addVendorScript('select2/select2'); \OC_Util::addVendorStyle('select2/select2'); @@ -44,4 +45,6 @@ $tmpl->assign('authMechanisms', $backendService->getAuthMechanisms()); $tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends())); $tmpl->assign('allowUserMounting', $backendService->isUserMountingAllowed()); +$tmpl->assign('globalCredentials', $globalAuth->getAuth('')); +$tmpl->assign('globalCredentialsUid', ''); return $tmpl->fetchPage(); diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php index 6662f637039c5..6fb2a0185479e 100644 --- a/apps/files_external/templates/settings.php +++ b/apps/files_external/templates/settings.php @@ -84,8 +84,24 @@ function writeParameterInput($parameter, $options, $classes = []) { } } ?> -
+

t('External Storage')); ?>

+

t('Global Credentials')); ?>

+ + + + +
+ +
'')) print_unescaped(''.$_['dependencies'].''); ?> '> diff --git a/apps/files_external/tests/Auth/Password/GlobalAuth.php b/apps/files_external/tests/Auth/Password/GlobalAuth.php new file mode 100644 index 0000000000000..912bfd1574d3e --- /dev/null +++ b/apps/files_external/tests/Auth/Password/GlobalAuth.php @@ -0,0 +1,117 @@ + + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCA\Files_External\Tests\Auth\Password; + +use OCA\Files_External\Lib\Auth\Password\GlobalAuth; +use OCA\Files_external\Lib\StorageConfig; +use Test\TestCase; + +class GlobalAuthTest extends TestCase { + /** + * @var \OCP\IL10N|\PHPUnit_Framework_MockObject_MockObject + */ + private $l10n; + + /** + * @var \OCP\Security\ICredentialsManager|\PHPUnit_Framework_MockObject_MockObject + */ + private $credentialsManager; + + /** + * @var GlobalAuth + */ + private $instance; + + protected function setUp() { + parent::setUp(); + $this->l10n = $this->getMock('\OCP\IL10N'); + $this->credentialsManager = $this->getMock('\OCP\Security\ICredentialsManager'); + $this->instance = new GlobalAuth($this->l10n, $this->credentialsManager); + } + + private function getStorageConfig($type, $config = []) { + /** @var \OCA\Files_External\Lib\StorageConfig|\PHPUnit_Framework_MockObject_MockObject $storageConfig */ + $storageConfig = $this->getMock('\OCA\Files_External\Lib\StorageConfig'); + $storageConfig->expects($this->any()) + ->method('getType') + ->will($this->returnValue($type)); + $storageConfig->expects($this->any()) + ->method('getBackendOptions') + ->will($this->returnCallback(function () use (&$config) { + return $config; + })); + $storageConfig->expects($this->any()) + ->method('getBackendOption') + ->will($this->returnCallback(function ($key) use (&$config) { + return $config[$key]; + })); + $storageConfig->expects($this->any()) + ->method('setBackendOption') + ->will($this->returnCallback(function ($key, $value) use (&$config) { + $config[$key] = $value; + })); + + return $storageConfig; + } + + public function testNoCredentials() { + $this->credentialsManager->expects($this->once()) + ->method('retrieve') + ->will($this->returnValue(null)); + + $storage = $this->getStorageConfig(StorageConfig::MOUNT_TYPE_ADMIN); + + $this->instance->manipulateStorageConfig($storage); + $this->assertEquals([], $storage->getBackendOptions()); + } + + public function testSavedCredentials() { + $this->credentialsManager->expects($this->once()) + ->method('retrieve') + ->will($this->returnValue([ + 'user' => 'a', + 'password' => 'b' + ])); + + $storage = $this->getStorageConfig(StorageConfig::MOUNT_TYPE_ADMIN); + + $this->instance->manipulateStorageConfig($storage); + $this->assertEquals([ + 'user' => 'a', + 'password' => 'b' + ], $storage->getBackendOptions()); + } + + /** + * @expectedException \OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException + */ + public function testNoCredentialsPersonal() { + $this->credentialsManager->expects($this->never()) + ->method('retrieve'); + + $storage = $this->getStorageConfig(StorageConfig::MOUNT_TYPE_PERSONAl); + + $this->instance->manipulateStorageConfig($storage); + $this->assertEquals([], $storage->getBackendOptions()); + } + +}