presseportale/app/Http/Responses/RoleAwareLoginResponse.php
Kevin Adametz f4ca452c6b Security: 2FA-Bypass beheben & Login-Pfade konsolidieren
Befund (Review 16.06.): Der Volt-Login machte direkt Auth::attempt() und umging
Fortifys 2FA-Pipeline (2FA-Bypass); zusätzlich existierte der Fortify-POST /login
parallel mit schwächeren Post-Login-Regeln.

Fix (Volt-nativ):
- Volt-Login prüft Credentials ohne sofortiges Login; bei aktivem 2FA wird der
  Session-Vertrag login.id/login.remember gesetzt und auf eine neue Volt-
  2FA-Challenge-Seite (/two-factor-challenge) geleitet, die an Fortifys
  bestehenden Controller postet (TOTP + Recovery-Code).
- Gemeinsame Post-Login-Logik in App\Support\LoginRedirect (rollengerechtes
  Home + 403-sicherer intended-Redirect), genutzt von Volt-Login UND Response.
- RoleAwareLoginResponse implementiert jetzt LoginResponse UND
  TwoFactorLoginResponse und erzwingt einheitlich: unverifiziert → Notice,
  verifiziert-inaktiv → Logout+Fehler, sonst 403-sicherer Redirect. Damit ist
  auch der direkte Fortify-POST-Pfad gehärtet.

Tests: 2FA-Übergabe, Challenge-Guard, voller TOTP-Flow, Fortify-POST blockt
inaktive User und hält Customer aus dem Admin-Bereich.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-16 10:00:15 +00:00

49 lines
1.7 KiB
PHP

<?php
namespace App\Http\Responses;
use App\Support\LoginRedirect;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
use Laravel\Fortify\Contracts\TwoFactorLoginResponse as TwoFactorLoginResponseContract;
/**
* Einheitliche Antwort für den Fortify-POST-Login UND den Abschluss der
* 2FA-Challenge. Spiegelt dieselbe Policy wie der Volt-Login:
* - unverifiziert → Verifizierungs-Notice
* - verifiziert, aber inaktiv → Login blockiert (Logout + Fehler)
* - sonst rollengerechter, 403-sicherer Redirect (intended nur wenn erreichbar)
*/
class RoleAwareLoginResponse implements LoginResponseContract, TwoFactorLoginResponseContract
{
public function toResponse($request): RedirectResponse|JsonResponse
{
if ($request instanceof Request && $request->wantsJson()) {
return new JsonResponse('', 204);
}
$user = $request->user();
if ($user && ! $user->hasVerifiedEmail()) {
return redirect()->route('verification.notice');
}
if ($user && ! $user->is_active) {
Auth::guard('web')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect()->route('login')->withErrors([
'email' => __('Ihr Konto ist nicht aktiv. Bitte wenden Sie sich an den Support.'),
]);
}
$default = LoginRedirect::homeFor($user);
$intended = $request->session()->pull('url.intended');
return redirect(LoginRedirect::safeTarget($user, $intended, $default));
}
}