فهرست منبع

Replace the useWebauthnAsDefault option by a client side form toggle

Bubka 2 سال پیش
والد
کامیت
4d8180a8c1

+ 0 - 1
app/Http/Controllers/Auth/WebAuthnManageController.php

@@ -58,7 +58,6 @@ class WebAuthnManageController extends Controller
         // no more registered device exists.
         // See #110
         if (blank($user->webAuthnCredentials()->WhereEnabled()->get())) {
-            Settings::delete('useWebauthnAsDefault');
             Settings::delete('useWebauthnOnly');
             Log::notice('No Webauthn credential enabled, Webauthn settings reset to default');
         }

+ 0 - 1
config/2fauth.php

@@ -80,7 +80,6 @@ return [
         'defaultGroup' => 0,
         'defaultCaptureMode' => 'livescan',
         'useDirectCapture' => false,
-        'useWebauthnAsDefault' => false,
         'useWebauthnOnly' => false,
         'getOfficialIcons' => true,
         'theme' => 'system',

+ 5 - 0
database/migrations/2023_02_10_145413_add_is_admin_and_preferences_to_users_table.php

@@ -24,6 +24,11 @@ return new class extends Migration
 
         DB::table('users')->update(['is_admin' => 1]);
 
+        // The 'useWebauthnAsDefault' option is replaced by a local storage record
+        // so we delete it form the Options table to prevent its conversion to
+        // a user preference
+        DB::table('options')->where('key', 'useWebauthnAsDefault')->delete();
+
         // User options are converted as user preferences
         $options     = DB::table('options')->get();
         $preferences = config('2fauth.preferences');

+ 7 - 1
resources/js/mixins.js

@@ -20,11 +20,17 @@ Vue.mixin({
             }
             else {
                 await this.axios.get('/user/logout')
-                this.$storage.clear()
+                this.clearStorage()
                 this.$router.push({ name: 'login', params: { forceRefresh: true } })
             }
         },
 
+        clearStorage() {
+            this.$storage.set('accounts')
+            this.$storage.set('groups')
+            this.$storage.set('lastRoute')
+        },
+
         exitSettings: function (event) {
             if (event) {
                 this.$notify({ clean: true })

+ 1 - 1
resources/js/views/auth/Autolock.vue

@@ -21,7 +21,7 @@
                 // there is nothing to do, we simply catch the error to avoid redondant navigation
             });
             
-            this.$storage.clear()
+            this.clearStorage()
         },
     }
 </script>

+ 13 - 4
resources/js/views/auth/Login.vue

@@ -12,7 +12,7 @@
             <div class="nav-links">
                 <p>{{ $t('auth.webauthn.lost_your_device') }}&nbsp;<router-link id="lnkRecoverAccount" :to="{ name: 'webauthn.lost' }" class="is-link">{{ $t('auth.webauthn.recover_your_account') }}</router-link></p>
                 <p v-if="!this.$root.userPreferences.useWebauthnOnly">{{ $t('auth.sign_in_using') }}&nbsp;
-                    <a id="lnkSignWithLegacy" role="button" class="is-link" @keyup.enter="showWebauthn = false" @click="showWebauthn = false" tabindex="0">{{ $t('auth.login_and_password') }}</a>
+                    <a id="lnkSignWithLegacy" role="button" class="is-link" @keyup.enter="toggleForm" @click="toggleForm" tabindex="0">{{ $t('auth.login_and_password') }}</a>
                 </p>
             </div>
         </form-wrapper>
@@ -28,7 +28,7 @@
             <div class="nav-links">
                 <p>{{ $t('auth.forms.forgot_your_password') }}&nbsp;<router-link id="lnkResetPwd" :to="{ name: 'password.request' }" class="is-link" :aria-label="$t('auth.forms.reset_your_password')">{{ $t('auth.forms.request_password_reset') }}</router-link></p>
                 <p >{{ $t('auth.sign_in_using') }}&nbsp;
-                    <a id="lnkSignWithWebauthn" role="button" class="is-link" @keyup.enter="showWebauthn = true" @click="showWebauthn = true" tabindex="0" :aria-label="$t('auth.sign_in_using_security_device')">{{ $t('auth.webauthn.security_device') }}</a>
+                    <a id="lnkSignWithWebauthn" role="button" class="is-link" @keyup.enter="toggleForm" @click="toggleForm" tabindex="0" :aria-label="$t('auth.sign_in_using_security_device')">{{ $t('auth.webauthn.security_device') }}</a>
                 </p>
                 <p class="mt-4">{{ $t('auth.forms.dont_have_account_yet') }}&nbsp;<router-link id="lnkRegister" :to="{ name: 'register' }" class="is-link">{{ $t('auth.register') }}</router-link></p>
             </div>
@@ -53,17 +53,26 @@
                     password: ''
                 }),
                 isBusy: false,
