mirror of
https://github.com/pelican-dev/panel.git
synced 2025-05-20 00:34:44 +02:00
Basic two factor auth implementation (#1050)
* Basic two factor auth * Remove unused import * Add translation
This commit is contained in:
parent
da195fd2fe
commit
36a38ab947
@ -3,17 +3,84 @@
|
|||||||
namespace App\Filament\Pages\Auth;
|
namespace App\Filament\Pages\Auth;
|
||||||
|
|
||||||
use App\Extensions\OAuth\Providers\OAuthProvider;
|
use App\Extensions\OAuth\Providers\OAuthProvider;
|
||||||
|
use App\Models\User;
|
||||||
use Coderflex\FilamentTurnstile\Forms\Components\Turnstile;
|
use Coderflex\FilamentTurnstile\Forms\Components\Turnstile;
|
||||||
|
use Filament\Facades\Filament;
|
||||||
use Filament\Forms\Components\Actions;
|
use Filament\Forms\Components\Actions;
|
||||||
use Filament\Forms\Components\Actions\Action;
|
use Filament\Forms\Components\Actions\Action;
|
||||||
use Filament\Forms\Components\Component;
|
use Filament\Forms\Components\Component;
|
||||||
use Filament\Forms\Components\TextInput;
|
use Filament\Forms\Components\TextInput;
|
||||||
|
use Filament\Http\Responses\Auth\Contracts\LoginResponse;
|
||||||
|
use Filament\Notifications\Notification;
|
||||||
use Filament\Pages\Auth\Login as BaseLogin;
|
use Filament\Pages\Auth\Login as BaseLogin;
|
||||||
use Filament\Support\Colors\Color;
|
use Filament\Support\Colors\Color;
|
||||||
|
use Illuminate\Support\Facades\Config;
|
||||||
|
use Illuminate\Support\Sleep;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use PragmaRX\Google2FA\Google2FA;
|
||||||
|
|
||||||
class Login extends BaseLogin
|
class Login extends BaseLogin
|
||||||
{
|
{
|
||||||
|
private Google2FA $google2FA;
|
||||||
|
|
||||||
|
public bool $verifyTwoFactor = false;
|
||||||
|
|
||||||
|
public function boot(Google2FA $google2FA): void
|
||||||
|
{
|
||||||
|
$this->google2FA = $google2FA;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authenticate(): ?LoginResponse
|
||||||
|
{
|
||||||
|
$data = $this->form->getState();
|
||||||
|
Filament::auth()->once($this->getCredentialsFromFormData($data));
|
||||||
|
|
||||||
|
/** @var ?User $user */
|
||||||
|
$user = Filament::auth()->user();
|
||||||
|
|
||||||
|
// Make sure that rate limits apply
|
||||||
|
if (!$user) {
|
||||||
|
return parent::authenticate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2FA disabled
|
||||||
|
if (!$user->use_totp) {
|
||||||
|
return parent::authenticate();
|
||||||
|
}
|
||||||
|
|
||||||
|
$token = $data['2fa'] ?? null;
|
||||||
|
|
||||||
|
// 2FA not shown yet
|
||||||
|
if ($token === null) {
|
||||||
|
$this->verifyTwoFactor = true;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$isValidToken = $this->google2FA->verifyKey(
|
||||||
|
$user->totp_secret,
|
||||||
|
$token,
|
||||||
|
Config::integer('panel.auth.2fa.window'),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$isValidToken) {
|
||||||
|
// Buffer to prevent bruteforce
|
||||||
|
Sleep::sleep(1);
|
||||||
|
|
||||||
|
Notification::make()
|
||||||
|
->title(trans('auth.failed-two-factor'))
|
||||||
|
->body(trans('auth.failed'))
|
||||||
|
->color('danger')
|
||||||
|
->icon('tabler-auth-2fa')
|
||||||
|
->danger()
|
||||||
|
->send();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::authenticate();
|
||||||
|
}
|
||||||
|
|
||||||
protected function getForms(): array
|
protected function getForms(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@ -24,6 +91,7 @@ class Login extends BaseLogin
|
|||||||
$this->getPasswordFormComponent(),
|
$this->getPasswordFormComponent(),
|
||||||
$this->getRememberFormComponent(),
|
$this->getRememberFormComponent(),
|
||||||
$this->getOAuthFormComponent(),
|
$this->getOAuthFormComponent(),
|
||||||
|
$this->getTwoFactorAuthenticationComponent(),
|
||||||
Turnstile::make('captcha')
|
Turnstile::make('captcha')
|
||||||
->hidden(!config('turnstile.turnstile_enabled'))
|
->hidden(!config('turnstile.turnstile_enabled'))
|
||||||
->validationMessages([
|
->validationMessages([
|
||||||
@ -36,6 +104,15 @@ class Login extends BaseLogin
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getTwoFactorAuthenticationComponent(): Component
|
||||||
|
{
|
||||||
|
return TextInput::make('2fa')
|
||||||
|
->label(trans('auth.two-factor-code'))
|
||||||
|
->hidden(fn () => !$this->verifyTwoFactor)
|
||||||
|
->required()
|
||||||
|
->live();
|
||||||
|
}
|
||||||
|
|
||||||
protected function throwFailureValidationException(): never
|
protected function throwFailureValidationException(): never
|
||||||
{
|
{
|
||||||
$this->dispatch('reset-captcha');
|
$this->dispatch('reset-captcha');
|
||||||
|
22
lang/en/auth.php
Normal file
22
lang/en/auth.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Authentication Language Lines
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The following language lines are used during authentication for various
|
||||||
|
| messages that we need to display to the user. You are free to modify
|
||||||
|
| these language lines according to your application's requirements.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'failed' => 'These credentials do not match our records.',
|
||||||
|
'failed-two-factor' => 'Incorrect 2FA Code',
|
||||||
|
'two-factor-code' => 'Two Factor Code',
|
||||||
|
'password' => 'The provided password is incorrect.',
|
||||||
|
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
|
||||||
|
|
||||||
|
];
|
Loading…
x
Reference in New Issue
Block a user