presseportale/tests/Feature/Auth/FortifyTwoFactorRoutesTest.php
Kevin Adametz 05cf53e17d security/api/betrieb: Fortify-2FA-Nebenwege gesperrt, Policy nur für aktive Super-Admins, Nachprüfungen aus dem Umsetzungsaudit (Block 7, U08–U10, U13, 7.1, 7.2, 7.5)
- Fortifys sieben 2FA-Verwaltungsrouten antworten mit 404 (Middleware über
  fortify.middleware); die Sicherheitsseite verlangt weiter den zweiten Faktor (U09)
- PressReleasePolicy/CompanyPolicy::before() bejahen nur aktive Super-Admins (7.2)
- API-Update prüft bei Portalwechsel die bestehende Kategorie gegen das neue Portal (U10)
- Aggregation: Zeitbudget 480 s unter dem Lock von 600 s, Marke nur unter
  Zeilensperre vom erwarteten Stand aus, sonst Fehler-Exit (U13)
- Newsletter-Bereinigungsmigration behält je Paar die sent-Zeile (U08)
- E-Mail-Wechsel stößt den Rechte-Sync sofort an; company-memberships:audit
  --classify zeigt vorher die Kandidaten und begrenzt mit --before (7.1)
- Detailseite wählt bei Slug-Kollision wie der Melde-Resolver (7.5)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 12:03:04 +00:00

55 lines
2 KiB
PHP

<?php
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Tests\TestCase;
/**
* Fortifys eigene 2FA-Verwaltungsrouten verlangen nur `password.confirm`.
* Das Projekt verlangt den zweiten Faktor (E3) und beantwortet diese
* Nebenwege deshalb mit 404 (Audit U09).
*/
function twoFactorUser(): User
{
return User::factory()->create([
'is_active' => true,
'password' => Hash::make('geheim-1234'),
'two_factor_secret' => encrypt('ABCDEFGHIJKLMNOP'),
'two_factor_recovery_codes' => encrypt(json_encode(['code-one', 'code-two'])),
'two_factor_confirmed_at' => now(),
]);
}
test('fortify two-factor management routes are unreachable even with a confirmed password (Audit U09)', function (string $method, string $uri) {
/** @var TestCase $this */
$user = twoFactorUser();
$this->actingAs($user)
->withSession(['auth.password_confirmed_at' => time()])
->{$method}($uri)
->assertNotFound();
expect($user->fresh()->two_factor_secret)->not->toBeNull()
->and($user->fresh()->two_factor_recovery_codes)->not->toBeNull();
})->with([
'enable' => ['post', '/user/two-factor-authentication'],
'confirm' => ['post', '/user/confirmed-two-factor-authentication'],
'disable' => ['delete', '/user/two-factor-authentication'],
'qr code' => ['get', '/user/two-factor-qr-code'],
'secret key' => ['get', '/user/two-factor-secret-key'],
'recovery codes' => ['get', '/user/two-factor-recovery-codes'],
'regenerate recovery codes' => ['post', '/user/two-factor-recovery-codes'],
]);
test('the two-factor challenge stays reachable', function () {
/** @var TestCase $this */
$user = twoFactorUser();
$this->withSession(['login.id' => $user->id, 'login.remember' => false])
->get('/two-factor-challenge')
->assertOk();
$this->withSession(['login.id' => $user->id, 'login.remember' => false])
->post('/two-factor-challenge', ['code' => '000000'])
->assertRedirect();
});