]> BookStack Code Mirror - bookstack/blob - tests/Auth/MfaVerificationTest.php
Added TOTP verification upon access
[bookstack] / tests / Auth / MfaVerificationTest.php
1 <?php
2
3 namespace Tests\Auth;
4
5 use BookStack\Auth\Access\Mfa\MfaValue;
6 use BookStack\Auth\Access\Mfa\TotpService;
7 use BookStack\Auth\User;
8 use Illuminate\Support\Facades\Hash;
9 use PragmaRX\Google2FA\Google2FA;
10 use Tests\TestCase;
11 use Tests\TestResponse;
12
13 class MfaVerificationTest extends TestCase
14 {
15     public function test_totp_verification()
16     {
17         [$user, $secret, $loginResp] = $this->startTotpLogin();
18         $loginResp->assertRedirect('/mfa/verify');
19
20         $resp = $this->get('/mfa/verify');
21         $resp->assertSee('Verify Access');
22         $resp->assertSee('Enter the code, generated using your mobile app, below:');
23         $resp->assertElementExists('form[action$="/mfa/verify/totp"] input[name="code"]');
24
25         $google2fa = new Google2FA();
26         $resp = $this->post('/mfa/verify/totp', [
27             'code' => $google2fa->getCurrentOtp($secret),
28         ]);
29         $resp->assertRedirect('/');
30         $this->assertEquals($user->id, auth()->user()->id);
31     }
32
33     public function test_totp_verification_fails_on_missing_invalid_code()
34     {
35         [$user, $secret, $loginResp] = $this->startTotpLogin();
36
37         $resp = $this->get('/mfa/verify');
38         $resp = $this->post('/mfa/verify/totp', [
39             'code' => '',
40         ]);
41         $resp->assertRedirect('/mfa/verify');
42
43         $resp = $this->get('/mfa/verify');
44         $resp->assertSeeText('The code field is required.');
45         $this->assertNull(auth()->user());
46
47         $resp = $this->post('/mfa/verify/totp', [
48             'code' => '123321',
49         ]);
50         $resp->assertRedirect('/mfa/verify');
51         $resp = $this->get('/mfa/verify');
52
53         $resp->assertSeeText('The provided code is not valid or has expired.');
54         $this->assertNull(auth()->user());
55     }
56
57     /**
58      * @return Array<User, string, TestResponse>
59      */
60     protected function startTotpLogin(): array
61     {
62         $secret = $this->app->make(TotpService::class)->generateSecret();
63         $user = $this->getEditor();
64         $user->password = Hash::make('password');
65         $user->save();
66         MfaValue::upsertWithValue($user, MfaValue::METHOD_TOTP, $secret);
67         $loginResp = $this->post('/login', [
68             'email' => $user->email,
69             'password' => 'password',
70         ]);
71
72         return [$user, $secret, $loginResp];
73     }
74
75 }