Replace the useWebauthnAsDefault option by a client side form toggle

This commit is contained in:
Bubka 2023-03-15 14:44:51 +01:00
parent f359a1ade3
commit 4d8180a8c1
10 changed files with 30 additions and 24 deletions

View File

@ -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');
}

View File

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

View File

@ -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');

View File

@ -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 })

View File

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

View File

@ -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
*/

View File

@ -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') })

View File

@ -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',

View File

@ -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'];

View File

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