From 79a0ee4f4ae315b357f51dd35d3d3c6e60897ee1 Mon Sep 17 00:00:00 2001 From: Christoph Wurst <christoph@winzerhof-wurst.at> Date: Wed, 26 Sep 2018 16:25:18 +0200 Subject: [PATCH] Consolidate personal two-factor provider settings Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at> --- apps/twofactor_backupcodes/js/settings.js | Bin 108962 -> 108980 bytes apps/twofactor_backupcodes/js/settings.js.map | Bin 542141 -> 542181 bytes .../lib/Provider/BackupCodesProvider.php | 15 ++++- .../lib/Settings/Personal.php | 63 +++--------------- .../src/views/PersonalSettings.vue | 6 +- .../templates/personal.php | 5 +- lib/private/Settings/Personal/Security.php | 52 +++++++++++++-- .../IPersonalProviderSettings.php | 43 ++++++++++++ .../IProvidesPersonalSettings.php | 47 +++++++++++++ settings/css/settings.scss | 20 ++++++ .../templates/settings/personal/security.php | 35 ++++++++++ 11 files changed, 220 insertions(+), 66 deletions(-) create mode 100644 lib/public/Authentication/TwoFactorAuth/IPersonalProviderSettings.php create mode 100644 lib/public/Authentication/TwoFactorAuth/IProvidesPersonalSettings.php diff --git a/apps/twofactor_backupcodes/js/settings.js b/apps/twofactor_backupcodes/js/settings.js index 0341dbf13a6bbccef68520adb9ed01448f462eeb..29252548de595cd6659c7844ed241a01134bbad7 100644 GIT binary patch delta 43 zcmZ2<nQhBuwuUW?F0(ll3W_pw6N@UhyUb=>%*2|fp_H0C{mER$p6z+_7)`hVf_D(S delta 42 zcmV+_0M-Ar(*~l`27t5yM4Puvn*pN&2xTr`b|@lTZkJ)40V<a%o&i_4f}Q~~3u$`~ AZvX%Q diff --git a/apps/twofactor_backupcodes/js/settings.js.map b/apps/twofactor_backupcodes/js/settings.js.map index 01fc5d81ea47cceed6b01dfae336d77be013bbd8..27b3318ff64a2ea40823d2de7e764ee97ffad3f2 100644 GIT binary patch delta 315 zcmdnnt@yNCaRYP0W}XB##%7tsc9}%R?J|i>Q>2(OowjeRX3}HgaMW>ibad45oqng5 z$(1?Pv1+<X9aAY|>GWB3Owx=6+qcy*^|7#dIy!nA7H<!1W|CoI1#v>R*R(PzGjmls z>j1f)8AVRh*LN_<aaUA1>3BOj=QtHQx8Lnx0%B$$W&vVWAZFWsw}X9VKZim=QD$yp zQRQ?;X%5-xX9YO8w$GK|*ul=0tP!J>nmhf2EQjdy`{Ep2(>I842v5&d;82?$AkU#O z{gxz$<n(h297fasDR3lDj~4-Q^~8WguOiSOAXj+$PDKvB?b{VORxt5qCFbeprB;+A v=j4~BOuy*BA+vpk3P+#--2Uw^O*mAUm~DVo@|trrFsJ6)ZSOYcFyaFMEC^>I delta 362 zcmYj}O-lk%6o&DR>5=@Hth7YMsg^@lWYY4^7$q$V`T;uVgyDpf<D?YXLPAR@TEwA< za@8s*h`1nxf1_oa_Wp!sYSZF5=jAys=esL>bcI(g?=f;kbyqR9+8dX5IXvRbp{eFn zW4{GT8x#ivh1^6OJM8h8%oF@PArhz12F9Aij2&!HF-x;_r6h@Kl+wB`i>kFnLy|T2 z(j=EopY1h0W8XI$Om2}V3H*1<dWIFx$SlX3W%>7uJ+iAt2Cq9L&Kp~Qa-GVWbd;3Z z{SL9<ESwf27B1HBxNooUf`>8eMZu5HJOIkf9mL@Tcv)`>?%X&CgBx=RyCZ-Xn+b^E zb`+fWkbr4B#c>#fCG-iPpdNuq91TI(F2`^nK!AM-@I=N7rRtthtLUX<y;3b3x>8Wt Z`5e@Fyib9jg;EeExR{1h_MV0X{|~EWas>bY diff --git a/apps/twofactor_backupcodes/lib/Provider/BackupCodesProvider.php b/apps/twofactor_backupcodes/lib/Provider/BackupCodesProvider.php index 03d1ee0d405..27653c1dd61 100644 --- a/apps/twofactor_backupcodes/lib/Provider/BackupCodesProvider.php +++ b/apps/twofactor_backupcodes/lib/Provider/BackupCodesProvider.php @@ -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(); + } + } + diff --git a/apps/twofactor_backupcodes/lib/Settings/Personal.php b/apps/twofactor_backupcodes/lib/Settings/Personal.php index eb28dacb42b..0b71b1da088 100644 --- a/apps/twofactor_backupcodes/lib/Settings/Personal.php +++ b/apps/twofactor_backupcodes/lib/Settings/Personal.php @@ -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; - -class Personal implements ISettings { - - /** @var Application */ - private $app; - /** @var BackupCodesProvider */ - private $provider; - /** @var IUserSession */ - private $userSession; +use OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings; +use OCP\Template; - public function __construct(Application $app, BackupCodesProvider $provider, IUserSession $userSession) { - $this->app = $app; - $this->provider = $provider; - $this->userSession = $userSession; - } - - /** - * @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'; - } +class Personal implements IPersonalProviderSettings { - return new TemplateResponse($templateOwner, $templateName, [], ''); + public function getBody(): Template { + return new Template('twofactor_backupcodes', 'personal'); } - /** - * @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; - } } diff --git a/apps/twofactor_backupcodes/src/views/PersonalSettings.vue b/apps/twofactor_backupcodes/src/views/PersonalSettings.vue index ac53de2e65c..fb4980abb59 100644 --- a/apps/twofactor_backupcodes/src/views/PersonalSettings.vue +++ b/apps/twofactor_backupcodes/src/views/PersonalSettings.vue @@ -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> diff --git a/apps/twofactor_backupcodes/templates/personal.php b/apps/twofactor_backupcodes/templates/personal.php index e440158f4cd..4c887aff915 100644 --- a/apps/twofactor_backupcodes/templates/personal.php +++ b/apps/twofactor_backupcodes/templates/personal.php @@ -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> diff --git a/lib/private/Settings/Personal/Security.php b/lib/private/Settings/Personal/Security.php index efcfd5589ce..0efe2d0746b 100644 --- a/lib/private/Settings/Personal/Security.php +++ b/lib/private/Settings/Personal/Security.php @@ -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; + })) + ]; + } } diff --git a/lib/public/Authentication/TwoFactorAuth/IPersonalProviderSettings.php b/lib/public/Authentication/TwoFactorAuth/IPersonalProviderSettings.php new file mode 100644 index 00000000000..80552d1fe8c --- /dev/null +++ b/lib/public/Authentication/TwoFactorAuth/IPersonalProviderSettings.php @@ -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; + +} diff --git a/lib/public/Authentication/TwoFactorAuth/IProvidesPersonalSettings.php b/lib/public/Authentication/TwoFactorAuth/IProvidesPersonalSettings.php new file mode 100644 index 00000000000..5ba7ad547e9 --- /dev/null +++ b/lib/public/Authentication/TwoFactorAuth/IProvidesPersonalSettings.php @@ -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; + +} diff --git a/settings/css/settings.scss b/settings/css/settings.scss index ae1a456b699..08baaed4cc6 100644 --- a/settings/css/settings.scss +++ b/settings/css/settings.scss @@ -471,6 +471,26 @@ 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; + } +} + + #new-app-login-name, #new-app-password { width: 245px; diff --git a/settings/templates/settings/personal/security.php b/settings/templates/settings/personal/security.php index 6dd0e8d3cef..6b2c37b6a88 100644 --- a/settings/templates/settings/personal/security.php +++ b/settings/templates/settings/personal/security.php @@ -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> -- GitLab