- 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>
55 lines
2 KiB
PHP
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();
|
|
});
|