2FA-Challenge: Fehlversuch crasht nicht mehr (Route two-factor.login fehlt)
Fortifys FailedTwoFactorLoginResponse leitet auf die Route two-factor.login um, die bei views => false nie registriert wird (RouteNotFoundException). Eigener Response leitet zurück auf die Volt-Challenge-Seite und meldet den Fehler auf Deutsch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
15387d0a3f
commit
b42e0e3f62
3 changed files with 65 additions and 0 deletions
31
app/Http/Responses/FailedTwoFactorChallengeResponse.php
Normal file
31
app/Http/Responses/FailedTwoFactorChallengeResponse.php
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Responses;
|
||||||
|
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Laravel\Fortify\Contracts\FailedTwoFactorLoginResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ersetzt Fortifys FailedTwoFactorLoginResponse: Der Standard leitet auf die
|
||||||
|
* Fortify-Route `two-factor.login` um, die bei `views => false` nicht
|
||||||
|
* registriert ist (RouteNotFoundException). Wir leiten stattdessen zurück auf
|
||||||
|
* unsere Volt-Challenge-Seite.
|
||||||
|
*/
|
||||||
|
class FailedTwoFactorChallengeResponse implements FailedTwoFactorLoginResponse
|
||||||
|
{
|
||||||
|
public function toResponse($request): Response
|
||||||
|
{
|
||||||
|
[$key, $message] = $request->filled('recovery_code')
|
||||||
|
? ['recovery_code', __('Der eingegebene Wiederherstellungs-Code ist ungültig.')]
|
||||||
|
: ['code', __('Der eingegebene Code ist ungültig. Bitte versuchen Sie es mit einem aktuellen Code erneut.')];
|
||||||
|
|
||||||
|
if ($request->wantsJson()) {
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
$key => [$message],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('two-factor.challenge')->withErrors([$key => $message]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ use App\Actions\Fortify\CreateNewUser;
|
||||||
use App\Actions\Fortify\ResetUserPassword;
|
use App\Actions\Fortify\ResetUserPassword;
|
||||||
use App\Actions\Fortify\UpdateUserPassword;
|
use App\Actions\Fortify\UpdateUserPassword;
|
||||||
use App\Actions\Fortify\UpdateUserProfileInformation;
|
use App\Actions\Fortify\UpdateUserProfileInformation;
|
||||||
|
use App\Http\Responses\FailedTwoFactorChallengeResponse;
|
||||||
use App\Http\Responses\RoleAwareLoginResponse;
|
use App\Http\Responses\RoleAwareLoginResponse;
|
||||||
use Illuminate\Cache\RateLimiting\Limit;
|
use Illuminate\Cache\RateLimiting\Limit;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
@ -13,6 +14,7 @@ use Illuminate\Support\Facades\RateLimiter;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Laravel\Fortify\Actions\RedirectIfTwoFactorAuthenticatable;
|
use Laravel\Fortify\Actions\RedirectIfTwoFactorAuthenticatable;
|
||||||
|
use Laravel\Fortify\Contracts\FailedTwoFactorLoginResponse;
|
||||||
use Laravel\Fortify\Contracts\LoginResponse;
|
use Laravel\Fortify\Contracts\LoginResponse;
|
||||||
use Laravel\Fortify\Contracts\TwoFactorLoginResponse;
|
use Laravel\Fortify\Contracts\TwoFactorLoginResponse;
|
||||||
use Laravel\Fortify\Fortify;
|
use Laravel\Fortify\Fortify;
|
||||||
|
|
@ -27,6 +29,9 @@ class FortifyServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
$this->app->singleton(LoginResponse::class, RoleAwareLoginResponse::class);
|
$this->app->singleton(LoginResponse::class, RoleAwareLoginResponse::class);
|
||||||
$this->app->singleton(TwoFactorLoginResponse::class, RoleAwareLoginResponse::class);
|
$this->app->singleton(TwoFactorLoginResponse::class, RoleAwareLoginResponse::class);
|
||||||
|
// Fortifys Default leitet auf die nicht registrierte Route
|
||||||
|
// `two-factor.login` (views => false) – zurück zur Volt-Challenge.
|
||||||
|
$this->app->singleton(FailedTwoFactorLoginResponse::class, FailedTwoFactorChallengeResponse::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,35 @@ test('a valid two-factor code completes login with a role-aware redirect', funct
|
||||||
$this->assertAuthenticatedAs($customer);
|
$this->assertAuthenticatedAs($customer);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('an invalid two-factor code returns to the challenge page with an error', function () {
|
||||||
|
/** @var TestCase $this */
|
||||||
|
$user = User::factory()->create(['is_active' => true]);
|
||||||
|
enableTwoFactor($user);
|
||||||
|
|
||||||
|
$this->withSession(['login.id' => $user->id, 'login.remember' => false])
|
||||||
|
->post('/two-factor-challenge', ['code' => '000000'])
|
||||||
|
->assertRedirect(route('two-factor.challenge'))
|
||||||
|
->assertSessionHasErrors('code');
|
||||||
|
|
||||||
|
$this->assertGuest();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('an invalid recovery code returns to the challenge page with an error', function () {
|
||||||
|
/** @var TestCase $this */
|
||||||
|
$user = User::factory()->create(['is_active' => true]);
|
||||||
|
enableTwoFactor($user);
|
||||||
|
$user->forceFill([
|
||||||
|
'two_factor_recovery_codes' => encrypt(json_encode(['gueltiger-code'])),
|
||||||
|
])->save();
|
||||||
|
|
||||||
|
$this->withSession(['login.id' => $user->id, 'login.remember' => false])
|
||||||
|
->post('/two-factor-challenge', ['recovery_code' => 'falscher-code'])
|
||||||
|
->assertRedirect(route('two-factor.challenge'))
|
||||||
|
->assertSessionHasErrors('recovery_code');
|
||||||
|
|
||||||
|
$this->assertGuest();
|
||||||
|
});
|
||||||
|
|
||||||
test('the fortify login post blocks inactive but verified users', function () {
|
test('the fortify login post blocks inactive but verified users', function () {
|
||||||
/** @var TestCase $this */
|
/** @var TestCase $this */
|
||||||
$user = User::factory()->create(['is_active' => false]);
|
$user = User::factory()->create(['is_active' => false]);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue