diff options
author | Morris Jobke <hey@morrisjobke.de> | 2017-01-30 19:30:04 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-01-30 19:30:04 -0600 |
commit | 5bad417e57231e129b7113ebb110b1f2b282f349 (patch) | |
tree | 77f5d78e2bd4cd4fe3a70e1659875cce4d832c56 | |
parent | e50320dc71135bf546c757f7dea6e23f5f48a906 (diff) | |
parent | 3ee5c7ea4e508b4945646013f871ad532d09ddbd (diff) | |
download | nextcloud-server-5bad417e57231e129b7113ebb110b1f2b282f349.tar.gz nextcloud-server-5bad417e57231e129b7113ebb110b1f2b282f349.zip |
Merge pull request #2044 from nextcloud/login-credential-store
Login credential store
22 files changed, 637 insertions, 80 deletions
diff --git a/apps/encryption/appinfo/info.xml b/apps/encryption/appinfo/info.xml index 1e63ca5c471..307fef4ad8a 100644 --- a/apps/encryption/appinfo/info.xml +++ b/apps/encryption/appinfo/info.xml @@ -18,8 +18,7 @@ <user>user-encryption</user> <admin>admin-encryption</admin> </documentation> - <rememberlogin>false</rememberlogin> - <version>1.5.0</version> + <version>1.6.0</version> <types> <filesystem/> </types> diff --git a/apps/files_external/appinfo/info.xml b/apps/files_external/appinfo/info.xml index 8482b8b25ed..3f6a48d2e22 100644 --- a/apps/files_external/appinfo/info.xml +++ b/apps/files_external/appinfo/info.xml @@ -12,8 +12,7 @@ External storage can be configured using the GUI or at the command line. This se <documentation> <admin>admin-external-storage</admin> </documentation> - <rememberlogin>false</rememberlogin> - <version>1.2.0</version> + <version>1.3.0</version> <types> <filesystem/> </types> diff --git a/apps/files_external/lib/Lib/Auth/Password/SessionCredentials.php b/apps/files_external/lib/Lib/Auth/Password/SessionCredentials.php index 2fa939764d7..30644206c26 100644 --- a/apps/files_external/lib/Lib/Auth/Password/SessionCredentials.php +++ b/apps/files_external/lib/Lib/Auth/Password/SessionCredentials.php @@ -1,4 +1,5 @@ <?php + /** * @copyright Copyright (c) 2016, ownCloud, Inc. * @@ -23,61 +24,42 @@ namespace OCA\Files_External\Lib\Auth\Password; -use \OCP\IUser; -use \OCP\IL10N; -use \OCA\Files_External\Lib\DefinitionParameter; -use \OCA\Files_External\Lib\Auth\AuthMechanism; -use \OCA\Files_External\Lib\StorageConfig; -use \OCP\ISession; -use \OCP\Security\ICrypto; -use \OCP\Files\Storage; -use \OCA\Files_External\Lib\SessionStorageWrapper; -use \OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException; +use OCA\Files_External\Lib\Auth\AuthMechanism; +use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException; +use OCA\Files_External\Lib\SessionStorageWrapper; +use OCA\Files_External\Lib\StorageConfig; +use OCP\Authentication\Exceptions\CredentialsUnavailableException; +use OCP\Authentication\LoginCredentials\IStore as CredentialsStore; +use OCP\Files\Storage; +use OCP\IL10N; +use OCP\IUser; /** * Username and password from login credentials, saved in session */ class SessionCredentials extends AuthMechanism { - /** @var ISession */ - protected $session; - - /** @var ICrypto */ - protected $crypto; + /** @var CredentialsStore */ + private $credentialsStore; - public function __construct(IL10N $l, ISession $session, ICrypto $crypto) { - $this->session = $session; - $this->crypto = $crypto; + public function __construct(IL10N $l, CredentialsStore $credentialsStore) { + $this->credentialsStore = $credentialsStore; - $this - ->setIdentifier('password::sessioncredentials') + $this->setIdentifier('password::sessioncredentials') ->setScheme(self::SCHEME_PASSWORD) ->setText($l->t('Log-in credentials, save in session')) - ->addParameters([ - ]) - ; - - \OCP\Util::connectHook('OC_User', 'post_login', $this, 'authenticate'); - } - - /** - * Hook listener on post login - * - * @param array $params - */ - public function authenticate(array $params) { - $this->session->set('password::sessioncredentials/credentials', $this->crypto->encrypt(json_encode($params))); + ->addParameters([]); } public function manipulateStorageConfig(StorageConfig &$storage, IUser $user = null) { - $encrypted = $this->session->get('password::sessioncredentials/credentials'); - if (!isset($encrypted)) { + try { + $credentials = $this->credentialsStore->getLoginCredentials(); + } catch (CredentialsUnavailableException $e) { throw new InsufficientDataForMeaningfulAnswerException('No session credentials saved'); } - $credentials = json_decode($this->crypto->decrypt($encrypted), true); - $storage->setBackendOption('user', $this->session->get('loginname')); - $storage->setBackendOption('password', $credentials['password']); + $storage->setBackendOption('user', $credentials->getLoginName()); + $storage->setBackendOption('password', $credentials->getPassword()); } public function wrapStorage(Storage $storage) { diff --git a/apps/files_external/tests/Command/ListCommandTest.php b/apps/files_external/tests/Command/ListCommandTest.php index 5563b19c7a8..76a8f98f520 100644 --- a/apps/files_external/tests/Command/ListCommandTest.php +++ b/apps/files_external/tests/Command/ListCommandTest.php @@ -31,25 +31,27 @@ use OCA\Files_External\Lib\Backend\Local; use OCA\Files_External\Lib\StorageConfig; use OCA\Files_External\Service\GlobalStoragesService; use OCA\Files_External\Service\UserStoragesService; +use OCP\Authentication\LoginCredentials\IStore; use OCP\IL10N; use OCP\ISession; use OCP\IUserManager; use OCP\IUserSession; use OCP\Security\ICrypto; +use PHPUnit_Framework_MockObject_MockObject; use Symfony\Component\Console\Output\BufferedOutput; class ListCommandTest extends CommandTest { /** - * @return \OCA\Files_External\Command\ListCommand|\PHPUnit_Framework_MockObject_MockObject + * @return ListCommand|PHPUnit_Framework_MockObject_MockObject */ private function getInstance() { - /** @var \OCA\Files_External\Service\GlobalStoragesService|\PHPUnit_Framework_MockObject_MockObject $globalService */ + /** @var GlobalStoragesService|PHPUnit_Framework_MockObject_MockObject $globalService */ $globalService = $this->createMock(GlobalStoragesService::class); - /** @var \OCA\Files_External\Service\UserStoragesService|\PHPUnit_Framework_MockObject_MockObject $userService */ + /** @var UserStoragesService|PHPUnit_Framework_MockObject_MockObject $userService */ $userService = $this->createMock(UserStoragesService::class); - /** @var \OCP\IUserManager|\PHPUnit_Framework_MockObject_MockObject $userManager */ + /** @var IUserManager|PHPUnit_Framework_MockObject_MockObject $userManager */ $userManager = $this->createMock(IUserManager::class); - /** @var \OCP\IUserSession|\PHPUnit_Framework_MockObject_MockObject $userSession */ + /** @var IUserSession|PHPUnit_Framework_MockObject_MockObject $userSession */ $userSession = $this->createMock(IUserSession::class); return new ListCommand($globalService, $userService, $userSession, $userManager); @@ -64,7 +66,8 @@ class ListCommandTest extends CommandTest { $mount1->setAuthMechanism(new Password($l10n)); $mount1->setBackend(new Local($l10n, new NullMechanism($l10n))); $mount2 = new StorageConfig(); - $mount2->setAuthMechanism(new SessionCredentials($l10n, $session, $crypto)); + $credentialStore = $this->createMock(IStore::class); + $mount2->setAuthMechanism(new SessionCredentials($l10n, $credentialStore)); $mount2->setBackend(new Local($l10n, new NullMechanism($l10n))); $input = $this->getInput($instance, [], [ 'output' => 'json' diff --git a/core/Controller/LoginController.php b/core/Controller/LoginController.php index 2509cdf0bde..52bd2213954 100644 --- a/core/Controller/LoginController.php +++ b/core/Controller/LoginController.php @@ -159,7 +159,6 @@ class LoginController extends Controller { } $parameters['alt_login'] = OC_App::getAlternativeLogIns(); - $parameters['rememberLoginAllowed'] = OC_Util::rememberLoginAllowed(); $parameters['rememberLoginState'] = !empty($remember_login) ? $remember_login : 0; if (!is_null($user) && $user !== '') { diff --git a/core/templates/login.php b/core/templates/login.php index c200dfe366b..221242c0dcb 100644 --- a/core/templates/login.php +++ b/core/templates/login.php @@ -68,7 +68,6 @@ script('core', [ <input type="submit" id="submit" class="login primary icon-confirm-white" title="" value="<?php p($l->t('Log in')); ?>" disabled="disabled" /> <div class="login-additional"> - <?php if ($_['rememberLoginAllowed'] === true) : ?> <div class="remember-login-container"> <?php if ($_['rememberLoginState'] === 0) { ?> <input type="checkbox" name="remember_login" value="1" id="remember_login" class="checkbox checkbox--white"> @@ -77,7 +76,6 @@ script('core', [ <?php } ?> <label for="remember_login"><?php p($l->t('Stay logged in')); ?></label> </div> - <?php endif; ?> </div> <input type="hidden" name="timezone_offset" id="timezone_offset"/> diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 9c4a2f2728b..4a345ed7a6d 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -54,7 +54,10 @@ return array( 'OCP\\App\\AppPathNotFoundException' => $baseDir . '/lib/public/App/AppPathNotFoundException.php', 'OCP\\App\\IAppManager' => $baseDir . '/lib/public/App/IAppManager.php', 'OCP\\App\\ManagerEvent' => $baseDir . '/lib/public/App/ManagerEvent.php', + 'OCP\\Authentication\\Exceptions\\CredentialsUnavailableException' => $baseDir . '/lib/public/Authentication/Exceptions/CredentialsUnavailableException.php', 'OCP\\Authentication\\IApacheBackend' => $baseDir . '/lib/public/Authentication/IApacheBackend.php', + 'OCP\\Authentication\\LoginCredentials\\ICredentials' => $baseDir . '/lib/public/Authentication/LoginCredentials/ICredentials.php', + 'OCP\\Authentication\\LoginCredentials\\IStore' => $baseDir . '/lib/public/Authentication/LoginCredentials/IStore.php', 'OCP\\Authentication\\TwoFactorAuth\\IProvider' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IProvider.php', 'OCP\\Authentication\\TwoFactorAuth\\TwoFactorException' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/TwoFactorException.php', 'OCP\\AutoloadNotAllowedException' => $baseDir . '/lib/public/AutoloadNotAllowedException.php', @@ -324,6 +327,8 @@ return array( 'OC\\Authentication\\Exceptions\\PasswordlessTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/PasswordlessTokenException.php', 'OC\\Authentication\\Exceptions\\TwoFactorAuthRequiredException' => $baseDir . '/lib/private/Authentication/Exceptions/TwoFactorAuthRequiredException.php', 'OC\\Authentication\\Exceptions\\UserAlreadyLoggedInException' => $baseDir . '/lib/private/Authentication/Exceptions/UserAlreadyLoggedInException.php', + 'OC\\Authentication\\LoginCredentials\\Credentials' => $baseDir . '/lib/private/Authentication/LoginCredentials/Credentials.php', + 'OC\\Authentication\\LoginCredentials\\Store' => $baseDir . '/lib/private/Authentication/LoginCredentials/Store.php', 'OC\\Authentication\\Token\\DefaultToken' => $baseDir . '/lib/private/Authentication/Token/DefaultToken.php', 'OC\\Authentication\\Token\\DefaultTokenCleanupJob' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenCleanupJob.php', 'OC\\Authentication\\Token\\DefaultTokenMapper' => $baseDir . '/lib/private/Authentication/Token/DefaultTokenMapper.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index de1047e9729..f8d360fec4b 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -84,7 +84,10 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OCP\\App\\AppPathNotFoundException' => __DIR__ . '/../../..' . '/lib/public/App/AppPathNotFoundException.php', 'OCP\\App\\IAppManager' => __DIR__ . '/../../..' . '/lib/public/App/IAppManager.php', 'OCP\\App\\ManagerEvent' => __DIR__ . '/../../..' . '/lib/public/App/ManagerEvent.php', + 'OCP\\Authentication\\Exceptions\\CredentialsUnavailableException' => __DIR__ . '/../../..' . '/lib/public/Authentication/Exceptions/CredentialsUnavailableException.php', 'OCP\\Authentication\\IApacheBackend' => __DIR__ . '/../../..' . '/lib/public/Authentication/IApacheBackend.php', + 'OCP\\Authentication\\LoginCredentials\\ICredentials' => __DIR__ . '/../../..' . '/lib/public/Authentication/LoginCredentials/ICredentials.php', + 'OCP\\Authentication\\LoginCredentials\\IStore' => __DIR__ . '/../../..' . '/lib/public/Authentication/LoginCredentials/IStore.php', 'OCP\\Authentication\\TwoFactorAuth\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IProvider.php', 'OCP\\Authentication\\TwoFactorAuth\\TwoFactorException' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/TwoFactorException.php', 'OCP\\AutoloadNotAllowedException' => __DIR__ . '/../../..' . '/lib/public/AutoloadNotAllowedException.php', @@ -354,6 +357,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Authentication\\Exceptions\\PasswordlessTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/PasswordlessTokenException.php', 'OC\\Authentication\\Exceptions\\TwoFactorAuthRequiredException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/TwoFactorAuthRequiredException.php', 'OC\\Authentication\\Exceptions\\UserAlreadyLoggedInException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/UserAlreadyLoggedInException.php', + 'OC\\Authentication\\LoginCredentials\\Credentials' => __DIR__ . '/../../..' . '/lib/private/Authentication/LoginCredentials/Credentials.php', + 'OC\\Authentication\\LoginCredentials\\Store' => __DIR__ . '/../../..' . '/lib/private/Authentication/LoginCredentials/Store.php', 'OC\\Authentication\\Token\\DefaultToken' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultToken.php', 'OC\\Authentication\\Token\\DefaultTokenCleanupJob' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenCleanupJob.php', 'OC\\Authentication\\Token\\DefaultTokenMapper' => __DIR__ . '/../../..' . '/lib/private/Authentication/Token/DefaultTokenMapper.php', diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php index 57499f3ffe8..0879b3e9330 100644 --- a/lib/private/AppFramework/DependencyInjection/DIContainer.php +++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php @@ -93,6 +93,10 @@ class DIContainer extends SimpleContainer implements IAppContainer { return new Output($this->getServer()->getWebRoot()); }); + $this->registerService(\OCP\Authentication\LoginCredentials\IStore::class, function() { + return $this->getServer()->query(\OCP\Authentication\LoginCredentials\IStore::class); + }); + $this->registerService('OCP\\IAvatarManager', function($c) { return $this->getServer()->getAvatarManager(); }); diff --git a/lib/private/Authentication/LoginCredentials/Credentials.php b/lib/private/Authentication/LoginCredentials/Credentials.php new file mode 100644 index 00000000000..9314b7489db --- /dev/null +++ b/lib/private/Authentication/LoginCredentials/Credentials.php @@ -0,0 +1,72 @@ +<?php + +/** + * @copyright 2016 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2016 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Authentication\LoginCredentials; + +use OCP\Authentication\LoginCredentials\ICredentials; + +class Credentials implements ICredentials { + + /** @var string */ + private $uid; + + /** @var string */ + private $loginName; + + /** @var string */ + private $password; + + /** + * @param string $uid + * @param string $loginName + * @param string $password + */ + public function __construct($uid, $loginName, $password) { + $this->uid = $uid; + $this->loginName = $loginName; + $this->password = $password; + } + + /** + * @return string + */ + public function getUID() { + return $this->uid; + } + + /** + * @return string + */ + public function getLoginName() { + return $this->loginName; + } + + /** + * @return string + */ + public function getPassword() { + return $this->password; + } + +} diff --git a/lib/private/Authentication/LoginCredentials/Store.php b/lib/private/Authentication/LoginCredentials/Store.php new file mode 100644 index 00000000000..e44c88c7aea --- /dev/null +++ b/lib/private/Authentication/LoginCredentials/Store.php @@ -0,0 +1,120 @@ +<?php + +/** + * @copyright 2016 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2016 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Authentication\LoginCredentials; + +use OC\Authentication\Exceptions\InvalidTokenException; +use OC\Authentication\Exceptions\PasswordlessTokenException; +use OC\Authentication\Token\IProvider; +use OCP\Authentication\Exceptions\CredentialsUnavailableException; +use OCP\Authentication\LoginCredentials\ICredentials; +use OCP\Authentication\LoginCredentials\IStore; +use OCP\ILogger; +use OCP\ISession; +use OCP\Session\Exceptions\SessionNotAvailableException; +use OCP\Util; + +class Store implements IStore { + + /** @var ISession */ + private $session; + + /** @var ILogger */ + private $logger; + + /** @var IProvider|null */ + private $tokenProvider; + + /** + * @param ISession $session + * @param ILogger $logger + * @param IProvider $tokenProvider + */ + public function __construct(ISession $session, ILogger $logger, IProvider $tokenProvider = null) { + $this->session = $session; + $this->logger = $logger; + $this->tokenProvider = $tokenProvider; + + Util::connectHook('OC_User', 'post_login', $this, 'authenticate'); + } + + /** + * Hook listener on post login + * + * @param array $params + */ + public function authenticate(array $params) { + $this->session->set('login_credentials', json_encode($params)); + } + + /** + * Replace the session implementation + * + * @param ISession $session + */ + public function setSession(ISession $session) { + $this->session = $session; + } + + /** + * @since 12 + * + * @return ICredentials the login credentials of the current user + * @throws CredentialsUnavailableException + */ + public function getLoginCredentials() { + if (is_null($this->tokenProvider)) { + throw new CredentialsUnavailableException(); + } + + $trySession = false; + try { + $sessionId = $this->session->getId(); + $token = $this->tokenProvider->getToken($sessionId); + + $uid = $token->getUID(); + $user = $token->getLoginName(); + $password = $this->tokenProvider->getPassword($token, $sessionId); + + return new Credentials($uid, $user, $password); + } catch (SessionNotAvailableException $ex) { + $this->logger->debug('could not get login credentials because session is unavailable', ['app' => 'core']); + } catch (InvalidTokenException $ex) { + $this->logger->debug('could not get login credentials because the token is invalid', ['app' => 'core']); + $trySession = true; + } catch (PasswordlessTokenException $ex) { + $this->logger->debug('could not get login credentials because the token has no password', ['app' => 'core']); + $trySession = true; + } + + if ($trySession && $this->session->exists('login_credentials')) { + $creds = json_decode($this->session->get('login_credentials')); + return new Credentials($creds->uid, $creds->uid, $creds->password); + } + + // If we reach this line, an exception was thrown. + throw new CredentialsUnavailableException(); + } + +} diff --git a/lib/private/Server.php b/lib/private/Server.php index bd8818e9460..3c716ae6ce6 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -46,6 +46,7 @@ use OC\App\AppStore\Fetcher\AppFetcher; use OC\App\AppStore\Fetcher\CategoryFetcher; use OC\AppFramework\Http\Request; use OC\AppFramework\Utility\TimeFactory; +use OC\Authentication\LoginCredentials\Store; use OC\Command\AsyncBus; use OC\Diagnostics\EventLogger; use OC\Diagnostics\NullEventLogger; @@ -89,6 +90,7 @@ use OC\Security\TrustedDomainHelper; use OC\Session\CryptoWrapper; use OC\Tagging\TagMapper; use OCA\Theming\ThemingDefaults; +use OCP\Authentication\LoginCredentials\IStore; use OCP\IL10N; use OCP\IServerContainer; use OCP\RichObjectStrings\IValidator; @@ -246,6 +248,17 @@ class Server extends ServerContainer implements IServerContainer { }); return $groupManager; }); + $this->registerService(Store::class, function(Server $c) { + $session = $c->getSession(); + if (\OC::$server->getSystemConfig()->getValue('installed', false)) { + $tokenProvider = $c->query('OC\Authentication\Token\IProvider'); + } else { + $tokenProvider = null; + } + $logger = $c->getLogger(); + return new Store($session, $logger, $tokenProvider); + }); + $this->registerAlias(IStore::class, Store::class); $this->registerService('OC\Authentication\Token\DefaultTokenMapper', function (Server $c) { $dbConnection = $c->getDatabaseConnection(); return new Authentication\Token\DefaultTokenMapper($dbConnection); @@ -1000,7 +1013,8 @@ class Server extends ServerContainer implements IServerContainer { */ public function setSession(\OCP\ISession $session) { $this->query(SessionStorage::class)->setSession($session); - return $this->query('UserSession')->setSession($session); + $this->query('UserSession')->setSession($session); + $this->query(Store::class)->setSession($session); } /** diff --git a/lib/private/legacy/util.php b/lib/private/legacy/util.php index d97ba37c4c0..5ef1130d361 100644 --- a/lib/private/legacy/util.php +++ b/lib/private/legacy/util.php @@ -1002,27 +1002,6 @@ class OC_Util { } /** - * Check if it is allowed to remember login. - * - * @note Every app can set 'rememberlogin' to 'false' to disable the remember login feature - * - * @return bool - */ - public static function rememberLoginAllowed() { - - $apps = OC_App::getEnabledApps(); - - foreach ($apps as $app) { - $appInfo = OC_App::getAppInfo($app); - if (isset($appInfo['rememberlogin']) && $appInfo['rememberlogin'] === 'false') { - return false; - } - - } - return true; - } - - /** * Check if the user is a subadmin, redirects to home if not * * @return null|boolean $groups where the current user is subadmin diff --git a/lib/public/Authentication/Exceptions/CredentialsUnavailableException.php b/lib/public/Authentication/Exceptions/CredentialsUnavailableException.php new file mode 100644 index 00000000000..9f9e38103f7 --- /dev/null +++ b/lib/public/Authentication/Exceptions/CredentialsUnavailableException.php @@ -0,0 +1,34 @@ +<?php + +/** + * @copyright 2016 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2016 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Authentication\Exceptions; + +use Exception; + +/** + * @since 12 + */ +class CredentialsUnavailableException extends Exception { + +} diff --git a/lib/public/Authentication/LoginCredentials/ICredentials.php b/lib/public/Authentication/LoginCredentials/ICredentials.php new file mode 100644 index 00000000000..c5ef9574398 --- /dev/null +++ b/lib/public/Authentication/LoginCredentials/ICredentials.php @@ -0,0 +1,58 @@ +<?php + +/** + * @copyright 2016 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2016 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Authentication\LoginCredentials; + +/** + * @since 12 + */ +interface ICredentials { + + /** + * Get the user UID + * + * @since 12 + * + * @return string + */ + public function getUID(); + + /** + * Get the login name the users used to login + * + * @since 12 + * + * @return string + */ + public function getLoginName(); + + /** + * Get the password + * + * @since 12 + * + * @return string + */ + public function getPassword(); +} diff --git a/lib/public/Authentication/LoginCredentials/IStore.php b/lib/public/Authentication/LoginCredentials/IStore.php new file mode 100644 index 00000000000..4787b16d982 --- /dev/null +++ b/lib/public/Authentication/LoginCredentials/IStore.php @@ -0,0 +1,44 @@ +<?php + +/** + * @copyright 2016 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2016 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Authentication\LoginCredentials; + +use OCP\Authentication\Exceptions\CredentialsUnavailableException; + +/** + * @since 12 + */ +interface IStore { + + /** + * Get login credentials of the currently logged in user + * + * @since 12 + * + * @throws CredentialsUnavailableException + * @return ICredentials the login credentials of the current user + */ + public function getLoginCredentials(); + +} diff --git a/tests/Core/Controller/LoginControllerTest.php b/tests/Core/Controller/LoginControllerTest.php index 600179a1dc5..a1a4452abf8 100644 --- a/tests/Core/Controller/LoginControllerTest.php +++ b/tests/Core/Controller/LoginControllerTest.php @@ -179,7 +179,6 @@ class LoginControllerTest extends TestCase { 'user_autofocus' => true, 'canResetPassword' => true, 'alt_login' => [], - 'rememberLoginAllowed' => \OC_Util::rememberLoginAllowed(), 'rememberLoginState' => 0, 'resetPasswordLink' => null, ], @@ -238,7 +237,6 @@ class LoginControllerTest extends TestCase { 'user_autofocus' => false, 'canResetPassword' => $expectedResult, 'alt_login' => [], - 'rememberLoginAllowed' => \OC_Util::rememberLoginAllowed(), 'rememberLoginState' => 0, 'resetPasswordLink' => false, ], @@ -277,7 +275,6 @@ class LoginControllerTest extends TestCase { 'user_autofocus' => false, 'canResetPassword' => false, 'alt_login' => [], - 'rememberLoginAllowed' => \OC_Util::rememberLoginAllowed(), 'rememberLoginState' => 0, 'resetPasswordLink' => false, ], diff --git a/tests/data/app/expected-info.json b/tests/data/app/expected-info.json index 646f22bea85..0666b902f2c 100644 --- a/tests/data/app/expected-info.json +++ b/tests/data/app/expected-info.json @@ -13,7 +13,6 @@ "user": "user-encryption", "admin": "admin-encryption" }, - "rememberlogin": "false", "types": ["filesystem"], "ocsid": "166047", "dependencies": { diff --git a/tests/data/app/invalid-info.xml b/tests/data/app/invalid-info.xml index 3947f5420c2..0ddb13b89c0 100644 --- a/tests/data/app/invalid-info.xml +++ b/tests/data/app/invalid-info.xml @@ -14,7 +14,6 @@ <user>user-encryption</user> <admin>admin-encryption</admin> </documentation> - <rememberlogin>false</rememberlogin> <types> <filesystem/> </types> diff --git a/tests/data/app/valid-info.xml b/tests/data/app/valid-info.xml index 4b22d55d7bc..4788d046c13 100644 --- a/tests/data/app/valid-info.xml +++ b/tests/data/app/valid-info.xml @@ -14,7 +14,6 @@ <user>user-encryption</user> <admin>admin-encryption</admin> </documentation> - <rememberlogin>false</rememberlogin> <types> <filesystem/> </types> diff --git a/tests/lib/Authentication/LoginCredentials/CredentialsTest.php b/tests/lib/Authentication/LoginCredentials/CredentialsTest.php new file mode 100644 index 00000000000..308ccafb151 --- /dev/null +++ b/tests/lib/Authentication/LoginCredentials/CredentialsTest.php @@ -0,0 +1,66 @@ +<?php + +/** + * @copyright 2016 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2016 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace Test\Authentication\LoginCredentials; + +use OC\Authentication\LoginCredentials\Credentials; +use Test\TestCase; + +class CredentialsTest extends TestCase { + + /** @var string */ + private $uid; + + /** @var string */ + private $user; + + /** @var string */ + private $password; + + /** @var Credentials */ + private $credentials; + + protected function setUp() { + parent::setUp(); + + $this->uid = 'user123'; + $this->user = 'User123'; + $this->password = '123456'; + + $this->credentials = new Credentials($this->uid, $this->user, $this->password); + } + + public function testGetUID() { + $this->assertEquals($this->uid, $this->credentials->getUID()); + } + + public function testGetUserName() { + $this->assertEquals($this->user, $this->credentials->getLoginName()); + } + + public function testGetPassword() { + $this->assertEquals($this->password, $this->credentials->getPassword()); + } + +} diff --git a/tests/lib/Authentication/LoginCredentials/StoreTest.php b/tests/lib/Authentication/LoginCredentials/StoreTest.php new file mode 100644 index 00000000000..9a719339b43 --- /dev/null +++ b/tests/lib/Authentication/LoginCredentials/StoreTest.php @@ -0,0 +1,182 @@ +<?php + +/** + * @copyright 2016 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2016 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace Test\Authentication\LoginCredentials; + +use OC\Authentication\Exceptions\InvalidTokenException; +use OC\Authentication\Exceptions\PasswordlessTokenException; +use OC\Authentication\LoginCredentials\Credentials; +use OC\Authentication\LoginCredentials\Store; +use OC\Authentication\Token\IProvider; +use OC\Authentication\Token\IToken; +use OCP\Authentication\Exceptions\CredentialsUnavailableException; +use OCP\ILogger; +use OCP\ISession; +use OCP\Session\Exceptions\SessionNotAvailableException; +use PHPUnit_Framework_MockObject_MockObject; +use Test\TestCase; + +class StoreTest extends TestCase { + + /** @var ISession|PHPUnit_Framework_MockObject_MockObject */ + private $session; + + /** @var IProvider|PHPUnit_Framework_MockObject_MockObject */ + private $tokenProvider; + + /** @var ILogger|PHPUnit_Framework_MockObject_MockObject */ + private $logger; + + /** @var Store */ + private $store; + + protected function setUp() { + parent::setUp(); + + $this->session = $this->createMock(ISession::class); + $this->tokenProvider = $this->createMock(IProvider::class); + $this->logger = $this->createMock(ILogger::class); + + $this->store = new Store($this->session, $this->logger, $this->tokenProvider); + } + + public function testAuthenticate() { + $params = [ + 'run' => true, + 'uid' => 'user123', + 'password' => 123456, + ]; + + $this->session->expects($this->once()) + ->method('set') + ->with($this->equalTo('login_credentials'), $this->equalTo(json_encode($params))); + + $this->store->authenticate($params); + } + + public function testSetSession() { + $session = $this->createMock(ISession::class); + + $this->store->setSession($session); + } + + public function testGetLoginCredentialsNoTokenProvider() { + $this->store = new Store($this->session, $this->logger, null); + + $this->expectException(CredentialsUnavailableException::class); + + $this->store->getLoginCredentials(); + } + + public function testGetLoginCredentials() { + $uid = 'uid'; + $user = 'user123'; + $password = 'passme'; + $token = $this->createMock(IToken::class); + $this->session->expects($this->once()) + ->method('getId') + ->willReturn('sess2233'); + $this->tokenProvider->expects($this->once()) + ->method('getToken') + ->with('sess2233') + ->willReturn($token); + $token->expects($this->once()) + ->method('getUID') + ->willReturn($uid); + $token->expects($this->once()) + ->method('getLoginName') + ->willReturn($user); + $this->tokenProvider->expects($this->once()) + ->method('getPassword') + ->with($token, 'sess2233') + ->willReturn($password); + $expected = new Credentials($uid, $user, $password); + + $creds = $this->store->getLoginCredentials(); + + $this->assertEquals($expected, $creds); + } + + public function testGetLoginCredentialsSessionNotAvailable() { + $this->session->expects($this->once()) + ->method('getId') + ->will($this->throwException(new SessionNotAvailableException())); + $this->expectException(CredentialsUnavailableException::class); + + $this->store->getLoginCredentials(); + } + + public function testGetLoginCredentialsInvalidToken() { + $this->session->expects($this->once()) + ->method('getId') + ->willReturn('sess2233'); + $this->tokenProvider->expects($this->once()) + ->method('getToken') + ->with('sess2233') + ->will($this->throwException(new InvalidTokenException())); + $this->expectException(CredentialsUnavailableException::class); + + $this->store->getLoginCredentials(); + } + + public function testGetLoginCredentialsInvalidTokenLoginCredentials() { + $uid = 'user987'; + $password = '7389374'; + + $this->session->expects($this->once()) + ->method('getId') + ->willReturn('sess2233'); + $this->tokenProvider->expects($this->once()) + ->method('getToken') + ->with('sess2233') + ->will($this->throwException(new InvalidTokenException())); + $this->session->expects($this->once()) + ->method('exists') + ->with($this->equalTo('login_credentials')) + ->willReturn(true); + $this->session->expects($this->once()) + ->method('get') + ->with($this->equalTo('login_credentials')) + ->willReturn('{"run":true,"uid":"user987","password":"7389374"}'); + $expected = new Credentials('user987', 'user987', '7389374'); + + $actual = $this->store->getLoginCredentials(); + + $this->assertEquals($expected, $actual); + } + + public function testGetLoginCredentialsPasswordlessToken() { + $this->session->expects($this->once()) + ->method('getId') + ->willReturn('sess2233'); + $this->tokenProvider->expects($this->once()) + ->method('getToken') + ->with('sess2233') + ->will($this->throwException(new PasswordlessTokenException())); + $this->expectException(CredentialsUnavailableException::class); + + $this->store->getLoginCredentials(); + } + +} |