Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "Global Auth" option to external storage #188

Merged
merged 1 commit into from
Jun 21, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion apps/files_external/appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@
'url' => '/ajax/public_key.php',
'verb' => 'POST',
'requirements' => array()
)
),
[
'name' => 'Ajax#saveGlobalCredentials',
'url' => '/globalcredentials',
'verb' => 'POST',
],
)
)
);
Expand Down
27 changes: 27 additions & 0 deletions apps/files_external/js/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions apps/files_external/lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down
20 changes: 19 additions & 1 deletion apps/files_external/lib/Controller/AjaxController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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() {
Expand All @@ -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;
}
}
88 changes: 88 additions & 0 deletions apps/files_external/lib/Lib/Auth/Password/GlobalAuth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php
/**
* @author Robin Appelman <icewind@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\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']);
}
}

}
4 changes: 4 additions & 0 deletions apps/files_external/personal.php
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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();
3 changes: 3 additions & 0 deletions apps/files_external/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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();
18 changes: 17 additions & 1 deletion apps/files_external/templates/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,24 @@ function writeParameterInput($parameter, $options, $classes = []) {
}
}
?>
<form id="files_external" class="section" data-encryption-enabled="<?php echo $_['encryptionEnabled']?'true': 'false'; ?>">
<form autocomplete="false" class="section" action="#"
id="global_credentials">
<h2><?php p($l->t('External Storage')); ?></h2>
<p><?php p($l->t('Global Credentials')); ?></p>
<input type="text" name="username"
autocomplete="false"
value="<?php p($_['globalCredentials']['user']); ?>"
placeholder="<?php p($l->t('Username')) ?>"/>
<input type="password" name="password"
autocomplete="false"
value="<?php p($_['globalCredentials']['password']); ?>"
placeholder="<?php p($l->t('Password')) ?>"/>
<input type="hidden" name="uid"
value="<?php p($_['globalCredentialsUid']); ?>"/>
<input type="submit" value="<?php p($l->t('Save')) ?>"/>
</form>

<form id="files_external" class="section" data-encryption-enabled="<?php echo $_['encryptionEnabled']?'true': 'false'; ?>">
<?php if (isset($_['dependencies']) and ($_['dependencies']<>'')) print_unescaped(''.$_['dependencies'].''); ?>
<table id="externalStorage" class="grid" data-admin='<?php print_unescaped(json_encode($_['visibilityType'] === BackendService::VISIBILITY_ADMIN)); ?>'>
<thead>
Expand Down
117 changes: 117 additions & 0 deletions apps/files_external/tests/Auth/Password/GlobalAuth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php
/**
* @author Robin Appelman <icewind@owncloud.com>
*
* @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 <http://www.gnu.org/licenses/>
*
*/

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

}