mirror of
https://github.com/Bubka/2FAuth.git
synced 2025-04-27 19:08:39 +02:00
Let the WebAuthn form log in any user
This commit is contained in:
parent
90f322f3b1
commit
5c83e17752
@ -71,8 +71,10 @@ public function login(LoginRequest $request)
|
|||||||
*/
|
*/
|
||||||
public function logout(Request $request)
|
public function logout(Request $request)
|
||||||
{
|
{
|
||||||
|
$user = $request->user();
|
||||||
Auth::logout();
|
Auth::logout();
|
||||||
Log::info('User logged out');
|
|
||||||
|
Log::info(sprintf('User id #%s logged out', $user->id));
|
||||||
|
|
||||||
return response()->json(['message' => 'signed out'], Response::HTTP_OK);
|
return response()->json(['message' => 'signed out'], Response::HTTP_OK);
|
||||||
}
|
}
|
||||||
@ -151,6 +153,6 @@ protected function authenticated(Request $request, $user)
|
|||||||
$user->last_seen_at = Carbon::now()->format('Y-m-d H:i:s');
|
$user->last_seen_at = Carbon::now()->format('Y-m-d H:i:s');
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
Log::info('User authenticated');
|
Log::info(sprintf('User id #%s authenticated using login & pwd', $user->id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,16 +43,13 @@ public function options(AssertionRequest $request) : Responsable|JsonResponse
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since 2FAuth is single user designed we fetch the user instance.
|
return $request->toVerify($request->validate([
|
||||||
// This lets Larapass validate the request without the need to ask
|
'email' => [
|
||||||
// the visitor for an email address.
|
'required',
|
||||||
$user = User::first();
|
'email',
|
||||||
|
new \App\Rules\CaseInsensitiveEmailExists
|
||||||
return $user
|
]
|
||||||
? $request->toVerify($user)
|
]));
|
||||||
: response()->json([
|
|
||||||
'message' => 'no registered user',
|
|
||||||
], 400);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,7 +66,7 @@ public function login(AssertedRequest $request)
|
|||||||
$response = $request->response;
|
$response = $request->response;
|
||||||
|
|
||||||
// Some authenticators do not send a userHandle so we hack the response to be compliant
|
// Some authenticators do not send a userHandle so we hack the response to be compliant
|
||||||
// with Larapass/webauthn-lib implementation that waits for a userHandle
|
// with Laragear\WebAuthn implementation that waits for a userHandle
|
||||||
if (! Arr::exists($response, 'userHandle') || blank($response['userHandle'])) {
|
if (! Arr::exists($response, 'userHandle') || blank($response['userHandle'])) {
|
||||||
$response['userHandle'] = User::getFromCredentialId($request->id)?->userHandle();
|
$response['userHandle'] = User::getFromCredentialId($request->id)?->userHandle();
|
||||||
$request->merge(['response' => $response]);
|
$request->merge(['response' => $response]);
|
||||||
@ -98,6 +95,6 @@ protected function authenticated($user)
|
|||||||
$user->last_seen_at = Carbon::now()->format('Y-m-d H:i:s');
|
$user->last_seen_at = Carbon::now()->format('Y-m-d H:i:s');
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
Log::info('User authenticated via webauthn');
|
Log::info(sprintf('User id #%s authenticated using webauthn', $user->id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,10 @@
|
|||||||
<div class="field">
|
<div class="field">
|
||||||
{{ $t('auth.webauthn.use_security_device_to_sign_in') }}
|
{{ $t('auth.webauthn.use_security_device_to_sign_in') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<form id="frmWebauthnLogin" @submit.prevent="webauthnLogin" @keydown="form.onKeydown($event)">
|
||||||
<button id="btnContinue" type="button" class="button is-link" @click="webauthnLogin">{{ $t('commons.continue') }}</button>
|
<form-field :form="form" fieldName="email" inputType="email" :label="$t('auth.forms.email')" autofocus />
|
||||||
</div>
|
<form-buttons :isBusy="form.isBusy" :caption="$t('commons.continue')" :submitId="'btnContinue'"/>
|
||||||
|
</form>
|
||||||
<div class="nav-links">
|
<div class="nav-links">
|
||||||
<p>{{ $t('auth.webauthn.lost_your_device') }} <router-link id="lnkRecoverAccount" :to="{ name: 'webauthn.lost' }" class="is-link">{{ $t('auth.webauthn.recover_your_account') }}</router-link></p>
|
<p>{{ $t('auth.webauthn.lost_your_device') }} <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') }}
|
<p v-if="!this.$root.userPreferences.useWebauthnOnly">{{ $t('auth.sign_in_using') }}
|
||||||
@ -103,11 +104,26 @@
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const loginOptions = await this.axios.post('/webauthn/login/options').then(res => res.data)
|
const loginOptions = await this.form.post('/webauthn/login/options').then(res => res.data)
|
||||||
const publicKey = this.webauthn.parseIncomingServerOptions(loginOptions)
|
const publicKey = this.webauthn.parseIncomingServerOptions(loginOptions)
|
||||||
const credentials = await navigator.credentials.get({ publicKey: publicKey })
|
const credentials = await navigator.credentials.get({ publicKey: publicKey })
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.$notify({ type: 'is-danger', text: this.$t('auth.webauthn.unknown_device') })
|
if (error.name == 'AbortError') {
|
||||||
|
this.$notify({ type: 'is-warning', text: this.$t('errors.aborted_by_user') })
|
||||||
|
}
|
||||||
|
else if (error.name == 'SecurityError') {
|
||||||
|
this.$notify({ type: 'is-danger', text: this.$t('errors.security_error_check_rpid') })
|
||||||
|
}
|
||||||
|
else if (error.name == 'NotAllowedError') {
|
||||||
|
this.$notify({ type: 'is-danger', text: this.$t('errors.not_allowed_operation') })
|
||||||
|
}
|
||||||
|
else if (error.name == 'NotSupportedError') {
|
||||||
|
this.$notify({ type: 'is-danger', text: this.$t('errors.unsupported_operation') })
|
||||||
|
}
|
||||||
|
else if (error.name == 'InvalidStateError') {
|
||||||
|
this.$notify({ type: 'is-danger', text: this.$t('auth.webauthn.unknown_device') })
|
||||||
|
}
|
||||||
|
else this.$notify({ type: 'is-danger', text: this.$t('errors.unknown_error') })
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!credentials) return false
|
if (!credentials) return false
|
||||||
|
@ -167,6 +167,9 @@
|
|||||||
else if (error.name == 'NotAllowedError') {
|
else if (error.name == 'NotAllowedError') {
|
||||||
this.$notify({ type: 'is-danger', text: this.$t('errors.not_allowed_operation') })
|
this.$notify({ type: 'is-danger', text: this.$t('errors.not_allowed_operation') })
|
||||||
}
|
}
|
||||||
|
else if (error.name == 'NotSupportedError') {
|
||||||
|
this.$notify({ type: 'is-danger', text: this.$t('errors.unsupported_operation') })
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,8 @@
|
|||||||
'aborted_by_user' => 'Aborted by user',
|
'aborted_by_user' => 'Aborted by user',
|
||||||
'security_device_unsupported' => 'Unsupported or in use device',
|
'security_device_unsupported' => 'Unsupported or in use device',
|
||||||
'not_allowed_operation' => 'Operation not allowed',
|
'not_allowed_operation' => 'Operation not allowed',
|
||||||
|
'unsupported_operation' => 'Unsupported operation',
|
||||||
|
'unknown_error' => 'Unknown error',
|
||||||
'security_error_check_rpid' => 'Security error<br/>Check your WEBAUTHN_ID env var',
|
'security_error_check_rpid' => 'Security error<br/>Check your WEBAUTHN_ID env var',
|
||||||
'unsupported_with_reverseproxy' => 'Not applicable when using an auth proxy',
|
'unsupported_with_reverseproxy' => 'Not applicable when using an auth proxy',
|
||||||
'user_deletion_failed' => 'User account deletion failed, no data have been deleted',
|
'user_deletion_failed' => 'User account deletion failed, no data have been deleted',
|
||||||
|
Loading…
Reference in New Issue
Block a user