Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add forced() method and middleware #28

Merged
merged 15 commits into from
Sep 15, 2024
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,36 @@ use Vormkracht10\TwoFactorAuth\Pages\TwoFactor;
])
```

### Forcing Two Factor Authentication

If you want to force users to enable Two Factor Authentication, you can add this to your `PanelProvider`:

```php
->plugins([
TwoFactorAuthPlugin::make()->forced(),
])
```

> [!WARNING]
> When you're using the `forced` method, make sure to set the `multi_tenancy` option to `true` in the `filament-two-factor-auth.php` config file when you're using a multi-tenant setup. Otherwise, the forced setting will not work. We cannot check the tenant in the `PanelProvider` because the user is not authenticated yet.

#### Customizing the forced message

If you want to customize the forced message, you can publish the language file:

```bash
php artisan vendor:publish --tag="filament-two-factor-auth-translations"
```

Then you can customize the message in the `lang/vendor/filament-two-factor-auth/en.json` file. You should change the following keys:

```json
{
"Your administrator requires you to enable two-factor authentication.": "Your custom message here.",
"Two-Factor Authentication mandatory": "Your custom title here."
}
```

## Testing

```bash
Expand Down
18 changes: 10 additions & 8 deletions resources/lang/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
"Confirm": "Bevestigen",
"Deactivate": "Deactiveer",
"Email": "E-mail",
"Generate new recovery codes": "Genereer nieuwe herstelcodes",
"Hello": "Hallo",
"If you didn't try to log in, please change your password immediately to protect your account.": "Als u niet heeft geprobeerd in te loggen, wijzig dan onmiddellijk uw wachtwoord om uw account te beschermen.",
"Kind regards": "Met vriendelijke groet",
"Login": "Inloggen",
"Or scan the QR code with your authenticator app": "Of scan de QR-code met uw authenticator-app",
"Password Confirmation": "Wachtwoordbevestiging",
Expand All @@ -19,19 +23,17 @@
"Secure your account": "Beveilig uw account",
"Submit": "Verzenden",
"Successfully resend the OTP code": "OTP-code succesvol opnieuw verzonden",
"The provided two factor authentication code was invalid.": "De verstrekte tweestapsverificatiecode was ongeldig.",
"The secret key to setup the authenticator app is": "De geheime sleutel om de authenticator-app in te stellen is",
"Two-Factor Authentication": "Tweestapsverificatie",
"Two-Factor Authentication enabled": "Tweestapsverificatie ingeschakeld",
"Two-Factor Authentication mandatory": "Tweestapsverificatie verplicht",
"Verify": "Verifiëren",
"You can disable two factor authentication at any time by using the button below": "U kunt tweestapsverificatie op elk moment uitschakelen met de onderstaande knop",
"You have :amount options to confirm your identity, please choose one of the options below to continue": "U heeft :amount opties om uw identiteit te bevestigen, kies een van de onderstaande opties om door te gaan",
"You recently requested to log in to your account. To complete the login, please use the following two-factor authentication (2FA) code:": "U heeft onlangs gevraagd om in te loggen op uw account. Gebruik de volgende tweestapsverificatie (2FA) code om de login te voltooien:",
"Your account has been secured with two factor authentication": "Uw account is beveiligd met tweestapsverificatie",
"Your administrator requires you to enable two-factor authentication.": "Uw beheerder vereist dat u tweestapsverificatie inschakelt.",
"Your security code for :app": "Uw beveiligingscode voor :app",
"Your security code is": "Uw beveiligingscode is",
"The provided two factor authentication code was invalid.": "De verstrekte tweestapsverificatiecode was ongeldig.",
"Generate new recovery codes": "Genereer nieuwe herstelcodes",
"You can disable two factor authentication at any time by using the button below": "U kunt tweestapsverificatie op elk moment uitschakelen met de onderstaande knop",
"You recently requested to log in to your account. To complete the login, please use the following two-factor authentication (2FA) code:": "U heeft onlangs gevraagd om in te loggen op uw account. Gebruik de volgende tweestapsverificatie (2FA) code om de login te voltooien:",
"If you didn't try to log in, please change your password immediately to protect your account.": "Als u niet heeft geprobeerd in te loggen, wijzig dan onmiddellijk uw wachtwoord om uw account te beschermen.",
"Kind regards": "Met vriendelijke groet",
"Hello": "Hallo"
"Your security code is": "Uw beveiligingscode is"
}
3 changes: 2 additions & 1 deletion resources/views/two-factor.blade.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<x-filament-panels::page>