-                showWebauthn: this.$root.userPreferences.useWebauthnAsDefault || this.$root.userPreferences.useWebauthnOnly,
+                showWebauthn: this.$root.userPreferences.useWebauthnOnly,
                 csrfRefresher: null,
                 webauthn: new WebAuthn()
             }
         },
 
         mounted: function() {
-            this.csrfRefresher = setInterval(this.refreshToken, 300000); // 5 min
+            this.csrfRefresher = setInterval(this.refreshToken, 300000) // 5 min
+            this.showWebauthn = this.$storage.get('showWebauthnForm', false)
         },
 
         methods : {
+            /**
+             * Toggle the form between legacy and webauthn method
+             */
+            toggleForm() {
+                this.showWebauthn = ! this.showWebauthn
+                this.$storage.set('showWebauthnForm', this.showWebauthn)
+            },
+
             /**
              * Sign in using the login/password form
              */

+ 0 - 5
resources/js/views/settings/WebAuthn.vue

@@ -42,8 +42,6 @@
                 <form>
                     <!-- use webauthn only -->
                     <form-checkbox v-on:useWebauthnOnly="savePreference('useWebauthnOnly', $event)" :form="form" fieldName="useWebauthnOnly" :label="$t('auth.webauthn.use_webauthn_only.label')" :help="$t('auth.webauthn.use_webauthn_only.help')" :disabled="isRemoteUser || credentials.length === 0" />
-                    <!-- default sign in method -->
-                    <form-checkbox v-on:useWebauthnAsDefault="savePreference('useWebauthnAsDefault', $event)" :form="form" fieldName="useWebauthnAsDefault" :label="$t('auth.webauthn.use_webauthn_as_default.label')" :help="$t('auth.webauthn.use_webauthn_as_default.help')" :disabled="isRemoteUser || credentials.length === 0" />
                 </form>
                 <!-- footer -->
                 <vue-footer :showButtons="true">
@@ -67,7 +65,6 @@
             return {
                 form: new Form({
                     useWebauthnOnly: null,
-                    useWebauthnAsDefault: null,
                 }),
                 credentials: [],
                 isFetching: false,
@@ -193,9 +190,7 @@
 
                         if (this.credentials.length == 0) {
                             this.form.useWebauthnOnly = false
-                            this.form.useWebauthnAsDefault = false
                             this.$root.userPreferences['useWebauthnOnly'] = false
-                            this.$root.userPreferences['useWebauthnAsDefault'] = false
                         }
 
                         this.$notify({ type: 'is-success', text: this.$t('auth.webauthn.device_revoked') })

+ 4 - 8
resources/lang/en/auth.php

@@ -68,15 +68,11 @@ return [
         'unknown_device' => 'Unknown device',
         'use_webauthn_only' => [
             'label' => 'Use WebAuthn only',
-            'help' => 'Make WebAuthn the only available method to sign in 2FAuth. This is the recommended setup to take advantage of the WebAuthn enhanced security.<br />
-                In case of device lost, you will be able to recover your account by resetting this option and signing in using your email and password.'
-        ],
-        'need_a_security_device_to_enable_options' => 'Set at least one device to enable these options',
-        'use_webauthn_as_default' => [
-            'label' => 'Use WebAuthn as default sign in method',
-            'help' => 'Set the 2FAuth sign in form to propose the WebAuthn authentication at first. The Login/password method is then available as an alternative/fallback solution.<br />
-                This has no effect if you only use WebAuthn.'
+            'help' => 'Make WebAuthn the only authorized method to log into your 2FAuth account. This is the recommended setup to take advantage of the WebAuthn enhanced security.<br /><br />
+                In case of device lost, you will be able to recover your account by resetting this option and signing in using your email and password.<br /><br />
+                Attention! The Email & Password form remains available despite this option being enabled, but it will always return an \'Authentication failed\' response.'
         ],
+        'need_a_security_device_to_enable_options' => 'Set at least one device to enable the following options',
     ],
     'forms' => [
         'name' => 'Name',

+ 0 - 2
tests/Api/v1/Controllers/Auth/UserControllerTest.php

@@ -95,7 +95,6 @@ class UserControllerTest extends FeatureTestCase
             'defaultGroup'         => 1,
             'defaultCaptureMode'   => 'advancedForm',
             'useDirectCapture'     => true,
-            'useWebauthnAsDefault' => true,
             'useWebauthnOnly'      => true,
             'getOfficialIcons'     => false,
             'theme'                => 'dark',
@@ -116,7 +115,6 @@ class UserControllerTest extends FeatureTestCase
         $this->user['preferences->defaultGroup']         = $userPrefs['defaultGroup'];
         $this->user['preferences->defaultCaptureMode']   = $userPrefs['defaultCaptureMode'];
         $this->user['preferences->useDirectCapture']     = $userPrefs['useDirectCapture'];
-        $this->user['preferences->useWebauthnAsDefault'] = $userPrefs['useWebauthnAsDefault'];
         $this->user['preferences->useWebauthnOnly']      = $userPrefs['useWebauthnOnly'];
         $this->user['preferences->getOfficialIcons']     = $userPrefs['getOfficialIcons'];
         $this->user['preferences->theme']                = $userPrefs['theme'];

+ 0 - 1
tests/Feature/Http/SystemControllerTest.php

@@ -81,7 +81,6 @@ class SystemControllerTest extends FeatureTestCase
                     'defaultGroup',
                     'defaultCaptureMode',
                     'useDirectCapture',
-                    'useWebauthnAsDefault',
                     'useWebauthnOnly',
                     'getOfficialIcons',
                     'lang',