mirror of
https://github.com/Bubka/2FAuth.git
synced 2024-11-25 01:34:15 +01:00
Upgrade to laragear/webauthn v2 - Fixes #255
This commit is contained in:
parent
4a8db39ab0
commit
ca903b6fc0
@ -200,7 +200,8 @@ PROXY_LOGOUT_URL=null
|
||||
WEBAUTHN_NAME=2FAuth
|
||||
|
||||
|
||||
# Relying Party ID. If null, the device will fill it internally.
|
||||
# Relying Party ID, should equal the site domain (i.e 2fauth.example.com).
|
||||
# If null, the device will fill it internally (recommended)
|
||||
# See https://webauthn-doc.spomky-labs.com/prerequisites/the-relying-party#how-to-determine-the-relying-party-id
|
||||
|
||||
WEBAUTHN_ID=null
|
||||
|
8
Dockerfile
vendored
8
Dockerfile
vendored
@ -194,14 +194,12 @@ ENV \
|
||||
# Custom logout URL to open when using an auth proxy.
|
||||
PROXY_LOGOUT_URL=null \
|
||||
# WebAuthn settings
|
||||
# Relying Party name, aka the name of the application. If null, defaults to APP_NAME
|
||||
# Relying Party name, aka the name of the application. If blank, defaults to APP_NAME. Do not set to null.
|
||||
WEBAUTHN_NAME=2FAuth \
|
||||
# Relying Party ID. If null, the device will fill it internally.
|
||||
# Relying Party ID, should equal the site domain (i.e 2fauth.example.com).
|
||||
# If null, the device will fill it internally (recommended)
|
||||
# See https://webauthn-doc.spomky-labs.com/prerequisites/the-relying-party#how-to-determine-the-relying-party-id
|
||||
WEBAUTHN_ID=null \
|
||||
# Optional image data in BASE64 (128 bytes maximum) or an image url
|
||||
# See https://webauthn-doc.spomky-labs.com/prerequisites/the-relying-party#relying-party-icon
|
||||
WEBAUTHN_ICON=null \
|
||||
# Use this setting to control how user verification behave during the
|
||||
# WebAuthn authentication flow.
|
||||
#
|
||||
|
@ -16,7 +16,7 @@ class WebauthnTwoFAuthUserProvider extends WebAuthnUserProvider
|
||||
public function validateCredentials($user, array $credentials) : bool
|
||||
{
|
||||
if ($user instanceof WebAuthnAuthenticatable && $this->isSignedChallenge($credentials)) {
|
||||
return $this->validateWebAuthn();
|
||||
return $this->validateWebAuthn($user);
|
||||
}
|
||||
|
||||
// If the user disabled the fallback, we will validate the credential password.
|
||||
|
@ -10,11 +10,10 @@
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Lang;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Laragear\WebAuthn\Enums\UserVerification;
|
||||
use Laragear\WebAuthn\Http\Requests\AssertionRequest;
|
||||
use Laragear\WebAuthn\WebAuthn;
|
||||
|
||||
class WebAuthnLoginController extends Controller
|
||||
{
|
||||
@ -44,10 +43,10 @@ class WebAuthnLoginController extends Controller
|
||||
public function options(AssertionRequest $request) : Responsable|JsonResponse
|
||||
{
|
||||
switch (config('webauthn.user_verification')) {
|
||||
case WebAuthn::USER_VERIFICATION_DISCOURAGED:
|
||||
case UserVerification::DISCOURAGED:
|
||||
$request = $request->fastLogin(); // Makes the authenticator to only check for user presence on registration
|
||||
break;
|
||||
case WebAuthn::USER_VERIFICATION_REQUIRED:
|
||||
case UserVerification::REQUIRED:
|
||||
$request = $request->secureLogin(); // Makes the authenticator to always verify the user thoroughly on registration
|
||||
break;
|
||||
}
|
||||
@ -88,17 +87,6 @@ public function login(WebauthnAssertedRequest $request)
|
||||
return $this->sendLockoutResponse($request);
|
||||
}
|
||||
|
||||
if ($request->has('response')) {
|
||||
$response = $request->response;
|
||||
|
||||
// Some authenticators do not send a userHandle so we hack the response to be compliant
|
||||
// with Laragear\WebAuthn implementation that waits for a userHandle
|
||||
if (! Arr::exists($response, 'userHandle') || blank($response['userHandle'])) {
|
||||
$response['userHandle'] = User::getFromCredentialId($request->id)?->userHandle();
|
||||
$request->merge(['response' => $response]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->attemptLogin($request)) {
|
||||
return $this->sendLoginResponse($request);
|
||||
}
|
||||
|
@ -6,9 +6,9 @@
|
||||
use Illuminate\Contracts\Support\Responsable;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Laragear\WebAuthn\Enums\UserVerification;
|
||||
use Laragear\WebAuthn\Http\Requests\AttestationRequest;
|
||||
use Laragear\WebAuthn\Http\Requests\AttestedRequest;
|
||||
use Laragear\WebAuthn\WebAuthn;
|
||||
|
||||
class WebAuthnRegisterController extends Controller
|
||||
{
|
||||
@ -18,10 +18,10 @@ class WebAuthnRegisterController extends Controller
|
||||
public function options(AttestationRequest $request) : Responsable
|
||||
{
|
||||
switch (config('webauthn.user_verification')) {
|
||||
case WebAuthn::USER_VERIFICATION_DISCOURAGED:
|
||||
case UserVerification::DISCOURAGED:
|
||||
$request = $request->fastRegistration(); // Makes the authenticator to only check for user presence on registration
|
||||
break;
|
||||
case WebAuthn::USER_VERIFICATION_REQUIRED:
|
||||
case UserVerification::REQUIRED:
|
||||
$request = $request->secureRegistration(); // Makes the authenticator to always verify the user thoroughly on registration
|
||||
break;
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
use App\Notifications\WebauthnRecoveryNotification;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @see \App\Models\WebAuthnAuthenticatable
|
||||
@ -12,20 +11,6 @@
|
||||
*/
|
||||
trait WebAuthnManageCredentials
|
||||
{
|
||||
/**
|
||||
* Return the handle used to identify his credentials.
|
||||
*/
|
||||
public function userHandle() : string
|
||||
{
|
||||
// Laragear\WebAuthn uses Ramsey\Uuid\Uuid::fromString()->getHex()->toString()
|
||||
// to obtain a UUID v4 with dashes removed and uses it as user_id (aka userHandle)
|
||||
// see https://github.com/ramsey/uuid/blob/4.x/src/Uuid.php#L379
|
||||
// and Laragear\WebAuthn\Assertion\Validator\Pipes\CheckCredentialIsForUser::validateId()
|
||||
|
||||
return $this->webAuthnCredentials()->value('user_id')
|
||||
?? str_replace('-', '', Str::uuid()->toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a new alias for a given WebAuthn credential.
|
||||
*/
|
||||
|
@ -6,11 +6,6 @@
|
||||
|
||||
interface WebAuthnAuthenticatable extends Authenticatable
|
||||
{
|
||||
/**
|
||||
* Return the handle used to identify his credentials.
|
||||
*/
|
||||
public function userHandle() : string;
|
||||
|
||||
/**
|
||||
* Saves a new alias for a given WebAuthn credential.
|
||||
*/
|
||||
|
@ -27,7 +27,7 @@
|
||||
"guzzlehttp/guzzle": "^7.2",
|
||||
"jackiedo/dotenv-editor": "^2.1",
|
||||
"khanamiryan/qrcode-detector-decoder": "^2.0.2",
|
||||
"laragear/webauthn": "^1.2.0",
|
||||
"laragear/webauthn": "^2.0",
|
||||
"laravel/framework": "^10.10",
|
||||
"laravel/passport": "^11.2",
|
||||
"laravel/socialite": "^5.10",
|
||||
|
109
composer.lock
generated
109
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "15022c60c2ef59e0821ae0064f477e50",
|
||||
"content-hash": "7c27f612b0b319b88f2b8b3f1d52a51d",
|
||||
"packages": [
|
||||
{
|
||||
"name": "brick/math",
|
||||
@ -1918,34 +1918,101 @@
|
||||
"time": "2022-11-17T10:54:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laragear/webauthn",
|
||||
"version": "v1.2.1",
|
||||
"name": "laragear/meta-model",
|
||||
"version": "v1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Laragear/WebAuthn.git",
|
||||
"reference": "e57ac258b0d76eee4ab77c1e1b465f5d8e0c46de"
|
||||
"url": "https://github.com/Laragear/MetaModel.git",
|
||||
"reference": "86aa8bbd0e1b9d03467a0257f0cd5815b6836a34"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Laragear/WebAuthn/zipball/e57ac258b0d76eee4ab77c1e1b465f5d8e0c46de",
|
||||
"reference": "e57ac258b0d76eee4ab77c1e1b465f5d8e0c46de",
|
||||
"url": "https://api.github.com/repos/Laragear/MetaModel/zipball/86aa8bbd0e1b9d03467a0257f0cd5815b6836a34",
|
||||
"reference": "86aa8bbd0e1b9d03467a0257f0cd5815b6836a34",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/database": "10.*|11.*",
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.6",
|
||||
"phpunit/phpunit": "^10.5|11.*"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laragear\\MetaModel\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Italo Israel Baeza Cabrera",
|
||||
"email": "DarkGhostHunter@Gmail.com",
|
||||
"homepage": "https://github.com/sponsors/DarkGhostHunter",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Let other developers customize your package model and migrations",
|
||||
"keywords": [
|
||||
"database",
|
||||
"eloquent",
|
||||
"laravel",
|
||||
"model"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Laragear/MetaModel/issues",
|
||||
"source": "https://github.com/Laragear/MetaModel"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sponsors/DarkGhostHunter",
|
||||
"type": "Github Sponsorship"
|
||||
},
|
||||
{
|
||||
"url": "https://paypal.me/darkghosthunter",
|
||||
"type": "Paypal"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-15T23:27:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laragear/webauthn",
|
||||
"version": "v2.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Laragear/WebAuthn.git",
|
||||
"reference": "15b29db0edb0a12c0fa45c404e57b0d5f1789465"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Laragear/WebAuthn/zipball/15b29db0edb0a12c0fa45c404e57b0d5f1789465",
|
||||
"reference": "15b29db0edb0a12c0fa45c404e57b0d5f1789465",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"ext-openssl": "*",
|
||||
"illuminate/auth": "9.*|10.*",
|
||||
"illuminate/config": "9.*|10.*",
|
||||
"illuminate/database": "9.*|10.*",
|
||||
"illuminate/encryption": "9.*|10.*",
|
||||
"illuminate/http": "9.*|10.*",
|
||||
"illuminate/session": "9.*|10.*",
|
||||
"illuminate/support": "9.*|10.*",
|
||||
"php": "8.*"
|
||||
"illuminate/auth": "10.*|11.*",
|
||||
"illuminate/config": "10.*|11.*",
|
||||
"illuminate/database": "10.*|11.*",
|
||||
"illuminate/encryption": "10.*|11.*",
|
||||
"illuminate/http": "10.*|11.*",
|
||||
"illuminate/session": "10.*|11.*",
|
||||
"illuminate/support": "10.*|11.*",
|
||||
"laragear/meta-model": "^1.1",
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"jetbrains/phpstorm-attributes": "*",
|
||||
"orchestra/testbench": "^7.22|8.*"
|
||||
"ext-sodium": "*",
|
||||
"orchestra/testbench": "8.*|9.*"
|
||||
},
|
||||
"suggest": {
|
||||
"paragonie/sodium_compat": "To enable EdDSA 25519 keys from authenticators, if `ext-sodium` is unavailable."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@ -1976,7 +2043,7 @@
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Authenticate your users with biometric data, devices or USB keys.",
|
||||
"description": "Authenticate users with Passkeys: fingerprints, patterns and biometric data.",
|
||||
"homepage": "https://github.com/laragear/webauthn",
|
||||
"keywords": [
|
||||
"Authentication",
|
||||
@ -1988,8 +2055,8 @@
|
||||
"windows hello"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Laragear/TwoFactor/issues",
|
||||
"source": "https://github.com/Laragear/TwoFactor"
|
||||
"issues": "https://github.com/Laragear/WebAuthn/issues",
|
||||
"source": "https://github.com/Laragear/WebAuthn"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2001,7 +2068,7 @@
|
||||
"type": "Paypal"
|
||||
}
|
||||
],
|
||||
"time": "2023-03-09T18:38:16+00:00"
|
||||
"time": "2024-03-18T22:38:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
|
@ -91,14 +91,12 @@ services:
|
||||
# Custom logout URL to open when using an auth proxy.
|
||||
- PROXY_LOGOUT_URL=null
|
||||
# WebAuthn settings
|
||||
# Relying Party name, aka the name of the application. If null, defaults to APP_NAME
|
||||
# Relying Party name, aka the name of the application. If blank, defaults to APP_NAME. Do not set to null.
|
||||
- WEBAUTHN_NAME=2FAuth
|
||||
# Relying Party ID. If null, the device will fill it internally.
|
||||
# Relying Party ID, should equal the site domain (i.e 2fauth.example.com).
|
||||
# If null, the device will fill it internally (recommended)
|
||||
# See https://webauthn-doc.spomky-labs.com/prerequisites/the-relying-party#how-to-determine-the-relying-party-id
|
||||
- WEBAUTHN_ID=null
|
||||
# Optional image data in BASE64 (128 bytes maximum) or an image url
|
||||
# See https://webauthn-doc.spomky-labs.com/prerequisites/the-relying-party#relying-party-icon
|
||||
- WEBAUTHN_ICON=null
|
||||
# Use this setting to control how user verification behave during the
|
||||
# WebAuthn authentication flow.
|
||||
#
|
||||
|
@ -8,7 +8,7 @@
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laragear\WebAuthn\Assertion\Validator\AssertionValidator;
|
||||
use Laragear\WebAuthn\WebAuthn;
|
||||
use Laragear\WebAuthn\Enums\UserVerification;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use Tests\FeatureTestCase;
|
||||
|
||||
@ -369,7 +369,7 @@ public function test_too_many_invalid_login_attempts_returns_too_many_request_er
|
||||
*/
|
||||
public function test_get_options_returns_success()
|
||||
{
|
||||
Config::set('webauthn.user_verification', WebAuthn::USER_VERIFICATION_PREFERRED);
|
||||
Config::set('webauthn.user_verification', UserVerification::PREFERRED);
|
||||
|
||||
$this->user = User::factory()->create(['email' => self::EMAIL]);
|
||||
|
||||
@ -409,7 +409,7 @@ public function test_get_options_returns_success()
|
||||
*/
|
||||
public function test_get_options_for_securelogin_returns_required_userVerification()
|
||||
{
|
||||
Config::set('webauthn.user_verification', WebAuthn::USER_VERIFICATION_REQUIRED);
|
||||
Config::set('webauthn.user_verification', UserVerification::REQUIRED);
|
||||
|
||||
$this->user = User::factory()->create(['email' => self::EMAIL]);
|
||||
|
||||
@ -451,7 +451,7 @@ public function test_get_options_for_securelogin_returns_required_userVerificati
|
||||
*/
|
||||
public function test_get_options_for_fastlogin_returns_discouraged_userVerification()
|
||||
{
|
||||
Config::set('webauthn.user_verification', WebAuthn::USER_VERIFICATION_DISCOURAGED);
|
||||
Config::set('webauthn.user_verification', UserVerification::DISCOURAGED);
|
||||
|
||||
$this->user = User::factory()->create(['email' => self::EMAIL]);
|
||||
|
||||
|
@ -5,10 +5,10 @@
|
||||
use App\Http\Controllers\Auth\WebAuthnRegisterController;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Laragear\WebAuthn\Enums\UserVerification;
|
||||
use Laragear\WebAuthn\Http\Requests\AttestationRequest;
|
||||
use Laragear\WebAuthn\Http\Requests\AttestedRequest;
|
||||
use Laragear\WebAuthn\JsonTransport;
|
||||
use Laragear\WebAuthn\WebAuthn;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use Tests\FeatureTestCase;
|
||||
|
||||
@ -38,7 +38,7 @@ public function setUp() : void
|
||||
*/
|
||||
public function test_uses_attestation_with_fastRegistration_request() : void
|
||||
{
|
||||
Config::set('webauthn.user_verification', WebAuthn::USER_VERIFICATION_DISCOURAGED);
|
||||
Config::set('webauthn.user_verification', UserVerification::DISCOURAGED);
|
||||
|
||||
$request = $this->mock(AttestationRequest::class);
|
||||
|
||||
@ -55,7 +55,7 @@ public function test_uses_attestation_with_fastRegistration_request() : void
|
||||
*/
|
||||
public function test_uses_attestation_with_secureRegistration_request() : void
|
||||
{
|
||||
Config::set('webauthn.user_verification', WebAuthn::USER_VERIFICATION_REQUIRED);
|
||||
Config::set('webauthn.user_verification', UserVerification::REQUIRED);
|
||||
|
||||
$request = $this->mock(AttestationRequest::class);
|
||||
|
||||
|
@ -2,14 +2,10 @@
|
||||
|
||||
namespace Tests\Feature\Models;
|
||||
|
||||
use App\Extensions\WebauthnCredentialBroker;
|
||||
use App\Models\Group;
|
||||
use App\Models\TwoFAccount;
|
||||
use App\Models\User;
|
||||
use Database\Factories\UserFactory;
|
||||
use Illuminate\Auth\Events\PasswordReset;
|
||||
use Illuminate\Http\Testing\FileFactory;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
@ -52,7 +48,7 @@ public function test_admin_scope_returns_only_admin()
|
||||
*/
|
||||
public function test_isAdministrator_returns_correct_state()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$admin = User::factory()->administrator()->create();
|
||||
|
||||
$this->assertEquals($user->isAdministrator(), false);
|
||||
@ -88,7 +84,7 @@ public function test_promoteToAdministrator_demote_administrator_status()
|
||||
*/
|
||||
public function test_resetPassword_resets_password_with_success()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
$oldPassword = $user->password;
|
||||
|
||||
$user->resetPassword();
|
||||
@ -118,7 +114,7 @@ public function test_delete_removes_user_data()
|
||||
$user = User::factory()->create();
|
||||
TwoFAccount::factory()->for($user)->create();
|
||||
Group::factory()->for($user)->create();
|
||||
|
||||
|
||||
DB::table('webauthn_credentials')->insert([
|
||||
'id' => '-VOLFKPY-_FuMI_sJ7gMllK76L3VoRUINj6lL_Z3qDg',
|
||||
'authenticatable_type' => \App\Models\User::class,
|
||||
@ -139,7 +135,7 @@ public function test_delete_removes_user_data()
|
||||
Password::broker()->createToken($user);
|
||||
|
||||
$user->delete();
|
||||
|
||||
|
||||
$this->assertDatabaseMissing('twofaccounts', [
|
||||
'user_id' => $user->id,
|
||||
]);
|
||||
|
Loading…
Reference in New Issue
Block a user