Merge pull request #11409 from nextcloud/feature/consolidated-2fa-settings

Consolidate personal two-factor provider settings
This commit is contained in:
Roeland Jago Douma 2018-10-03 09:56:21 +02:00 committed by GitHub
commit f9e201adfe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 225 additions and 66 deletions

View file

@ -25,12 +25,15 @@ namespace OCA\TwoFactorBackupCodes\Provider;
use OC\App\AppManager;
use OCA\TwoFactorBackupCodes\Service\BackupCodeStorage;
use OCA\TwoFactorBackupCodes\Settings\Personal;
use OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings;
use OCP\Authentication\TwoFactorAuth\IProvider;
use OCP\Authentication\TwoFactorAuth\IProvidesPersonalSettings;
use OCP\IL10N;
use OCP\IUser;
use OCP\Template;
class BackupCodesProvider implements IProvider {
class BackupCodesProvider implements IProvider, IProvidesPersonalSettings {
/** @var string */
private $appName;
@ -139,4 +142,14 @@ class BackupCodesProvider implements IProvider {
return false;
}
/**
* @param IUser $user
*
* @return IPersonalProviderSettings
*/
public function getPersonalSettings(IUser $user): IPersonalProviderSettings {
return new Personal();
}
}

View file

@ -1,8 +1,9 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @license GNU AGPL version 3 or any later version
*
@ -24,59 +25,13 @@
namespace OCA\TwoFactorBackupCodes\Settings;
use OCA\TwoFactorBackupCodes\AppInfo\Application;
use OCA\TwoFactorBackupCodes\Provider\BackupCodesProvider;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IUserSession;
use OCP\Settings\ISettings;
use OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings;
use OCP\Template;
class Personal implements ISettings {
class Personal implements IPersonalProviderSettings {
/** @var Application */
private $app;
/** @var BackupCodesProvider */
private $provider;
/** @var IUserSession */
private $userSession;
public function __construct(Application $app, BackupCodesProvider $provider, IUserSession $userSession) {
$this->app = $app;
$this->provider = $provider;
$this->userSession = $userSession;
public function getBody(): Template {
return new Template('twofactor_backupcodes', 'personal');
}
/**
* @return TemplateResponse returns the instance with all parameters set, ready to be rendered
* @since 9.1
*/
public function getForm() {
$templateOwner = 'settings';
$templateName = 'settings/empty';
if ($this->provider->isActive($this->userSession->getUser())) {
$templateOwner = $this->app->getContainer()->getAppName();
$templateName = 'personal';
}
return new TemplateResponse($templateOwner, $templateName, [], '');
}
/**
* @return string the section ID, e.g. 'sharing'
* @since 9.1
*/
public function getSection() {
return 'security';
}
/**
* @return int whether the form should be rather on the top or bottom of
* the admin section. The forms are arranged in ascending order of the
* priority values. It is required to return a value between 0 and 100.
*
* E.g.: 70
* @since 9.1
*/
public function getPriority() {
return 40;
}
}

View file

@ -14,7 +14,7 @@
<li v-for="code in codes" class="backup-code">{{code}}</li>
</ul>
<a :href="downloadUrl"
class="button"
class="button primary"
download="Nextcloud-backup-codes.txt">{{ t('twofactor_backupcodes', 'Save backup codes') }}</a>
<button class="button"
v-on:click="printCodes">{{ t('twofactor_backupcodes', 'Print backup codes') }}</button>
@ -25,9 +25,9 @@
:class="{'icon-loading-small': generatingCodes}"
v-on:click="generateBackupCodes">{{ t('twofactor_backupcodes', 'Regenerate backup codes') }}</button>
</p>
<p>
<p><em>
{{ t('twofactor_backupcodes', 'If you regenerate backup codes, you automatically invalidate old codes.') }}
</p>
</em></p>
</template>
</div>
</template>

View file

@ -5,7 +5,4 @@ style('twofactor_backupcodes', 'style');
?>
<div class="section">
<h2 data-anchor-name="second-factor-backup-codes"><?php p($l->t('Second-factor backup codes')); ?></h2>
<div id="twofactor-backupcodes-settings"></div>
</div>
<div id="twofactor-backupcodes-settings"></div>

View file

@ -72,9 +72,11 @@ return array(
'OCP\\Authentication\\LoginCredentials\\IStore' => $baseDir . '/lib/public/Authentication/LoginCredentials/IStore.php',
'OCP\\Authentication\\TwoFactorAuth\\IActivatableByAdmin' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IActivatableByAdmin.php',
'OCP\\Authentication\\TwoFactorAuth\\IDeactivatableByAdmin' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IDeactivatableByAdmin.php',
'OCP\\Authentication\\TwoFactorAuth\\IPersonalProviderSettings' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IPersonalProviderSettings.php',
'OCP\\Authentication\\TwoFactorAuth\\IProvider' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IProvider.php',
'OCP\\Authentication\\TwoFactorAuth\\IProvidesCustomCSP' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IProvidesCustomCSP.php',
'OCP\\Authentication\\TwoFactorAuth\\IProvidesIcons' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IProvidesIcons.php',
'OCP\\Authentication\\TwoFactorAuth\\IProvidesPersonalSettings' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IProvidesPersonalSettings.php',
'OCP\\Authentication\\TwoFactorAuth\\IRegistry' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/IRegistry.php',
'OCP\\Authentication\\TwoFactorAuth\\RegistryEvent' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/RegistryEvent.php',
'OCP\\Authentication\\TwoFactorAuth\\TwoFactorException' => $baseDir . '/lib/public/Authentication/TwoFactorAuth/TwoFactorException.php',

View file

@ -102,9 +102,11 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OCP\\Authentication\\LoginCredentials\\IStore' => __DIR__ . '/../../..' . '/lib/public/Authentication/LoginCredentials/IStore.php',
'OCP\\Authentication\\TwoFactorAuth\\IActivatableByAdmin' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IActivatableByAdmin.php',
'OCP\\Authentication\\TwoFactorAuth\\IDeactivatableByAdmin' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IDeactivatableByAdmin.php',
'OCP\\Authentication\\TwoFactorAuth\\IPersonalProviderSettings' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IPersonalProviderSettings.php',
'OCP\\Authentication\\TwoFactorAuth\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IProvider.php',
'OCP\\Authentication\\TwoFactorAuth\\IProvidesCustomCSP' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IProvidesCustomCSP.php',
'OCP\\Authentication\\TwoFactorAuth\\IProvidesIcons' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IProvidesIcons.php',
'OCP\\Authentication\\TwoFactorAuth\\IProvidesPersonalSettings' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IProvidesPersonalSettings.php',
'OCP\\Authentication\\TwoFactorAuth\\IRegistry' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/IRegistry.php',
'OCP\\Authentication\\TwoFactorAuth\\RegistryEvent' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/RegistryEvent.php',
'OCP\\Authentication\\TwoFactorAuth\\TwoFactorException' => __DIR__ . '/../../..' . '/lib/public/Authentication/TwoFactorAuth/TwoFactorException.php',

View file

@ -24,18 +24,41 @@
namespace OC\Settings\Personal;
use function array_filter;
use function array_map;
use function is_null;
use OC\Authentication\TwoFactorAuth\Manager as TwoFactorManager;
use OC\Authentication\TwoFactorAuth\ProviderLoader;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\Authentication\TwoFactorAuth\IProvider;
use OCP\Authentication\TwoFactorAuth\IProvidesPersonalSettings;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Settings\ISettings;
class Security implements ISettings {
/** @var IUserManager */
private $userManager;
public function __construct(
IUserManager $userManager
) {
/** @var TwoFactorManager */
private $twoFactorManager;
/** @var ProviderLoader */
private $providerLoader;
/** @var IUserSession */
private $userSession;
public function __construct(IUserManager $userManager,
TwoFactorManager $providerManager,
ProviderLoader $providerLoader,
IUserSession $userSession) {
$this->userManager = $userManager;
$this->twoFactorManager = $providerManager;
$this->providerLoader = $providerLoader;
$this->userSession = $userSession;
}
/**
@ -50,7 +73,8 @@ class Security implements ISettings {
}
return new TemplateResponse('settings', 'settings/personal/security', [
'passwordChangeSupported' => $passwordChangeSupported
'passwordChangeSupported' => $passwordChangeSupported,
'twoFactorProviderData' => $this->getTwoFactorProviderData(),
]);
}
@ -73,4 +97,24 @@ class Security implements ISettings {
public function getPriority() {
return 10;
}
private function getTwoFactorProviderData(): array {
$user = $this->userSession->getUser();
if (is_null($user)) {
// Actually impossible, but still …
return [];
}
return [
'isEnabled' => $this->twoFactorManager->isTwoFactorAuthenticated($user),
'providers' => array_map(function (IProvidesPersonalSettings $provider) use ($user) {
return [
'provider' => $provider,
'settings' => $provider->getPersonalSettings($user)
];
}, array_filter($this->providerLoader->getProviders($user), function (IProvider $provider) {
return $provider instanceof IProvidesPersonalSettings;
}))
];
}
}

View file

@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
/**
* @author Christoph Wurst <christoph@owncloud.com>
*
* @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\TwoFactorAuth;
use OCP\Template;
/**
* Interface IPersonalProviderSettings
*
* @since 15.0.0
*/
interface IPersonalProviderSettings {
/**
* @return Template
*
* @since 15.0.0
*/
public function getBody(): Template;
}

View file

@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
/**
* @author Christoph Wurst <christoph@owncloud.com>
*
* @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\TwoFactorAuth;
use OCP\IUser;
/**
* Interface for admins that have personal settings. These settings will be shown in the
* security sections. Some information like the display name of the provider is read
* from the provider directly.
*
* @since 15.0.0
*/
interface IProvidesPersonalSettings extends IProvider {
/**
* @param IUser $user
*
* @return IPersonalProviderSettings
*
* @since 15.0.0
*/
public function getPersonalSettings(IUser $user): IPersonalProviderSettings;
}

View file

@ -471,6 +471,27 @@ table.nostyle {
}
}
/* Two-Factor Authentication (2FA) */
#two-factor-auth {
h3 {
margin-top: 24px;
}
li > div {
margin-left: 20px;
}
.two-factor-provider-settings-icon {
width: 16px;
height: 16px;
vertical-align: sub;
}
}
#new-app-login-name,
#new-app-password {
width: 245px;

View file

@ -101,3 +101,38 @@ if($_['passwordChangeSupported']) {
</div>
</div>
</div>
<div id="two-factor-auth" class="section">
<h2><?php p($l->t('Two-Factor Authentication'));?></h2>
<p class="settings-hint">
<?php
if ($_['twoFactorProviderData']['enabled']) {
p($l->t('Two-factor authentication is enabled on your account.'));
} else {
p($l->t('Two-factor authentication is disabled on your account.'));
}
?>
</p>
<ul>
<?php foreach ($_['twoFactorProviderData']['providers'] as $data) { ?>
<li>
<?php
/** @var \OCP\Authentication\TwoFactorAuth\IProvidesPersonalSettings $provider */
$provider = $data['provider'];
if ($provider instanceof \OCP\Authentication\TwoFactorAuth\IProvidesIcons) {
$icon = $provider->getDarkIcon();
} else {
$icon = image_path('core', 'actions/password.svg');
}
/** @var \OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings $settings */
$settings = $data['settings'];
?>
<h3>
<img class="two-factor-provider-settings-icon" src="<?php p($icon) ?>" alt="">
<?php p($provider->getDisplayName()) ?>
</h3>
<?php print_unescaped($settings->getBody()->fetchPage()) ?>
</li>
<?php } ?>
</ul>
</div>