From 89d01e47a11d518ff8e490fad739d01d2c9c7cab Mon Sep 17 00:00:00 2001 From: Alexis Saettler Date: Mon, 4 Sep 2023 11:45:46 +0200 Subject: [PATCH] feat!: remove deprecated PublicKeyCredentialSourceRepository and refactor all signature methods --- .../2019_03_29_163611_add_webauthn.php | 12 +- src/Actions/AttemptToAuthenticate.php | 61 ++-------- src/Actions/DeleteKey.php | 4 - src/Actions/EnsureLoginIsNotThrottled.php | 24 +--- src/Actions/LoginUserRetrieval.php | 35 +----- src/Actions/PrepareAssertionData.php | 3 - src/Actions/PrepareAuthenticatedSession.php | 24 +--- src/Actions/PrepareCreationData.php | 9 +- src/Actions/UpdateKey.php | 4 - src/Actions/ValidateKeyCreation.php | 16 +-- src/Auth/EloquentWebAuthnProvider.php | 21 +--- src/Contracts/LoginViewResponse.php | 4 - src/Contracts/RegisterSuccessResponse.php | 4 - src/Contracts/RegisterViewResponse.php | 4 - src/Events/WebauthnLogin.php | 27 +---- src/Events/WebauthnLoginData.php | 27 +---- src/Events/WebauthnRegister.php | 16 +-- src/Events/WebauthnRegisterData.php | 27 +---- src/Events/WebauthnRegisterFailed.php | 27 +---- src/Facades/Webauthn.php | 4 +- .../Controllers/AuthenticateController.php | 16 +-- .../Controllers/WebauthnKeyController.php | 22 +--- src/Http/Middleware/WebauthnMiddleware.php | 26 +--- .../Requests/WebauthnLoginAttemptRequest.php | 4 +- src/Http/Requests/WebauthnLoginRequest.php | 4 +- src/Http/Requests/WebauthnRegisterRequest.php | 4 +- src/Http/Requests/WebauthnUpdateRequest.php | 4 +- src/Http/Responses/LockoutResponse.php | 17 +-- src/Http/Responses/LoginViewResponse.php | 6 - .../Responses/RegisterSuccessResponse.php | 9 -- src/Http/Responses/RegisterViewResponse.php | 6 - src/Listeners/LoginViaRemember.php | 7 +- src/Models/Casts/Base64.php | 20 +--- src/Models/Casts/TrustPath.php | 21 ++-- src/Models/Casts/Uuid.php | 20 +--- src/Models/WebauthnKey.php | 79 +++++++------ src/Services/LoginRateLimiter.php | 49 ++------ src/Services/Webauthn.php | 99 +++------------- .../Webauthn/CreationOptionsFactory.php | 45 ++----- .../Webauthn/CredentialAssertionValidator.php | 37 ++---- .../CredentialAttestationValidator.php | 37 ++---- .../Webauthn/CredentialRepository.php | 111 ++---------------- src/Services/Webauthn/CredentialValidator.php | 28 +---- src/Services/Webauthn/OptionsFactory.php | 26 +--- .../Webauthn/RequestOptionsFactory.php | 28 ++--- src/Services/WebauthnRepository.php | 17 +-- src/WebauthnAuthenticatable.php | 4 +- src/WebauthnServiceProvider.php | 36 ++---- .../AuthenticateControllerTest.php | 15 ++- .../Webauthn/CredentialRepositoryTest.php | 74 +++--------- tests/User.php | 2 +- 51 files changed, 252 insertions(+), 974 deletions(-) diff --git a/database/migrations/2019_03_29_163611_add_webauthn.php b/database/migrations/2019_03_29_163611_add_webauthn.php index 6c2ef703..1b47b6f5 100644 --- a/database/migrations/2019_03_29_163611_add_webauthn.php +++ b/database/migrations/2019_03_29_163611_add_webauthn.php @@ -6,14 +6,12 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class AddWebauthn extends Migration +return new class() extends Migration { /** * Run the migrations. - * - * @return void */ - public function up() + public function up(): void { Schema::create('webauthn_keys', function (Blueprint $table) { $table->id(); @@ -42,11 +40,9 @@ public function up() /** * Reverse the migrations. - * - * @return void */ - public function down() + public function down(): void { Schema::dropIfExists('webauthn_keys'); } -} +}; diff --git a/src/Actions/AttemptToAuthenticate.php b/src/Actions/AttemptToAuthenticate.php index ac16c222..b2648a5b 100644 --- a/src/Actions/AttemptToAuthenticate.php +++ b/src/Actions/AttemptToAuthenticate.php @@ -2,6 +2,7 @@ namespace LaravelWebauthn\Actions; +use Closure; use Illuminate\Auth\Events\Failed; use Illuminate\Contracts\Auth\Authenticatable as User; use Illuminate\Contracts\Auth\StatefulGuard; @@ -13,41 +14,18 @@ class AttemptToAuthenticate { - /** - * The guard implementation. - * - * @var \Illuminate\Contracts\Auth\StatefulGuard - */ - protected StatefulGuard $guard; - - /** - * The login rate limiter instance. - * - * @var \LaravelWebauthn\Services\LoginRateLimiter - */ - protected LoginRateLimiter $limiter; - /** * Create a new controller instance. - * - * @param \Illuminate\Contracts\Auth\StatefulGuard $guard - * @param \LaravelWebauthn\Services\LoginRateLimiter $limiter - * @return void */ - public function __construct(StatefulGuard $guard, LoginRateLimiter $limiter) - { - $this->guard = $guard; - $this->limiter = $limiter; - } + public function __construct( + protected StatefulGuard $guard, + protected LoginRateLimiter $limiter + ) { } /** * Handle the incoming request. - * - * @param \Illuminate\Http\Request $request - * @param callable $next - * @return mixed */ - public function handle(Request $request, $next) + public function handle(Request $request, Closure $next): mixed { if (Webauthn::$authenticateUsingCallback !== null) { return $this->handleUsingCustomCallback($request, $next); @@ -65,10 +43,6 @@ public function handle(Request $request, $next) /** * Attempt to log the user into the application. - * - * @param array $challenge - * @param bool $remember - * @return bool */ protected function attemptLogin(array $challenge, bool $remember = false): bool { @@ -77,9 +51,6 @@ protected function attemptLogin(array $challenge, bool $remember = false): bool /** * Attempt to validate assertion for authenticated user. - * - * @param \Illuminate\Http\Request $request - * @return bool */ protected function attemptValidateAssertion(Request $request): bool { @@ -104,12 +75,8 @@ protected function attemptValidateAssertion(Request $request): bool /** * Attempt to authenticate using a custom callback. - * - * @param \Illuminate\Http\Request $request - * @param callable $next - * @return mixed */ - protected function handleUsingCustomCallback(Request $request, $next) + protected function handleUsingCustomCallback(Request $request, callable $next): mixed { $user = Webauthn::$authenticateUsingCallback !== null ? call_user_func(Webauthn::$authenticateUsingCallback, $request) @@ -131,12 +98,9 @@ protected function handleUsingCustomCallback(Request $request, $next) /** * Throw a failed authentication validation exception. * - * @param \Illuminate\Http\Request $request - * @return void - * * @throws \Illuminate\Validation\ValidationException */ - protected function throwFailedAuthenticationException(Request $request) + protected function throwFailedAuthenticationException(Request $request): void { $this->limiter->increment($request); @@ -147,12 +111,8 @@ protected function throwFailedAuthenticationException(Request $request) /** * Fire the failed authentication attempt event with the given arguments. - * - * @param \Illuminate\Http\Request $request - * @param \Illuminate\Contracts\Auth\Authenticatable|null $user - * @return void */ - protected function fireFailedEvent(Request $request, ?User $user = null) + protected function fireFailedEvent(Request $request, ?User $user = null): void { event(new Failed(config('webauthn.guard'), $user, [ Webauthn::username() => $user !== null @@ -163,9 +123,6 @@ protected function fireFailedEvent(Request $request, ?User $user = null) /** * Get array of webauthn credentials. - * - * @param \Illuminate\Http\Request $request - * @return array */ protected function filterCredentials(Request $request): array { diff --git a/src/Actions/DeleteKey.php b/src/Actions/DeleteKey.php index f43c09ea..2758e2f6 100644 --- a/src/Actions/DeleteKey.php +++ b/src/Actions/DeleteKey.php @@ -9,10 +9,6 @@ class DeleteKey { /** * Delete a key. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param int $webauthnKeyId - * @return void */ public function __invoke(User $user, int $webauthnKeyId): void { diff --git a/src/Actions/EnsureLoginIsNotThrottled.php b/src/Actions/EnsureLoginIsNotThrottled.php index 09e809f5..f273eb89 100644 --- a/src/Actions/EnsureLoginIsNotThrottled.php +++ b/src/Actions/EnsureLoginIsNotThrottled.php @@ -2,6 +2,7 @@ namespace LaravelWebauthn\Actions; +use Closure; use Illuminate\Auth\Events\Lockout; use Illuminate\Http\Request; use LaravelWebauthn\Contracts\LockoutResponse; @@ -9,32 +10,17 @@ class EnsureLoginIsNotThrottled { - /** - * The login rate limiter instance. - * - * @var \LaravelWebauthn\Services\LoginRateLimiter - */ - protected LoginRateLimiter $limiter; - /** * Create a new class instance. - * - * @param \LaravelWebauthn\Services\LoginRateLimiter $limiter - * @return void */ - public function __construct(LoginRateLimiter $limiter) - { - $this->limiter = $limiter; - } + public function __construct( + protected LoginRateLimiter $limiter + ) { } /** * Handle the incoming request. - * - * @param \Illuminate\Http\Request $request - * @param callable $next - * @return mixed */ - public function handle(Request $request, $next) + public function handle(Request $request, Closure $next): mixed { if (! $this->limiter->tooManyAttempts($request)) { return $next($request); diff --git a/src/Actions/LoginUserRetrieval.php b/src/Actions/LoginUserRetrieval.php index 72b9cab5..2a6acc76 100644 --- a/src/Actions/LoginUserRetrieval.php +++ b/src/Actions/LoginUserRetrieval.php @@ -13,29 +13,15 @@ class LoginUserRetrieval { - /** - * The login rate limiter instance. - * - * @var \LaravelWebauthn\Services\LoginRateLimiter - */ - protected LoginRateLimiter $limiter; - /** * Create a new controller instance. - * - * @param \LaravelWebauthn\Services\LoginRateLimiter $limiter - * @return void */ - public function __construct(LoginRateLimiter $limiter) - { - $this->limiter = $limiter; - } + public function __construct( + protected LoginRateLimiter $limiter + ) { } /** * Handle the incoming request. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Contracts\Auth\Authenticatable|null */ public function __invoke(Request $request): ?User { @@ -54,9 +40,6 @@ public function __invoke(Request $request): ?User /** * Return the user that should authenticate via WebAuthn. - * - * @param array|null $credentials - * @return \Illuminate\Contracts\Auth\Authenticatable|null */ protected function getUserFromCredentials(?array $credentials): ?User { @@ -73,8 +56,6 @@ protected function getUserFromCredentials(?array $credentials): ?User /** * Get the User Provider for WebAuthn Authenticatable users. - * - * @return \Illuminate\Contracts\Auth\UserProvider|null */ protected function userProvider(): ?UserProvider { @@ -84,12 +65,9 @@ protected function userProvider(): ?UserProvider /** * Throw a failed authentication validation exception. * - * @param \Illuminate\Http\Request $request - * @return void - * * @throws \Illuminate\Validation\ValidationException */ - protected function throwFailedAuthenticationException(Request $request) + protected function throwFailedAuthenticationException(Request $request): void { $this->limiter->increment($request); @@ -100,11 +78,8 @@ protected function throwFailedAuthenticationException(Request $request) /** * Fire the failed authentication attempt event with the given arguments. - * - * @param \Illuminate\Http\Request $request - * @return void */ - protected function fireFailedEvent(Request $request) + protected function fireFailedEvent(Request $request): void { event(new Failed(config('webauthn.guard'), null, [ Webauthn::username() => $request->{Webauthn::username()}, diff --git a/src/Actions/PrepareAssertionData.php b/src/Actions/PrepareAssertionData.php index 4c33fe62..d5a27bf6 100644 --- a/src/Actions/PrepareAssertionData.php +++ b/src/Actions/PrepareAssertionData.php @@ -10,9 +10,6 @@ class PrepareAssertionData { /** * Get data to authenticate a user. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @return PublicKeyCredentialRequestOptions */ public function __invoke(User $user): PublicKeyCredentialRequestOptions { diff --git a/src/Actions/PrepareAuthenticatedSession.php b/src/Actions/PrepareAuthenticatedSession.php index 37a59b04..c0cc8a74 100644 --- a/src/Actions/PrepareAuthenticatedSession.php +++ b/src/Actions/PrepareAuthenticatedSession.php @@ -2,37 +2,23 @@ namespace LaravelWebauthn\Actions; +use Closure; use Illuminate\Http\Request; use LaravelWebauthn\Services\LoginRateLimiter; class PrepareAuthenticatedSession { - /** - * The login rate limiter instance. - * - * @var \LaravelWebauthn\Services\LoginRateLimiter - */ - protected LoginRateLimiter $limiter; - /** * Create a new class instance. - * - * @param \LaravelWebauthn\Services\LoginRateLimiter $limiter - * @return void */ - public function __construct(LoginRateLimiter $limiter) - { - $this->limiter = $limiter; - } + public function __construct( + protected LoginRateLimiter $limiter + ) { } /** * Handle the incoming request. - * - * @param \Illuminate\Http\Request $request - * @param callable $next - * @return mixed */ - public function handle(Request $request, $next) + public function handle(Request $request, Closure $next): mixed { $request->session()->regenerate(); diff --git a/src/Actions/PrepareCreationData.php b/src/Actions/PrepareCreationData.php index 056c4489..c20b0d03 100644 --- a/src/Actions/PrepareCreationData.php +++ b/src/Actions/PrepareCreationData.php @@ -13,9 +13,6 @@ class PrepareCreationData { /** * Get data to register a new key. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @return PublicKeyCredentialCreationOptions */ public function __invoke(User $user): PublicKeyCredentialCreationOptions { @@ -29,13 +26,9 @@ public function __invoke(User $user): PublicKeyCredentialCreationOptions /** * Throw a failed register validation exception. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param Exception|null $e - * @return void - * * @throws \Illuminate\Validation\ValidationException */ - protected function throwFailedRegisterException(User $user, ?Exception $e = null) + protected function throwFailedRegisterException(User $user, ?Exception $e = null): void { WebauthnRegisterFailed::dispatch($user, $e); diff --git a/src/Actions/UpdateKey.php b/src/Actions/UpdateKey.php index 4dd35a6e..cad69238 100644 --- a/src/Actions/UpdateKey.php +++ b/src/Actions/UpdateKey.php @@ -10,10 +10,6 @@ class UpdateKey { /** * Update a key. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param int $webauthnKeyId - * @return \Illuminate\Database\Eloquent\Model */ public function __invoke(User $user, int $webauthnKeyId, string $keyName): Model { diff --git a/src/Actions/ValidateKeyCreation.php b/src/Actions/ValidateKeyCreation.php index 6b283755..8d0423bf 100644 --- a/src/Actions/ValidateKeyCreation.php +++ b/src/Actions/ValidateKeyCreation.php @@ -13,11 +13,6 @@ class ValidateKeyCreation { /** * Register a new key. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param array $data - * @param string $keyName - * @return \Illuminate\Database\Eloquent\Model|null */ public function __invoke(User $user, array $data, string $keyName): ?Model { @@ -33,11 +28,6 @@ public function __invoke(User $user, array $data, string $keyName): ?Model /** * Validate key. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param array $data - * @param string $keyName - * @return \Illuminate\Database\Eloquent\Model|null */ protected function validateAttestation(User $user, array $data, string $keyName): ?Model { @@ -53,13 +43,9 @@ protected function validateAttestation(User $user, array $data, string $keyName) /** * Throw a failed register validation exception. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param \Exception|null $e - * @return void - * * @throws \Illuminate\Validation\ValidationException */ - protected function throwFailedRegisterException(User $user, ?Exception $e = null) + protected function throwFailedRegisterException(User $user, ?Exception $e = null): void { WebauthnRegisterFailed::dispatch($user, $e); diff --git a/src/Auth/EloquentWebAuthnProvider.php b/src/Auth/EloquentWebAuthnProvider.php index f73010b2..1cb0f3cd 100644 --- a/src/Auth/EloquentWebAuthnProvider.php +++ b/src/Auth/EloquentWebAuthnProvider.php @@ -17,25 +17,16 @@ class EloquentWebAuthnProvider extends EloquentUserProvider { /** * If it should fallback to password credentials whenever possible. - * - * @var bool */ protected bool $fallback; /** * WebAuthn assertion validator. - * - * @var CredentialAssertionValidator */ protected CredentialAssertionValidator $validator; /** * Create a new database user provider. - * - * @param \Illuminate\Contracts\Config\Repository $config - * @param CredentialAssertionValidator $validator - * @param \Illuminate\Contracts\Hashing\Hasher $hasher - * @param string $model */ public function __construct(Config $config, CredentialAssertionValidator $validator, Hasher $hasher, string $model) { @@ -47,11 +38,8 @@ public function __construct(Config $config, CredentialAssertionValidator $valida /** * Retrieve a user by the given credentials. - * - * @param array $credentials - * @return \Illuminate\Contracts\Auth\Authenticatable|null */ - public function retrieveByCredentials(array $credentials) + public function retrieveByCredentials(array $credentials): ?User { if ($this->isSignedChallenge($credentials)) { try { @@ -70,9 +58,6 @@ public function retrieveByCredentials(array $credentials) /** * Check if the credentials are for a public key signed challenge. - * - * @param array $credentials - * @return bool */ protected function isSignedChallenge(array $credentials): bool { @@ -81,10 +66,6 @@ protected function isSignedChallenge(array $credentials): bool /** * Validate a user against the given credentials. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param array $credentials - * @return bool */ public function validateCredentials(User $user, array $credentials): bool { diff --git a/src/Contracts/LoginViewResponse.php b/src/Contracts/LoginViewResponse.php index 31f1fc73..55fa3f4c 100644 --- a/src/Contracts/LoginViewResponse.php +++ b/src/Contracts/LoginViewResponse.php @@ -10,10 +10,6 @@ interface LoginViewResponse extends Responsable { /** * Set public key request data. - * - * @param \Illuminate\Http\Request $request - * @param \Webauthn\PublicKeyCredentialRequestOptions $publicKey - * @return self */ public function setPublicKey(Request $request, PublicKeyCredentialRequestOptions $publicKey): self; } diff --git a/src/Contracts/RegisterSuccessResponse.php b/src/Contracts/RegisterSuccessResponse.php index c396c10e..48b1f9a6 100644 --- a/src/Contracts/RegisterSuccessResponse.php +++ b/src/Contracts/RegisterSuccessResponse.php @@ -10,10 +10,6 @@ interface RegisterSuccessResponse extends Responsable { /** * Set the new webauthn key. - * - * @param \Illuminate\Http\Request $request - * @param \Illuminate\Database\Eloquent\Model $webauthnKey - * @return self */ public function setWebauthnKey(Request $request, Model $webauthnKey): self; } diff --git a/src/Contracts/RegisterViewResponse.php b/src/Contracts/RegisterViewResponse.php index 3536998a..cb95ff43 100644 --- a/src/Contracts/RegisterViewResponse.php +++ b/src/Contracts/RegisterViewResponse.php @@ -10,10 +10,6 @@ interface RegisterViewResponse extends Responsable { /** * Set public key request data. - * - * @param \Illuminate\Http\Request $request - * @param \Webauthn\PublicKeyCredentialCreationOptions $publicKey - * @return self */ public function setPublicKey(Request $request, PublicKeyCredentialCreationOptions $publicKey): self; } diff --git a/src/Events/WebauthnLogin.php b/src/Events/WebauthnLogin.php index b50d501c..50fb89ae 100644 --- a/src/Events/WebauthnLogin.php +++ b/src/Events/WebauthnLogin.php @@ -10,29 +10,14 @@ class WebauthnLogin { use SerializesModels, Dispatchable; - /** - * The authenticated user. - * - * @var \Illuminate\Contracts\Auth\Authenticatable - */ - public User $user; - - /** - * Login via eloquent webauthn provider. - * - * @var bool - */ - public bool $eloquent; - /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param bool $eloquent + * @param \Illuminate\Contracts\Auth\Authenticatable $user The authenticated user. + * @param bool $eloquent Login via eloquent webauthn provider. */ - public function __construct(User $user, bool $eloquent = false) - { - $this->user = $user; - $this->eloquent = $eloquent; - } + public function __construct( + public User $user, + public bool $eloquent = false + ) { } } diff --git a/src/Events/WebauthnLoginData.php b/src/Events/WebauthnLoginData.php index 3714aae3..c6aa7014 100644 --- a/src/Events/WebauthnLoginData.php +++ b/src/Events/WebauthnLoginData.php @@ -11,29 +11,14 @@ class WebauthnLoginData { use SerializesModels, Dispatchable; - /** - * The authenticated user. - * - * @var \Illuminate\Contracts\Auth\Authenticatable - */ - public User $user; - - /** - * The authentication data. - * - * @var PublicKeyCredentialRequestOptions - */ - public PublicKeyCredentialRequestOptions $publicKey; - /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param PublicKeyCredentialRequestOptions $publicKey + * @param \Illuminate\Contracts\Auth\Authenticatable $user The authenticated user. + * @param PublicKeyCredentialRequestOptions $publicKey The authentication data. */ - public function __construct(User $user, PublicKeyCredentialRequestOptions $publicKey) - { - $this->user = $user; - $this->publicKey = $publicKey; - } + public function __construct( + public User $user, + public PublicKeyCredentialRequestOptions $publicKey + ) { } } diff --git a/src/Events/WebauthnRegister.php b/src/Events/WebauthnRegister.php index 88551fc1..d0cc3691 100644 --- a/src/Events/WebauthnRegister.php +++ b/src/Events/WebauthnRegister.php @@ -10,20 +10,12 @@ class WebauthnRegister { use SerializesModels, Dispatchable; - /** - * The new WebauthnKey. - * - * @var \Illuminate\Database\Eloquent\Model - */ - public Model $webauthnKey; - /** * Create a new event instance. * - * @param \Illuminate\Database\Eloquent\Model $webauthnKey + * @param \Illuminate\Database\Eloquent\Model $webauthnKey The new WebauthnKey. */ - public function __construct(Model $webauthnKey) - { - $this->webauthnKey = $webauthnKey; - } + public function __construct( + public Model $webauthnKey + ) { } } diff --git a/src/Events/WebauthnRegisterData.php b/src/Events/WebauthnRegisterData.php index c427ff1b..20cf5037 100644 --- a/src/Events/WebauthnRegisterData.php +++ b/src/Events/WebauthnRegisterData.php @@ -11,29 +11,14 @@ class WebauthnRegisterData { use SerializesModels, Dispatchable; - /** - * The authenticated user. - * - * @var \Illuminate\Contracts\Auth\Authenticatable - */ - public User $user; - - /** - * The register data. - * - * @var PublicKeyCredentialCreationOptions - */ - public PublicKeyCredentialCreationOptions $publicKey; - /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param PublicKeyCredentialCreationOptions $publicKey + * @param \Illuminate\Contracts\Auth\Authenticatable $user The authenticated user. + * @param PublicKeyCredentialCreationOptions $publicKey The register data. */ - public function __construct(User $user, PublicKeyCredentialCreationOptions $publicKey) - { - $this->user = $user; - $this->publicKey = $publicKey; - } + public function __construct( + public User $user, + public PublicKeyCredentialCreationOptions $publicKey + ) { } } diff --git a/src/Events/WebauthnRegisterFailed.php b/src/Events/WebauthnRegisterFailed.php index 3f5dce20..70bd67b7 100644 --- a/src/Events/WebauthnRegisterFailed.php +++ b/src/Events/WebauthnRegisterFailed.php @@ -11,29 +11,14 @@ class WebauthnRegisterFailed { use SerializesModels, Dispatchable; - /** - * The authenticated user. - * - * @var \Illuminate\Contracts\Auth\Authenticatable - */ - public User $user; - - /** - * Exception throwned. - * - * @var ?Exception - */ - public ?Exception $exception; - /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param Exception|null $exception + * @param \Illuminate\Contracts\Auth\Authenticatable $user The authenticated user. + * @param Exception|null $exception Exception throwned. */ - public function __construct(User $user, ?Exception $exception = null) - { - $this->user = $user; - $this->exception = $exception; - } + public function __construct( + public User $user, + public ?Exception $exception = null + ) { } } diff --git a/src/Facades/Webauthn.php b/src/Facades/Webauthn.php index 8097e89e..c28038a9 100644 --- a/src/Facades/Webauthn.php +++ b/src/Facades/Webauthn.php @@ -26,10 +26,8 @@ class Webauthn extends Facade { /** * Get the registered name of the component. - * - * @return string */ - protected static function getFacadeAccessor() + protected static function getFacadeAccessor(): string { return \LaravelWebauthn\Services\Webauthn::class; } diff --git a/src/Http/Controllers/AuthenticateController.php b/src/Http/Controllers/AuthenticateController.php index 41edb7ea..ff1b35de 100644 --- a/src/Http/Controllers/AuthenticateController.php +++ b/src/Http/Controllers/AuthenticateController.php @@ -19,11 +19,8 @@ class AuthenticateController extends Controller { /** * Show the login Webauthn request after a login authentication. - * - * @param \LaravelWebauthn\Http\Requests\WebauthnLoginAttemptRequest $request - * @return LoginViewResponse */ - public function create(WebauthnLoginAttemptRequest $request) + public function create(WebauthnLoginAttemptRequest $request): LoginViewResponse { $user = $this->createPipeline($request)->then(function ($request) { return app(LoginUserRetrieval::class)($request); @@ -37,9 +34,6 @@ public function create(WebauthnLoginAttemptRequest $request) /** * Get the authentication pipeline instance. - * - * @param \LaravelWebauthn\Http\Requests\WebauthnLoginAttemptRequest $request - * @return \Illuminate\Pipeline\Pipeline */ protected function createPipeline(WebauthnLoginAttemptRequest $request): Pipeline { @@ -52,11 +46,8 @@ protected function createPipeline(WebauthnLoginAttemptRequest $request): Pipelin /** * Authenticate a webauthn request. - * - * @param WebauthnLoginRequest $request - * @return LoginSuccessResponse */ - public function store(WebauthnLoginRequest $request) + public function store(WebauthnLoginRequest $request): LoginSuccessResponse { return $this->loginPipeline($request)->then(function ($request) { Webauthn::login($request->user()); @@ -67,9 +58,6 @@ public function store(WebauthnLoginRequest $request) /** * Get the authentication pipeline instance. - * - * @param \LaravelWebauthn\Http\Requests\WebauthnLoginRequest $request - * @return \Illuminate\Pipeline\Pipeline */ protected function loginPipeline(WebauthnLoginRequest $request): Pipeline { diff --git a/src/Http/Controllers/WebauthnKeyController.php b/src/Http/Controllers/WebauthnKeyController.php index d774dc11..738e999f 100644 --- a/src/Http/Controllers/WebauthnKeyController.php +++ b/src/Http/Controllers/WebauthnKeyController.php @@ -19,11 +19,8 @@ class WebauthnKeyController extends Controller { /** * Return the register data to attempt a Webauthn registration. - * - * @param \Illuminate\Http\Request $request - * @return RegisterViewResponse */ - public function create(Request $request) + public function create(Request $request): RegisterViewResponse { $publicKey = app(PrepareCreationData::class)($request->user()); @@ -33,11 +30,8 @@ public function create(Request $request) /** * Validate and create the Webauthn request. - * - * @param WebauthnRegisterRequest $request - * @return RegisterSuccessResponse */ - public function store(WebauthnRegisterRequest $request) + public function store(WebauthnRegisterRequest $request): RegisterSuccessResponse { $webauthnKey = app(ValidateKeyCreation::class)( $request->user(), @@ -51,12 +45,8 @@ public function store(WebauthnRegisterRequest $request) /** * Update an existing Webauthn key. - * - * @param WebauthnUpdateRequest $request - * @param int $webauthnKeyId - * @return UpdateResponse */ - public function update(WebauthnUpdateRequest $request, int $webauthnKeyId) + public function update(WebauthnUpdateRequest $request, int $webauthnKeyId): UpdateResponse { app(UpdateKey::class)( $request->user(), @@ -69,12 +59,8 @@ public function update(WebauthnUpdateRequest $request, int $webauthnKeyId) /** * Delete an existing Webauthn key. - * - * @param \Illuminate\Http\Request $request - * @param int $webauthnKeyId - * @return DestroyResponse */ - public function destroy(Request $request, int $webauthnKeyId) + public function destroy(Request $request, int $webauthnKeyId): DestroyResponse { app(DeleteKey::class)( $request->user(), diff --git a/src/Http/Middleware/WebauthnMiddleware.php b/src/Http/Middleware/WebauthnMiddleware.php index bae43d9f..aac7e969 100644 --- a/src/Http/Middleware/WebauthnMiddleware.php +++ b/src/Http/Middleware/WebauthnMiddleware.php @@ -4,37 +4,23 @@ use Closure; use Illuminate\Contracts\Auth\Factory as AuthFactory; +use Illuminate\Http\Request; use Illuminate\Support\Facades\Redirect; use LaravelWebauthn\Facades\Webauthn; class WebauthnMiddleware { /** - * The auth factory instance. - * - * @var \Illuminate\Contracts\Auth\Factory + * Create a Webauthn middleware. */ - protected AuthFactory $auth; - - /** - * Create a Webauthn. - * - * @param \Illuminate\Contracts\Auth\Factory $auth - */ - public function __construct(AuthFactory $auth) - { - $this->auth = $auth; - } + public function __construct( + protected AuthFactory $auth + ) { } /** * Handle an incoming request. - * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @param string|null $guard - * @return mixed */ - public function handle($request, Closure $next, $guard = null) + public function handle(Request $request, Closure $next, ?string $guard = null): mixed { if (Webauthn::webauthnEnabled() && ! Webauthn::check()) { abort_if($this->auth->guard($guard)->guest(), 401, /** @var string $m */ $m = trans('webauthn::errors.user_unauthenticated')); diff --git a/src/Http/Requests/WebauthnLoginAttemptRequest.php b/src/Http/Requests/WebauthnLoginAttemptRequest.php index 6eb792bc..f714cc78 100644 --- a/src/Http/Requests/WebauthnLoginAttemptRequest.php +++ b/src/Http/Requests/WebauthnLoginAttemptRequest.php @@ -9,10 +9,8 @@ class WebauthnLoginAttemptRequest extends FormRequest { /** * Get the validation rules that apply to the request. - * - * @return array */ - public function rules() + public function rules(): array { return [ Webauthn::username() => 'sometimes|string', diff --git a/src/Http/Requests/WebauthnLoginRequest.php b/src/Http/Requests/WebauthnLoginRequest.php index a06fac6d..c3875107 100644 --- a/src/Http/Requests/WebauthnLoginRequest.php +++ b/src/Http/Requests/WebauthnLoginRequest.php @@ -8,10 +8,8 @@ class WebauthnLoginRequest extends FormRequest { /** * Get the validation rules that apply to the request. - * - * @return array */ - public function rules() + public function rules(): array { return [ 'id' => 'required|string', diff --git a/src/Http/Requests/WebauthnRegisterRequest.php b/src/Http/Requests/WebauthnRegisterRequest.php index 308b6b29..a3ec904b 100644 --- a/src/Http/Requests/WebauthnRegisterRequest.php +++ b/src/Http/Requests/WebauthnRegisterRequest.php @@ -8,10 +8,8 @@ class WebauthnRegisterRequest extends FormRequest { /** * Get the validation rules that apply to the request. - * - * @return array */ - public function rules() + public function rules(): array { return [ 'id' => 'required|string', diff --git a/src/Http/Requests/WebauthnUpdateRequest.php b/src/Http/Requests/WebauthnUpdateRequest.php index a7f26d9b..06ec7828 100644 --- a/src/Http/Requests/WebauthnUpdateRequest.php +++ b/src/Http/Requests/WebauthnUpdateRequest.php @@ -8,10 +8,8 @@ class WebauthnUpdateRequest extends FormRequest { /** * Get the validation rules that apply to the request. - * - * @return array */ - public function rules() + public function rules(): array { return [ 'name' => 'required|string', diff --git a/src/Http/Responses/LockoutResponse.php b/src/Http/Responses/LockoutResponse.php index c7363199..a29db3fe 100644 --- a/src/Http/Responses/LockoutResponse.php +++ b/src/Http/Responses/LockoutResponse.php @@ -10,23 +10,12 @@ class LockoutResponse implements LockoutResponseContract { - /** - * The login rate limiter instance. - * - * @var \LaravelWebauthn\Services\LoginRateLimiter - */ - protected LoginRateLimiter $limiter; - /** * Create a new response instance. - * - * @param \LaravelWebauthn\Services\LoginRateLimiter $limiter - * @return void */ - public function __construct(LoginRateLimiter $limiter) - { - $this->limiter = $limiter; - } + public function __construct( + protected LoginRateLimiter $limiter + ) { } /** * Create an HTTP response that represents the object. diff --git a/src/Http/Responses/LoginViewResponse.php b/src/Http/Responses/LoginViewResponse.php index 70026096..1e28814b 100644 --- a/src/Http/Responses/LoginViewResponse.php +++ b/src/Http/Responses/LoginViewResponse.php @@ -11,8 +11,6 @@ class LoginViewResponse implements LoginViewResponseContract { /** * The public key options. - * - * @var \Webauthn\PublicKeyCredentialRequestOptions */ protected PublicKeyCredentialRequestOptions $publicKey; @@ -33,10 +31,6 @@ public function toResponse($request) /** * Set public key request data. - * - * @param \Illuminate\Http\Request $request - * @param \Webauthn\PublicKeyCredentialRequestOptions $publicKey - * @return self */ public function setPublicKey(Request $request, PublicKeyCredentialRequestOptions $publicKey): self { diff --git a/src/Http/Responses/RegisterSuccessResponse.php b/src/Http/Responses/RegisterSuccessResponse.php index 124e71bc..8aa37833 100644 --- a/src/Http/Responses/RegisterSuccessResponse.php +++ b/src/Http/Responses/RegisterSuccessResponse.php @@ -13,8 +13,6 @@ class RegisterSuccessResponse implements RegisterSuccessResponseContract { /** * The new Webauthn key. - * - * @var \Illuminate\Database\Eloquent\Model */ protected Model $webauthnKey; @@ -33,9 +31,6 @@ public function toResponse($request) /** * Create an HTTP response that represents the object. - * - * @param \Illuminate\Http\Request $request - * @return \Symfony\Component\HttpFoundation\Response */ protected function jsonResponse(Request $request): \Symfony\Component\HttpFoundation\Response { @@ -49,10 +44,6 @@ protected function jsonResponse(Request $request): \Symfony\Component\HttpFounda /** * Set the new Webauthn key. - * - * @param \Illuminate\Http\Request $request - * @param \Illuminate\Database\Eloquent\Model $webauthnKey - * @return self */ public function setWebauthnKey(Request $request, Model $webauthnKey): self { diff --git a/src/Http/Responses/RegisterViewResponse.php b/src/Http/Responses/RegisterViewResponse.php index 2c3e0515..efb542f4 100644 --- a/src/Http/Responses/RegisterViewResponse.php +++ b/src/Http/Responses/RegisterViewResponse.php @@ -11,8 +11,6 @@ class RegisterViewResponse implements RegisterViewResponseContract { /** * The public key options. - * - * @var \Webauthn\PublicKeyCredentialCreationOptions */ protected PublicKeyCredentialCreationOptions $publicKey; @@ -33,10 +31,6 @@ public function toResponse($request) /** * Set public key request data. - * - * @param \Illuminate\Http\Request $request - * @param \Webauthn\PublicKeyCredentialCreationOptions $publicKey - * @return self */ public function setPublicKey(Request $request, PublicKeyCredentialCreationOptions $publicKey): self { diff --git a/src/Listeners/LoginViaRemember.php b/src/Listeners/LoginViaRemember.php index f5d12412..3a11b0e8 100644 --- a/src/Listeners/LoginViaRemember.php +++ b/src/Listeners/LoginViaRemember.php @@ -11,11 +11,8 @@ class LoginViaRemember { /** * Handle the event. - * - * @param \Illuminate\Auth\Events\Login $event - * @return void */ - public function handle(Login $event) + public function handle(Login $event): void { if (Auth::viaRemember()) { $this->registerWebauthn($event->user); @@ -24,8 +21,6 @@ public function handle(Login $event) /** * Force register Webauthn login. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user */ private function registerWebauthn(User $user) { diff --git a/src/Models/Casts/Base64.php b/src/Models/Casts/Base64.php index 64587127..45250b18 100644 --- a/src/Models/Casts/Base64.php +++ b/src/Models/Casts/Base64.php @@ -3,35 +3,27 @@ namespace LaravelWebauthn\Models\Casts; use Illuminate\Contracts\Database\Eloquent\CastsAttributes; +use Illuminate\Database\Eloquent\Model; use ParagonIE\ConstantTime\Base64UrlSafe; use Webauthn\Util\Base64 as Base64Webauthn; +/** + * @implements CastsAttributes + */ class Base64 implements CastsAttributes { /** * Cast the given value. - * - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @param mixed $value - * @param array $attributes - * @return string|null */ - public function get($model, $key, $value, $attributes): ?string + public function get(Model $model, string $key, mixed $value, array $attributes): ?string { return $value !== null ? Base64Webauthn::decode($value) : null; } /** * Prepare the given value for storage. - * - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @param mixed $value - * @param array $attributes - * @return string|null */ - public function set($model, $key, $value, $attributes): ?string + public function set(Model $model, string $key, mixed $value, array $attributes): ?string { return $value !== null ? Base64UrlSafe::encode($value) : null; } diff --git a/src/Models/Casts/TrustPath.php b/src/Models/Casts/TrustPath.php index 089652c5..d5c9fb89 100644 --- a/src/Models/Casts/TrustPath.php +++ b/src/Models/Casts/TrustPath.php @@ -3,34 +3,27 @@ namespace LaravelWebauthn\Models\Casts; use Illuminate\Contracts\Database\Eloquent\CastsAttributes; +use Illuminate\Database\Eloquent\Model; use Webauthn\TrustPath\TrustPathLoader; +use Webauthn\TrustPath\TrustPath as TrustPathLib; +/** + * @implements CastsAttributes + */ class TrustPath implements CastsAttributes { /** * Cast the given value. - * - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @param mixed $value - * @param array $attributes - * @return \Webauthn\TrustPath\TrustPath|null */ - public function get($model, $key, $value, $attributes): ?\Webauthn\TrustPath\TrustPath + public function get(Model $model, string $key, mixed $value, array $attributes): ?TrustPathLib { return $value !== null ? TrustPathLoader::loadTrustPath(json_decode($value, true, flags: JSON_THROW_ON_ERROR)) : null; } /** * Prepare the given value for storage. - * - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @param mixed $value - * @param array $attributes - * @return string */ - public function set($model, $key, $value, $attributes): string + public function set(Model $model, string $key, mixed $value, array $attributes): ?string { return json_encode($value, flags: JSON_THROW_ON_ERROR); } diff --git a/src/Models/Casts/Uuid.php b/src/Models/Casts/Uuid.php index 0dabc805..fb4042c9 100644 --- a/src/Models/Casts/Uuid.php +++ b/src/Models/Casts/Uuid.php @@ -3,21 +3,19 @@ namespace LaravelWebauthn\Models\Casts; use Illuminate\Contracts\Database\Eloquent\CastsAttributes; +use Illuminate\Database\Eloquent\Model; use Symfony\Component\Uid\AbstractUid; use Symfony\Component\Uid\Uuid as UuidConvert; +/** + * @implements CastsAttributes + */ class Uuid implements CastsAttributes { /** * Cast the given value. - * - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @param mixed $value - * @param array $attributes - * @return \Symfony\Component\Uid\AbstractUid|null */ - public function get($model, $key, $value, $attributes): ?AbstractUid + public function get(Model $model, string $key, mixed $value, array $attributes): ?AbstractUid { if ($value !== null && UuidConvert::isValid($value)) { return UuidConvert::fromString($value); @@ -28,14 +26,8 @@ public function get($model, $key, $value, $attributes): ?AbstractUid /** * Prepare the given value for storage. - * - * @param \Illuminate\Database\Eloquent\Model $model - * @param string $key - * @param mixed $value - * @param array $attributes - * @return string|null */ - public function set($model, $key, $value, $attributes): ?string + public function set(Model $model, string $key, mixed $value, array $attributes): ?string { return (string) $value; } diff --git a/src/Models/WebauthnKey.php b/src/Models/WebauthnKey.php index 69913422..578ee3a2 100644 --- a/src/Models/WebauthnKey.php +++ b/src/Models/WebauthnKey.php @@ -2,7 +2,9 @@ namespace LaravelWebauthn\Models; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Arr; use LaravelWebauthn\Exceptions\WrongUserHandleException; use LaravelWebauthn\Models\Casts\Base64; use LaravelWebauthn\Models\Casts\TrustPath; @@ -24,7 +26,7 @@ class WebauthnKey extends Model /** * The attributes that are mass assignable. * - * @var string[] + * @var array */ protected $fillable = [ 'user_id', @@ -43,7 +45,7 @@ class WebauthnKey extends Model /** * The attributes that should be visible in serialization. * - * @var array + * @var array */ protected $visible = [ 'id', @@ -57,7 +59,7 @@ class WebauthnKey extends Model /** * The attributes that should be cast to native types. * - * @var array + * @var array */ protected $casts = [ 'counter' => 'integer', @@ -71,41 +73,46 @@ class WebauthnKey extends Model /** * Get PublicKeyCredentialSource object from WebauthnKey attributes. * - * @return PublicKeyCredentialSource + * @return Attribute */ - public function getPublicKeyCredentialSourceAttribute(): PublicKeyCredentialSource + public function publicKeyCredentialSource(): Attribute { - return new PublicKeyCredentialSource( - $this->credentialId, - $this->type, - $this->transports, - $this->attestationType, - $this->trustPath, - $this->aaguid ?? new NilUuid(), - $this->credentialPublicKey, - (string) $this->user_id, - $this->counter - ); - } + return Attribute::make( + get: fn (): PublicKeyCredentialSource => new PublicKeyCredentialSource( + $this->credentialId, + $this->type, + $this->transports, + $this->attestationType, + $this->trustPath, + $this->aaguid ?? new NilUuid(), + $this->credentialPublicKey, + (string) $this->user_id, + $this->counter + ), + set: function (PublicKeyCredentialSource $value, array $attributes): array { + if (((string) Arr::get($attributes, 'user_id')) !== $value->getUserHandle()) { + throw new WrongUserHandleException(); + } - /** - * Set WebauthnKey attributes from a PublicKeyCredentialSource object. - * - * @param PublicKeyCredentialSource $value - * @return void - */ - public function setPublicKeyCredentialSourceAttribute(PublicKeyCredentialSource $value) - { - if ((string) $this->user_id !== $value->getUserHandle()) { - throw new WrongUserHandleException(); - } - $this->credentialId = $value->getPublicKeyCredentialId(); - $this->type = $value->getType(); - $this->transports = $value->getTransports(); - $this->attestationType = $value->getAttestationType(); - $this->trustPath = $value->getTrustPath(); - $this->aaguid = $value->getAaguid(); - $this->credentialPublicKey = $value->getCredentialPublicKey(); - $this->counter = $value->getCounter(); + // Set value to attributes using casts + $this->credentialId = $value->getPublicKeyCredentialId(); + $this->transports = $value->getTransports(); + $this->trustPath = $value->getTrustPath(); + $this->aaguid = $value->getAaguid(); + $this->credentialPublicKey = $value->getCredentialPublicKey(); + $this->counter = $value->getCounter(); + + return [ + 'credentialId' => $this->attributes['credentialId'], + 'type' => $value->getType(), + 'transports' => $this->attributes['transports'], + 'attestationType' => $value->getAttestationType(), + 'trustPath' => $this->attributes['trustPath'], + 'aaguid' => $this->attributes['aaguid'], + 'credentialPublicKey' => $this->attributes['credentialPublicKey'], + 'counter' => $this->attributes['counter'], + ]; + } + )->shouldCache(); } } diff --git a/src/Services/LoginRateLimiter.php b/src/Services/LoginRateLimiter.php index a190dabd..84c8c659 100644 --- a/src/Services/LoginRateLimiter.php +++ b/src/Services/LoginRateLimiter.php @@ -8,86 +8,57 @@ class LoginRateLimiter { - /** - * The login rate limiter instance. - * - * @var \Illuminate\Cache\RateLimiter - */ - protected RateLimiter $limiter; - /** * Create a new login rate limiter instance. - * - * @param \Illuminate\Cache\RateLimiter $limiter - * @return void */ - public function __construct(RateLimiter $limiter) - { - $this->limiter = $limiter; - } + public function __construct( + protected RateLimiter $limiter + ) { } /** * Get the number of attempts for the given key. - * - * @param \Illuminate\Http\Request $request - * @return mixed */ - public function attempts(Request $request) + public function attempts(Request $request): mixed { return $this->limiter->attempts($this->throttleKey($request)); } /** * Determine if the user has too many failed login attempts. - * - * @param \Illuminate\Http\Request $request - * @return bool */ - public function tooManyAttempts(Request $request) + public function tooManyAttempts(Request $request): bool { return $this->limiter->tooManyAttempts($this->throttleKey($request), 5); } /** * Increment the login attempts for the user. - * - * @param \Illuminate\Http\Request $request - * @return void */ - public function increment(Request $request) + public function increment(Request $request): int { - $this->limiter->hit($this->throttleKey($request), 60); + return $this->limiter->hit($this->throttleKey($request), 60); } /** * Determine the number of seconds until logging in is available again. - * - * @param \Illuminate\Http\Request $request - * @return int */ - public function availableIn(Request $request) + public function availableIn(Request $request): int { return $this->limiter->availableIn($this->throttleKey($request)); } /** * Clear the login locks for the given user credentials. - * - * @param \Illuminate\Http\Request $request - * @return void */ - public function clear(Request $request) + public function clear(Request $request): void { $this->limiter->clear($this->throttleKey($request)); } /** * Get the throttle key for the given request. - * - * @param \Illuminate\Http\Request $request - * @return string */ - protected function throttleKey(Request $request) + protected function throttleKey(Request $request): string { return Str::lower($request->input(Webauthn::username())).'|'.$request->ip(); } diff --git a/src/Services/Webauthn.php b/src/Services/Webauthn.php index 428608fe..a9f4e709 100644 --- a/src/Services/Webauthn.php +++ b/src/Services/Webauthn.php @@ -36,39 +36,29 @@ class Webauthn extends WebauthnRepository /** * Indicates if Webauthn routes will be registered. - * - * @var bool */ public static bool $registersRoutes = true; /** * Get the username used for authentication. - * - * @return string */ - public static function username() + public static function username(): string { return config('webauthn.username', 'email'); } /** * Get a completion redirect path for a specific feature. - * - * @param string $redirect - * @return string */ - public static function redirects(string $redirect, $default = null) + public static function redirects(string $redirect, $default = null): string { return config('webauthn.redirects.'.$redirect) ?? $default ?? config('webauthn.home'); } /** * Save authentication in session. - * - * @param \Illuminate\Contracts\Auth\Authenticatable|null $user - * @return void */ - public static function login(?User $user) + public static function login(?User $user): void { session([static::sessionName() => true]); @@ -79,10 +69,8 @@ public static function login(?User $user) /** * Remove authentication from session. - * - * @return void */ - public static function logout() + public static function logout(): void { session()->forget(static::sessionName()); } @@ -90,13 +78,11 @@ public static function logout() /** * Force authentication in session. * - * @return void - * * @deprecated use login() instead * * @codeCoverageIgnore */ - public static function forceAuthenticate() + public static function forceAuthenticate(): void { static::login(null); } @@ -104,22 +90,17 @@ public static function forceAuthenticate() /** * Force remove authentication in session. * - * @return void - * * @deprecated use logout() instead * * @codeCoverageIgnore */ - public static function forgetAuthenticate() + public static function forgetAuthenticate(): void { static::logout(); } /** * Get publicKey data to prepare Webauthn login. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @return \Webauthn\PublicKeyCredentialRequestOptions */ public static function prepareAssertion(User $user): PublicKeyCredentialRequestOptions { @@ -130,10 +111,6 @@ public static function prepareAssertion(User $user): PublicKeyCredentialRequestO /** * Validate a Webauthn login request. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param array $credentials - * @return bool */ public static function validateAssertion(User $user, array $credentials): bool { @@ -146,9 +123,6 @@ public static function validateAssertion(User $user, array $credentials): bool /** * Get publicKey data to prepare Webauthn key creation. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @return \Webauthn\PublicKeyCredentialCreationOptions */ public static function prepareAttestation(User $user): PublicKeyCredentialCreationOptions { @@ -159,11 +133,6 @@ public static function prepareAttestation(User $user): PublicKeyCredentialCreati /** * Validate a Webauthn key creation request. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param array $credentials - * @param string $keyName - * @return \Illuminate\Database\Eloquent\Model */ public static function validateAttestation(User $user, array $credentials, string $keyName): Model { @@ -180,8 +149,6 @@ public static function validateAttestation(User $user, array $credentials, strin /** * Check authentication of the user in session. - * - * @return bool */ public static function check(): bool { @@ -190,8 +157,6 @@ public static function check(): bool /** * Get webauthn session store name. - * - * @return string */ public static function sessionName(): string { @@ -200,9 +165,6 @@ public static function sessionName(): string /** * Test if the user has one or more webauthn key. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @return bool */ public static function enabled(User $user): bool { @@ -211,9 +173,6 @@ public static function enabled(User $user): bool /** * Test if the user can register a new key. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @return bool */ public static function canRegister(User $user): bool { @@ -222,8 +181,6 @@ public static function canRegister(User $user): bool /** * Test if webauthn is enabled. - * - * @return bool */ public static function webauthnEnabled(): bool { @@ -233,23 +190,17 @@ public static function webauthnEnabled(): bool /** * Register a callback that is responsible for building the authentication pipeline array. * - * @param callable $callback - * @return void - * * @codeCoverageIgnore */ - public static function authenticateThrough(callable $callback) + public static function authenticateThrough(callable $callback): void { static::$authenticateThroughCallback = $callback; } /** * Register a callback that is responsible for validating incoming authentication credentials. - * - * @param callable $callback - * @return void */ - public static function authenticateUsing(callable $callback) + public static function authenticateUsing(callable $callback): void { static::$authenticateUsingCallback = $callback; } @@ -257,12 +208,9 @@ public static function authenticateUsing(callable $callback) /** * Register a class / callback that should be used to the destroy view response. * - * @param \Closure|string $callback - * @return void - * * @codeCoverageIgnore */ - public static function destroyViewResponseUsing($callback) + public static function destroyViewResponseUsing(\Closure|string $callback): void { app()->singleton(\LaravelWebauthn\Contracts\DestroyResponse::class, $callback); } @@ -270,12 +218,9 @@ public static function destroyViewResponseUsing($callback) /** * Register a class / callback that should be used to the update view response. * - * @param \Closure|string $callback - * @return void - * * @codeCoverageIgnore */ - public static function updateViewResponseUsing($callback) + public static function updateViewResponseUsing(\Closure|string $callback): void { app()->singleton(\LaravelWebauthn\Contracts\UpdateResponse::class, $callback); } @@ -283,12 +228,9 @@ public static function updateViewResponseUsing($callback) /** * Register a class / callback that should be used to the login success view response. * - * @param \Closure|string $callback - * @return void - * * @codeCoverageIgnore */ - public static function loginSuccessResponseUsing($callback) + public static function loginSuccessResponseUsing(\Closure|string $callback): void { app()->singleton(\LaravelWebauthn\Contracts\LoginSuccessResponse::class, $callback); } @@ -296,12 +238,9 @@ public static function loginSuccessResponseUsing($callback) /** * Register a class / callback that should be used to the login view response. * - * @param \Closure|string $callback - * @return void - * * @codeCoverageIgnore */ - public static function loginViewResponseUsing($callback) + public static function loginViewResponseUsing(\Closure|string $callback): void { app()->singleton(\LaravelWebauthn\Contracts\LoginViewResponse::class, $callback); } @@ -309,12 +248,9 @@ public static function loginViewResponseUsing($callback) /** * Register a class / callback that should be used to the register key success view response. * - * @param \Closure|string $callback - * @return void - * * @codeCoverageIgnore */ - public static function registerSuccessResponseUsing($callback) + public static function registerSuccessResponseUsing(\Closure|string $callback): void { app()->singleton(\LaravelWebauthn\Contracts\RegisterSuccessResponse::class, $callback); } @@ -322,22 +258,17 @@ public static function registerSuccessResponseUsing($callback) /** * Register a class / callback that should be used to the register creation view response. * - * @param \Closure|string $callback - * @return void - * * @codeCoverageIgnore */ - public static function registerViewResponseUsing($callback) + public static function registerViewResponseUsing(\Closure|string $callback): void { app()->singleton(\LaravelWebauthn\Contracts\RegisterViewResponse::class, $callback); } /** * Configure Webauthn to not register its routes. - * - * @return void */ - public static function ignoreRoutes() + public static function ignoreRoutes(): void { static::$registersRoutes = false; } diff --git a/src/Services/Webauthn/CreationOptionsFactory.php b/src/Services/Webauthn/CreationOptionsFactory.php index 1bee5a17..44b68bac 100644 --- a/src/Services/Webauthn/CreationOptionsFactory.php +++ b/src/Services/Webauthn/CreationOptionsFactory.php @@ -13,47 +13,30 @@ use Webauthn\PublicKeyCredentialDescriptor; use Webauthn\PublicKeyCredentialParameters; use Webauthn\PublicKeyCredentialRpEntity; -use Webauthn\PublicKeyCredentialSourceRepository; use Webauthn\PublicKeyCredentialUserEntity; final class CreationOptionsFactory extends OptionsFactory { - /** - * @var PublicKeyCredentialRpEntity - */ - protected PublicKeyCredentialRpEntity $publicKeyCredentialRpEntity; - - /** - * @var AuthenticatorSelectionCriteria - */ - protected AuthenticatorSelectionCriteria $authenticatorSelectionCriteria; - - /** - * @var CoseAlgorithmManager - */ - protected CoseAlgorithmManager $algorithmManager; - /** * Attestation Conveyance preference. - * - * @var string */ protected string $attestationConveyance; - public function __construct(Request $request, Cache $cache, Config $config, PublicKeyCredentialSourceRepository $repository, PublicKeyCredentialRpEntity $publicKeyCredentialRpEntity, AuthenticatorSelectionCriteria $authenticatorSelectionCriteria, CoseAlgorithmManager $algorithmManager) - { + public function __construct( + Request $request, + Cache $cache, + Config $config, + CredentialRepository $repository, + protected PublicKeyCredentialRpEntity $publicKeyCredentialRpEntity, + protected AuthenticatorSelectionCriteria $authenticatorSelectionCriteria, + protected CoseAlgorithmManager $algorithmManager + ) { parent::__construct($request, $cache, $config, $repository); - $this->publicKeyCredentialRpEntity = $publicKeyCredentialRpEntity; - $this->authenticatorSelectionCriteria = $authenticatorSelectionCriteria; - $this->algorithmManager = $algorithmManager; $this->attestationConveyance = $config->get('webauthn.attestation_conveyance', 'none'); } /** * Create a new PublicKeyCredentialCreationOptions object. - * - * @param User $user - * @return PublicKeyCredentialCreationOptions */ public function __invoke(User $user): PublicKeyCredentialCreationOptions { @@ -75,9 +58,6 @@ public function __invoke(User $user): PublicKeyCredentialCreationOptions /** * Return the credential user entity. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @return PublicKeyCredentialUserEntity */ private function getUserEntity(User $user): PublicKeyCredentialUserEntity { @@ -90,7 +70,7 @@ private function getUserEntity(User $user): PublicKeyCredentialUserEntity } /** - * @return PublicKeyCredentialParameters[] + * @return array */ private function createCredentialParameters(): array { @@ -106,12 +86,9 @@ private function createCredentialParameters(): array /** * Get the excluded credentials. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @return array */ protected function getExcludedCredentials(User $user): array { - return $this->repository->getRegisteredKeys($user); + return CredentialRepository::getRegisteredKeys($user); } } diff --git a/src/Services/Webauthn/CredentialAssertionValidator.php b/src/Services/Webauthn/CredentialAssertionValidator.php index 41a2cf14..7832ab1f 100644 --- a/src/Services/Webauthn/CredentialAssertionValidator.php +++ b/src/Services/Webauthn/CredentialAssertionValidator.php @@ -16,36 +16,19 @@ class CredentialAssertionValidator extends CredentialValidator { - /** - * @var ServerRequestInterface - */ - protected ServerRequestInterface $serverRequest; - - /** - * @var PublicKeyCredentialLoader - */ - protected PublicKeyCredentialLoader $loader; - - /** - * @var AuthenticatorAssertionResponseValidator - */ - protected AuthenticatorAssertionResponseValidator $validator; - - public function __construct(Request $request, Cache $cache, ServerRequestInterface $serverRequest, PublicKeyCredentialLoader $loader, AuthenticatorAssertionResponseValidator $validator) - { + public function __construct( + Request $request, + Cache $cache, + protected ServerRequestInterface $serverRequest, + protected PublicKeyCredentialLoader $loader, + protected AuthenticatorAssertionResponseValidator $validator + ) { parent::__construct($request, $cache); - $this->serverRequest = $serverRequest; - $this->loader = $loader; - $this->validator = $validator; } /** * Validate an authentication request. * - * @param User $user - * @param array $data - * @return bool - * * @throws ResponseMismatchException */ public function __invoke(User $user, array $data): bool @@ -67,9 +50,6 @@ public function __invoke(User $user, array $data): bool /** * Get public Key credential. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @return \Webauthn\PublicKeyCredentialRequestOptions */ protected function pullPublicKey(User $user): PublicKeyCredentialRequestOptions { @@ -83,9 +63,6 @@ protected function pullPublicKey(User $user): PublicKeyCredentialRequestOptions /** * Get authenticator response. - * - * @param \Webauthn\PublicKeyCredential $publicKeyCredential - * @return \Webauthn\AuthenticatorAssertionResponse */ protected function getResponse(PublicKeyCredential $publicKeyCredential): AuthenticatorAssertionResponse { diff --git a/src/Services/Webauthn/CredentialAttestationValidator.php b/src/Services/Webauthn/CredentialAttestationValidator.php index e85730bc..292222be 100644 --- a/src/Services/Webauthn/CredentialAttestationValidator.php +++ b/src/Services/Webauthn/CredentialAttestationValidator.php @@ -17,36 +17,19 @@ class CredentialAttestationValidator extends CredentialValidator { - /** - * @var ServerRequestInterface - */ - protected ServerRequestInterface $serverRequest; - - /** - * @var PublicKeyCredentialLoader - */ - protected PublicKeyCredentialLoader $loader; - - /** - * @var AuthenticatorAttestationResponseValidator - */ - protected AuthenticatorAttestationResponseValidator $validator; - - public function __construct(Request $request, Cache $cache, ServerRequestInterface $serverRequest, PublicKeyCredentialLoader $loader, AuthenticatorAttestationResponseValidator $validator) - { + public function __construct( + Request $request, + Cache $cache, + protected ServerRequestInterface $serverRequest, + protected PublicKeyCredentialLoader $loader, + protected AuthenticatorAttestationResponseValidator $validator + ) { parent::__construct($request, $cache); - $this->serverRequest = $serverRequest; - $this->loader = $loader; - $this->validator = $validator; } /** * Validate a creation request. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param array $data - * @return PublicKeyCredentialSource - * * @throws ResponseMismatchException */ public function __invoke(User $user, array $data): PublicKeyCredentialSource @@ -64,9 +47,6 @@ public function __invoke(User $user, array $data): PublicKeyCredentialSource /** * Get public Key credential. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @return \Webauthn\PublicKeyCredentialCreationOptions */ protected function pullPublicKey(User $user): PublicKeyCredentialCreationOptions { @@ -80,9 +60,6 @@ protected function pullPublicKey(User $user): PublicKeyCredentialCreationOptions /** * Get authenticator response. - * - * @param \Webauthn\PublicKeyCredential $publicKeyCredential - * @return \Webauthn\AuthenticatorAttestationResponse */ protected function getResponse(PublicKeyCredential $publicKeyCredential): AuthenticatorAttestationResponse { diff --git a/src/Services/Webauthn/CredentialRepository.php b/src/Services/Webauthn/CredentialRepository.php index 938e19a4..12a81972 100644 --- a/src/Services/Webauthn/CredentialRepository.php +++ b/src/Services/Webauthn/CredentialRepository.php @@ -3,83 +3,19 @@ namespace LaravelWebauthn\Services\Webauthn; use Illuminate\Contracts\Auth\Authenticatable as User; -use Illuminate\Contracts\Auth\Factory as AuthFactory; -use Illuminate\Database\Eloquent\ModelNotFoundException; use LaravelWebauthn\Facades\Webauthn; -use LaravelWebauthn\Models\WebauthnKey; -use ParagonIE\ConstantTime\Base64UrlSafe; use Webauthn\PublicKeyCredentialDescriptor; +use Illuminate\Support\Collection; use Webauthn\PublicKeyCredentialSource; -use Webauthn\PublicKeyCredentialSourceRepository; -use Webauthn\PublicKeyCredentialUserEntity; -class CredentialRepository implements PublicKeyCredentialSourceRepository +class CredentialRepository { - /** - * The auth factory instance. - * - * @var \Illuminate\Contracts\Auth\Factory - */ - protected AuthFactory $auth; - - public function __construct(AuthFactory $auth) - { - $this->auth = $auth; - } - - /** - * Return a PublicKeyCredentialSource object. - * - * @param string $publicKeyCredentialId - * @return null|PublicKeyCredentialSource - */ - public function findOneByCredentialId(string $publicKeyCredentialId): ?PublicKeyCredentialSource - { - try { - $webauthnKey = $this->model($publicKeyCredentialId); - - return $webauthnKey->publicKeyCredentialSource; - } catch (ModelNotFoundException $e) { - // No result - } - - return null; - } - - /** - * Return a list of PublicKeyCredentialSource objects. - * - * @param PublicKeyCredentialUserEntity $publicKeyCredentialUserEntity - * @return PublicKeyCredentialSource[] - */ - public function findAllForUserEntity(PublicKeyCredentialUserEntity $publicKeyCredentialUserEntity): array - { - return $this->getAllRegisteredKeys($publicKeyCredentialUserEntity->getId()) - ->toArray(); - } - - /** - * Save a PublicKeyCredentialSource object. - * - * @param PublicKeyCredentialSource $publicKeyCredentialSource - * - * @throws ModelNotFoundException - */ - public function saveCredentialSource(PublicKeyCredentialSource $publicKeyCredentialSource): void - { - $webauthnKey = $this->model($publicKeyCredentialSource->getPublicKeyCredentialId()); - - $webauthnKey->publicKeyCredentialSource = $publicKeyCredentialSource; - $webauthnKey->save(); - } - /** * List of PublicKeyCredentialSource associated to the user. * - * @param int|string $userId - * @return \Illuminate\Support\Collection collection of PublicKeyCredentialSource + * @return Collection */ - protected function getAllRegisteredKeys($userId): \Illuminate\Support\Collection + protected static function getAllRegisteredKeys(int|string $userId): Collection { return (Webauthn::model())::where('user_id', $userId) ->get() @@ -90,46 +26,13 @@ protected function getAllRegisteredKeys($userId): \Illuminate\Support\Collection /** * List of registered PublicKeyCredentialDescriptor associated to the user. * - * @param User $user - * @return PublicKeyCredentialDescriptor[] + * @return array */ - public function getRegisteredKeys(User $user): array + public static function getRegisteredKeys(User $user): array { - return $this->getAllRegisteredKeys($user->getAuthIdentifier()) + return static::getAllRegisteredKeys($user->getAuthIdentifier()) ->map ->getPublicKeyCredentialDescriptor() ->toArray(); } - - /** - * Get one WebauthnKey. - * - * @param string $credentialId - * @return WebauthnKey - * - * @throws ModelNotFoundException - */ - private function model(string $credentialId): WebauthnKey - { - return (Webauthn::model())::where(function ($query) { - if ($this->guard()->check()) { - $query->where('user_id', $this->guard()->id()); - } - }) - ->where(function ($query) use ($credentialId) { - $query->where('credentialId', Base64UrlSafe::encode($credentialId)) - ->orWhere('credentialId', Base64UrlSafe::encodeUnpadded($credentialId)); - }) - ->firstOrFail(); - } - - /** - * Get current guard. - * - * @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard - */ - private function guard() - { - return $this->auth->guard(); - } } diff --git a/src/Services/Webauthn/CredentialValidator.php b/src/Services/Webauthn/CredentialValidator.php index 22d3f27f..eb9c4fe3 100644 --- a/src/Services/Webauthn/CredentialValidator.php +++ b/src/Services/Webauthn/CredentialValidator.php @@ -10,36 +10,16 @@ abstract class CredentialValidator { /** * PublicKey Request session name. - * - * @var string */ public const CACHE_PUBLICKEY_REQUEST = 'webauthn.publicKeyRequest'; - /** - * HTTP Request. - * - * @var \Illuminate\Http\Request - */ - protected Request $request; - - /** - * Cache repository. - * - * @var \Illuminate\Contracts\Cache\Repository - */ - protected Cache $cache; - - public function __construct(Request $request, Cache $cache) - { - $this->request = $request; - $this->cache = $cache; - } + public function __construct( + protected Request $request, + protected Cache $cache + ) { } /** * Returns the cache key to remember the challenge for the user. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @return string */ protected function cacheKey(User $user): string { diff --git a/src/Services/Webauthn/OptionsFactory.php b/src/Services/Webauthn/OptionsFactory.php index a88c1652..ae9b8c75 100644 --- a/src/Services/Webauthn/OptionsFactory.php +++ b/src/Services/Webauthn/OptionsFactory.php @@ -5,39 +5,27 @@ use Illuminate\Contracts\Cache\Repository as Cache; use Illuminate\Contracts\Config\Repository as Config; use Illuminate\Http\Request; -use Webauthn\PublicKeyCredentialSourceRepository; abstract class OptionsFactory extends CredentialValidator { - /** - * Public Key Credential Source Repository. - * - * @var CredentialRepository - */ - protected CredentialRepository $repository; - /** * Number random bytes. - * - * @var int */ protected int $challengeLength; /** * Timeout in seconds. - * - * @var int */ protected int $timeout; - public function __construct(Request $request, Cache $cache, Config $config, PublicKeyCredentialSourceRepository $repository) - { + public function __construct( + Request $request, + Cache $cache, + Config $config, + protected CredentialRepository $repository + ) { parent::__construct($request, $cache); - if ($repository instanceof CredentialRepository) { - $this->repository = $repository; - } - $this->challengeLength = (int) $config->get('webauthn.challenge_length', 32); $this->timeout = (int) $config->get('webauthn.timeout', 60000); } @@ -45,8 +33,6 @@ public function __construct(Request $request, Cache $cache, Config $config, Publ /** * Get a challenge sequence. * - * @return string - * * @psalm-suppress ArgumentTypeCoercion */ protected function getChallenge(): string diff --git a/src/Services/Webauthn/RequestOptionsFactory.php b/src/Services/Webauthn/RequestOptionsFactory.php index fba55d8b..2da447a0 100644 --- a/src/Services/Webauthn/RequestOptionsFactory.php +++ b/src/Services/Webauthn/RequestOptionsFactory.php @@ -6,9 +6,9 @@ use Illuminate\Contracts\Cache\Repository as Cache; use Illuminate\Contracts\Config\Repository as Config; use Illuminate\Http\Request; +use Webauthn\PublicKeyCredentialDescriptor; use Webauthn\PublicKeyCredentialRequestOptions; use Webauthn\PublicKeyCredentialRpEntity; -use Webauthn\PublicKeyCredentialSourceRepository; final class RequestOptionsFactory extends OptionsFactory { @@ -19,23 +19,19 @@ final class RequestOptionsFactory extends OptionsFactory */ protected ?string $userVerification; - /** - * @var PublicKeyCredentialRpEntity - */ - protected PublicKeyCredentialRpEntity $publicKeyCredentialRpEntity; - - public function __construct(Request $request, Cache $cache, Config $config, PublicKeyCredentialSourceRepository $repository, PublicKeyCredentialRpEntity $publicKeyCredentialRpEntity) - { + public function __construct( + Request $request, + Cache $cache, + Config $config, + CredentialRepository $repository, + protected PublicKeyCredentialRpEntity $publicKeyCredentialRpEntity + ) { parent::__construct($request, $cache, $config, $repository); - $this->publicKeyCredentialRpEntity = $publicKeyCredentialRpEntity; $this->userVerification = self::getUserVerification($config); } /** * Create a new PublicKeyCredentialCreationOptions object. - * - * @param User $user - * @return PublicKeyCredentialRequestOptions */ public function __invoke(User $user): PublicKeyCredentialRequestOptions { @@ -52,9 +48,6 @@ public function __invoke(User $user): PublicKeyCredentialRequestOptions /** * Get user verification preference. - * - * @param \Illuminate\Contracts\Config\Repository $config - * @return string|null */ private static function getUserVerification(Config $config): ?string { @@ -66,12 +59,11 @@ private static function getUserVerification(Config $config): ?string /** * Get the list of allowed keys. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @return array + * @return array */ private function getAllowedCredentials(User $user): array { - return $this->repository->getRegisteredKeys($user); + return CredentialRepository::getRegisteredKeys($user); } /** diff --git a/src/Services/WebauthnRepository.php b/src/Services/WebauthnRepository.php index 26567181..5b469f56 100644 --- a/src/Services/WebauthnRepository.php +++ b/src/Services/WebauthnRepository.php @@ -19,11 +19,6 @@ abstract class WebauthnRepository /** * Create a new key. - * - * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param string $keyName - * @param \Webauthn\PublicKeyCredentialSource $publicKeyCredentialSource - * @return \Illuminate\Database\Eloquent\Model */ public static function create(User $user, string $keyName, PublicKeyCredentialSource $publicKeyCredentialSource): Model { @@ -44,19 +39,14 @@ public static function create(User $user, string $keyName, PublicKeyCredentialSo /** * Register a callback that is responsible for creating a new webauthnkey. - * - * @param callable $callback - * @return void */ - public static function createWebauthnkeyUsing(callable $callback) + public static function createWebauthnkeyUsing(callable $callback): void { static::$createWebauthnkeyUsingCallback = $callback; } /** * Get the model for Webauthnkey. - * - * @return string */ public static function model(): string { @@ -67,8 +57,6 @@ public static function model(): string /** * Create a new model instance. - * - * @return \Illuminate\Database\Eloquent\Model */ public static function createModel(): Model { @@ -83,9 +71,6 @@ public static function createModel(): Model /** * Detect if user has a key. - * - * @param User $user - * @return bool */ public static function hasKey(User $user): bool { diff --git a/src/WebauthnAuthenticatable.php b/src/WebauthnAuthenticatable.php index 42d086b2..91baea6b 100644 --- a/src/WebauthnAuthenticatable.php +++ b/src/WebauthnAuthenticatable.php @@ -9,10 +9,8 @@ trait WebauthnAuthenticatable { /** * Get the webauthn keys associated to this user. - * - * @return HasMany */ - public function webauthnKeys() + public function webauthnKeys(): HasMany { return $this->hasMany(WebauthnKey::class); } diff --git a/src/WebauthnServiceProvider.php b/src/WebauthnServiceProvider.php index ddd0a32a..0b129088 100644 --- a/src/WebauthnServiceProvider.php +++ b/src/WebauthnServiceProvider.php @@ -32,7 +32,6 @@ use LaravelWebauthn\Http\Responses\UpdateResponse; use LaravelWebauthn\Services\Webauthn; use LaravelWebauthn\Services\Webauthn\CredentialAssertionValidator; -use LaravelWebauthn\Services\Webauthn\CredentialRepository; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestFactoryInterface; use Psr\Http\Message\ResponseFactoryInterface; @@ -58,16 +57,13 @@ use Webauthn\Counter\ThrowExceptionIfInvalid; use Webauthn\PublicKeyCredentialLoader; use Webauthn\PublicKeyCredentialRpEntity; -use Webauthn\PublicKeyCredentialSourceRepository; class WebauthnServiceProvider extends ServiceProvider { /** * Bootstrap any application services. - * - * @return void */ - public function boot() + public function boot(): void { $this->configurePublishing(); $this->configureRoutes(); @@ -77,10 +73,8 @@ public function boot() /** * Register any application services. - * - * @return void */ - public function register() + public function register(): void { $this->app->singleton(WebauthnFacade::class, Webauthn::class); @@ -99,10 +93,8 @@ public function register() * Register the package routes. * * @psalm-suppress InvalidArgument - * - * @return void */ - private function configureRoutes() + private function configureRoutes(): void { if (Webauthn::$registersRoutes) { $this->app['router']->group([ @@ -115,10 +107,8 @@ private function configureRoutes() /** * Register the response bindings. - * - * @return void */ - public function registerResponseBindings() + public function registerResponseBindings(): void { $this->app->singleton(DestroyResponseContract::class, DestroyResponse::class); $this->app->singleton(LoginSuccessResponseContract::class, LoginSuccessResponse::class); @@ -130,13 +120,9 @@ public function registerResponseBindings() /** * Bind all the WebAuthn package services to the Service Container. - * - * @return void */ protected function bindWebAuthnPackage(): void { - $this->app->bind(PublicKeyCredentialSourceRepository::class, CredentialRepository::class); - $this->app->bind( PackedAttestationStatementSupport::class, fn ($app) => new PackedAttestationStatementSupport( @@ -197,7 +183,7 @@ protected function bindWebAuthnPackage(): void AuthenticatorAttestationResponseValidator::class, fn ($app) => tap(new AuthenticatorAttestationResponseValidator( $app[AttestationStatementSupportManager::class], - $app[PublicKeyCredentialSourceRepository::class], + null, null, $app[ExtensionOutputCheckerHandler::class] ), function ($responseValidator) use ($app) { @@ -207,7 +193,7 @@ protected function bindWebAuthnPackage(): void $this->app->bind( AuthenticatorAssertionResponseValidator::class, fn ($app) => tap(new AuthenticatorAssertionResponseValidator( - $app[PublicKeyCredentialSourceRepository::class], + null, null, $app[ExtensionOutputCheckerHandler::class], $app[CoseAlgorithmManager::class] @@ -360,7 +346,7 @@ protected function bindPsrInterfaces(): void } } - private function passwordLessWebauthn() + private function passwordLessWebauthn(): void { $this->app['auth']->provider('webauthn', function ($app, array $config) { return new EloquentWebAuthnProvider( @@ -374,10 +360,8 @@ private function passwordLessWebauthn() /** * Register the package's publishable resources. - * - * @return void */ - private function configurePublishing() + private function configurePublishing(): void { if ($this->app->runningInConsole()) { $this->publishes([ @@ -400,10 +384,8 @@ private function configurePublishing() /** * Register other package's resources. - * - * @return void */ - private function configureResources() + private function configureResources(): void { $this->loadViewsFrom(__DIR__.'/../resources/views/', 'webauthn'); $this->loadTranslationsFrom(__DIR__.'/../resources/lang', 'webauthn'); diff --git a/tests/Unit/Http/Controllers/AuthenticateControllerTest.php b/tests/Unit/Http/Controllers/AuthenticateControllerTest.php index 9159ca55..02086033 100644 --- a/tests/Unit/Http/Controllers/AuthenticateControllerTest.php +++ b/tests/Unit/Http/Controllers/AuthenticateControllerTest.php @@ -3,6 +3,7 @@ namespace LaravelWebauthn\Tests\Unit\Http\Controllers; use Illuminate\Foundation\Testing\DatabaseTransactions; +use Illuminate\Http\Request; use LaravelWebauthn\Actions\AttemptToAuthenticate; use LaravelWebauthn\Facades\Webauthn; use LaravelWebauthn\Tests\FeatureTestCase; @@ -50,7 +51,7 @@ protected function setUp(): void */ public function it_auth_get() { - $user = $this->signIn(); + $this->signIn(); Webauthn::shouldReceive('canRegister')->andReturn(true); @@ -67,11 +68,9 @@ public function it_auth_get() */ public function it_auth_success() { - $user = $this->signIn(); + $this->signIn(); $this->mock(AttemptToAuthenticate::class, function (MockInterface $mock) { - $mock->shouldReceive('handle')->andReturnUsing(function ($request, $next) { - $next($request); - }); + $mock->shouldReceive('handle')->andReturnUsing(fn (Request $request, \Closure $next): mixed => $next($request)); }); $response = $this->post('/webauthn/auth', [ @@ -95,7 +94,7 @@ public function it_auth_success() */ public function it_auth_success2() { - $user = $this->signIn(); + $this->signIn(); Webauthn::shouldReceive('validateAssertion')->andReturn(true); @@ -120,7 +119,7 @@ public function it_auth_success2() */ public function it_auth_exception() { - $user = $this->signIn(); + $this->signIn(); Webauthn::shouldReceive('validateAssertion')->andReturn(false); @@ -152,7 +151,7 @@ public function it_auth_exception() */ public function it_auth_success_with_redirect() { - $user = $this->signIn(); + $this->signIn(); Webauthn::shouldReceive('redirects')->andReturn('redirect'); Webauthn::shouldReceive('validateAssertion')->andReturn(true); diff --git a/tests/Unit/Services/Webauthn/CredentialRepositoryTest.php b/tests/Unit/Services/Webauthn/CredentialRepositoryTest.php index e9a33806..1b633c9e 100644 --- a/tests/Unit/Services/Webauthn/CredentialRepositoryTest.php +++ b/tests/Unit/Services/Webauthn/CredentialRepositoryTest.php @@ -4,83 +4,37 @@ use Illuminate\Foundation\Testing\DatabaseTransactions; use LaravelWebauthn\Models\WebauthnKey; +use LaravelWebauthn\Services\Webauthn\CredentialRepository; use LaravelWebauthn\Tests\FeatureTestCase; -use Webauthn\PublicKeyCredentialSourceRepository; -use Webauthn\PublicKeyCredentialUserEntity; class CredentialRepositoryTest extends FeatureTestCase { use DatabaseTransactions; - public function test_find_one() + /** @test */ + public function it_returns_an_empty_array_when_no_keys_are_registered() { - $user = $this->signIn(); - $webauthnKey = factory(WebauthnKey::class)->create([ - 'user_id' => $user->getAuthIdentifier(), - ]); + $user = $this->user(); - $publicKey = $this->app[PublicKeyCredentialSourceRepository::class] - ->findOneByCredentialId($webauthnKey->credentialId); + $this->assertEmpty(WebauthnKey::all()); - $this->assertNotNull($publicKey); + $this->assertEquals([], CredentialRepository::getRegisteredKeys($user)); } - public function test_find_one_null() + /** @test */ + public function it_returns_an_array_with_the_keys() { - $user = $this->signIn(); + $user = $this->user(); - $publicKey = $this->app[PublicKeyCredentialSourceRepository::class] - ->findOneByCredentialId('123'); + $this->assertEmpty(WebauthnKey::all()); - $this->assertNull($publicKey); - } - - public function test_find_one_null_wrong_user() - { - $this->signIn(); $webauthnKey = factory(WebauthnKey::class)->create([ - 'user_id' => '-1', - ]); - - $publicKey = $this->app[PublicKeyCredentialSourceRepository::class] - ->findOneByCredentialId($webauthnKey->credentialId); - - $this->assertNull($publicKey); - } - - public function test_find_all() - { - $user = $this->signIn(); - factory(WebauthnKey::class)->create([ - 'user_id' => $this->user()->getAuthIdentifier(), - ]); - factory(WebauthnKey::class)->create([ 'user_id' => $user->getAuthIdentifier(), + 'credentialId' => '1', ]); - $publicKeys = $this->app[PublicKeyCredentialSourceRepository::class] - ->findAllForUserEntity(new PublicKeyCredentialUserEntity('name', $user->getAuthIdentifier(), 'name')); - - $this->assertNotNull($publicKeys); - $this->assertCount(1, $publicKeys); - } - - public function test_save_credential() - { - $user = $this->signIn(); - $webauthnKey = factory(WebauthnKey::class)->create([ - 'user_id' => $user->getAuthIdentifier(), - ]); - - $publicKeyCredentialSource = $webauthnKey->publicKeyCredentialSource; - $publicKeyCredentialSource->setCounter(154); - - $this->app[PublicKeyCredentialSourceRepository::class] - ->saveCredentialSource($publicKeyCredentialSource); - - $this->assertDatabaseHas('webauthn_keys', [ - 'user_id' => $user->getAuthIdentifier(), - 'counter' => '154', - ]); + $keys = CredentialRepository::getRegisteredKeys($user); + $this->assertCount(1, $keys); + $this->assertEquals('{"type":"public-key","id":"MQ"}', json_encode($keys[0], JSON_THROW_ON_ERROR)); } } diff --git a/tests/User.php b/tests/User.php index a3f7af0e..e9cce838 100644 --- a/tests/User.php +++ b/tests/User.php @@ -12,7 +12,7 @@ class User extends Authenticatable /** * The attributes that are mass assignable. * - * @var string[] + * @var array */ protected $fillable = [ 'name',