123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- <?php
- namespace App\Http\Controllers\Auth;
- use App\Extensions\WebauthnCredentialBroker;
- use App\Facades\Settings;
- use App\Http\Controllers\Controller;
- use App\Http\Requests\WebauthnRecoveryRequest;
- use Illuminate\Auth\AuthenticationException;
- use Illuminate\Foundation\Auth\ResetsPasswords;
- use Illuminate\Http\JsonResponse;
- use Illuminate\Http\Request;
- use Illuminate\Support\Facades\Auth;
- use Illuminate\Support\Facades\Password;
- use Illuminate\Validation\ValidationException;
- class WebAuthnRecoveryController extends Controller
- {
- use ResetsPasswords;
- /**
- * Let the user regain access to his account using email+password by resetting
- * the "use webauthn only" setting.
- *
- * @param \App\Http\Requests\WebauthnRecoveryRequest $request
- * @param \App\Extensions\WebauthnCredentialBroker $broker
- * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
- *
- * @throws \Illuminate\Validation\ValidationException
- */
- public function recover(WebauthnRecoveryRequest $request, WebauthnCredentialBroker $broker)
- {
- $credentials = $request->validated();
- $response = $broker->reset(
- $credentials,
- function ($user) use ($request) {
- // At this time, the WebAuthnUserProvider is already registered in the Laravel Service Container,
- // with a password_fallback value set using the useWebauthnOnly user setting (see AuthServiceProvider.php).
- // To ensure user login with email+pwd credentials, we replace the registered WebAuthnUserProvider instance
- // with a new instance configured with password_fallback On.
- $provider = new \Laragear\WebAuthn\Auth\WebAuthnUserProvider(
- app()->make('hash'),
- \App\Models\User::class,
- app()->make(\Laragear\WebAuthn\Assertion\Validator\AssertionValidator::class),
- true,
- );
- Auth::guard()->setProvider($provider);
- if (Auth::attempt($request->only('email', 'password'))) {
- if ($this->shouldRevokeAllCredentials($request)) {
- $user->flushCredentials();
- }
- Settings::delete('useWebauthnOnly');
- } else {
- throw new AuthenticationException();
- }
- }
- );
- return $response === Password::PASSWORD_RESET
- ? $this->sendRecoveryResponse($request, $response)
- : $this->sendRecoveryFailedResponse($request, $response);
- }
- /**
- * Check if the user has set to revoke all credentials.
- *
- * @param \App\Http\Requests\WebauthnRecoveryRequest $request
- * @return bool|mixed
- */
- protected function shouldRevokeAllCredentials(WebauthnRecoveryRequest $request) : mixed
- {
- return filter_var($request->header('WebAuthn-Unique'), FILTER_VALIDATE_BOOLEAN)
- ?: $request->input('revokeAll', true);
- }
- /**
- * Get the response for a successful account recovery.
- *
- * @param \Illuminate\Http\Request $request
- * @param string $response
- * @return \Illuminate\Http\JsonResponse
- */
- protected function sendRecoveryResponse(Request $request, string $response) : JsonResponse
- {
- return response()->json(['message' => __('auth.webauthn.webauthn_login_disabled')]);
- }
- /**
- * Get the response for a failed account recovery.
- *
- * @param \Illuminate\Http\Request $request
- * @param string $response
- * @return \Illuminate\Http\JsonResponse
- *
- * @throws \Illuminate\Validation\ValidationException
- */
- protected function sendRecoveryFailedResponse(Request $request, string $response) : JsonResponse
- {
- switch ($response) {
- case Password::INVALID_TOKEN:
- throw ValidationException::withMessages(['token' => [__('auth.webauthn.invalid_reset_token')]]);
- default:
- throw ValidationException::withMessages(['email' => [trans($response)]]);
- }
- }
- }
|