Skip to content

Commit

Permalink
Fixes #1630 - 2FA not working (#1691)
Browse files Browse the repository at this point in the history
  • Loading branch information
ildyria authored Jan 7, 2023
1 parent aeef2e0 commit ecef28a
Showing 1 changed file with 63 additions and 4 deletions.
67 changes: 63 additions & 4 deletions app/Http/Controllers/WebAuthn/WebAuthnLoginController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@

namespace App\Http\Controllers\WebAuthn;

use App\Exceptions\UnauthenticatedException;
use App\Models\User;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Contracts\Support\Responsable;
use Illuminate\Support\Facades\Auth;
use Laragear\WebAuthn\Assertion\Validator\AssertionValidation;
use Laragear\WebAuthn\Assertion\Validator\AssertionValidator;
use Laragear\WebAuthn\Http\Requests\AssertedRequest;
use Laragear\WebAuthn\Http\Requests\AssertionRequest;
use Symfony\Component\HttpFoundation\Response;
Expand All @@ -28,15 +33,69 @@ public function options(AssertionRequest $request): Responsable
/**
* Log the user in.
*
* 1. We retrieve the credentials candidate
* 2. Double check the challenge is signed.
* 3. Retrieve the User from the credential ID, we will use it to validate later (otherwise keys like yubikey4 are not working).
* 4. Validate the credentials
* 5. Log in on success
*
* @param AssertedRequest $request
*
* @return void
*/
public function login(AssertedRequest $request): void
public function login(AssertedRequest $request, AssertionValidator $validator): void
{
$user = $request->login();
if ($user === null) {
throw new HttpException(Response::HTTP_UNPROCESSABLE_ENTITY);
$credentials = $request->validated();

if (!$this->isSignedChallenge($credentials)) {
throw new HttpException(Response::HTTP_UNPROCESSABLE_ENTITY, 'Response is not signed.');
}
$associatedUser = $this->retrieveByCredentials($credentials);

if ($associatedUser === null) {
throw new HttpException(Response::HTTP_UNPROCESSABLE_ENTITY, 'Associated user does not exists.');
}

$credential = $validator
->send(new AssertionValidation($request, $associatedUser))
->thenReturn()
->credential;

if ($credential === null) {
throw new UnauthenticatedException('Invalid credentials');
}

/** @var \Illuminate\Contracts\Auth\Authenticatable $authenticatable */
$authenticatable = $credential->authenticatable;
Auth::login($authenticatable);
}

/**
* Check if the credentials are for a public key signed challenge.
*
* @param array $credentials
*
* @return bool
*/
private function isSignedChallenge(array $credentials): bool
{
return isset($credentials['id'], $credentials['rawId'], $credentials['response'], $credentials['type']);
}

/**
* Retrieve a user by the given credentials.
*
* @param array $credentials
*
* @return User|null
*/
public function retrieveByCredentials(array $credentials): User|null
{
/** @var User|null $user */
$user = User::whereHas('webAuthnCredentials',
fn ($query) => $query->whereKey($credentials['id'])->whereEnabled()
)->first();

return $user;
}
}

0 comments on commit ecef28a

Please sign in to comment.