<div class="space-y-10 divide-y divide-gray-900/10 ">
<div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3">
<div class="pr-4 sm:px-0">
<h2 class="text-base font-semibold leading-7 dark:bg-white">
{{ __('Secure your account') }}
{{ __('Secure your account') }} sdfsadfsa
</h2>

@if (!$showingRecoveryCodes && $user->two_factor_confirmed_at)
Expand Down
31 changes: 31 additions & 0 deletions src/Http/Middleware/ForceTwoFactor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Vormkracht10\TwoFactorAuth\Http\Middleware;

use Closure;
use Filament\Facades\Filament;
use Illuminate\Http\Request;

class ForceTwoFactor
{
public function handle(Request $request, Closure $next): mixed
{
$user = Filament::auth()->user();

if ($request->is('*/two-factor') || $request->is('*/logout')) {
return $next($request);
}

if ($user && ! $user->two_factor_confirmed_at) {
$currentPanel = Filament::getCurrentPanel();

if ($currentPanel) {
return redirect()->to(route('filament.' . $currentPanel->getId() . '.pages.two-factor', [
'tenant' => Filament::getTenant(),
]))->with('two_factor_redirect_message', __('Your administrator requires you to enable two-factor authentication.'));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this customizable?
Example:

->forced(message: __('Some message')

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes maybe it's better to let the developer choose which message to show to the user. I'm also not really satisfied with showing the message yet. Weird enough I couldn't show the message in the blade view itself using the session helper..

}
}

return $next($request);
}
}
13 changes: 11 additions & 2 deletions src/Pages/TwoFactor.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ public function getTitle(): string | Htmlable

public function mount(): void
{
if (session('two_factor_redirect_message')) {
Notification::make()
->title(__('Two-Factor Authentication mandatory'))
->body(session('two_factor_redirect_message'))
->danger()
->persistent()
->send();
}

$this->twoFactorOptionsCount = config('filament-two-factor-auth.options') ? count(config('filament-two-factor-auth.options')) : 0;

$this->user = Auth::user();
Expand Down Expand Up @@ -88,7 +97,7 @@ public function getConfirmationForm(): array
return [
TextInput::make('current_password')
->label(__('Password'))
->dehydrateStateUsing(fn ($state) => filled($state))
->dehydrateStateUsing(fn($state) => filled($state))
->required()
->password()
->inlineLabel()
Expand Down Expand Up @@ -272,4 +281,4 @@ public function regenerateRecoveryCodes(GenerateNewRecoveryCodes $generate): voi

$this->showingRecoveryCodes = true;
}
}
}
27 changes: 25 additions & 2 deletions src/TwoFactorAuthPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
namespace Vormkracht10\TwoFactorAuth;

use Filament\Contracts\Plugin;
use Filament\Facades\Filament;
use Filament\Navigation\MenuItem;
use Filament\Panel;
use Vormkracht10\TwoFactorAuth\Http\Middleware\ForceTwoFactor;
use Vormkracht10\TwoFactorAuth\Pages\TwoFactor;

class TwoFactorAuthPlugin implements Plugin
{
private bool $forced = false;

public function getId(): string
{
return 'filament-two-factor-auth';
Expand All @@ -24,12 +28,19 @@ public function register(Panel $panel): void
])
->viteTheme('vendor/vormkracht10/filament-2fa/resources/dist/filament-two-factor-auth.css');

if ($this->isForced()) {
$middlewareMethod = config('filament-two-factor-auth.enabled_features.multi_tenancy') ? 'tenantMiddleware' : 'middleware';
$panel->$middlewareMethod([
ForceTwoFactor::class,
]);
}

if (! config('filament-two-factor-auth.enabled_features.multi_tenancy')) {
$panel->userMenuItems([
'two-factor-authentication' => MenuItem::make()
->icon('heroicon-o-lock-closed')
->label(__('Two-Factor Authentication'))
->url(fn (): string => TwoFactor::getUrl()),
->url(fn(): string => TwoFactor::getUrl()),
]);
}

Expand All @@ -55,4 +66,16 @@ public static function get(): static

return $plugin;
}
}

public function forced(bool $forced = true, bool $withTenancy = false): self
{
$this->forced = $forced;

return $this;
}

public function isForced(): bool
{
return $this->forced;
}
}