236 lines
6.3 KiB
PHP
236 lines
6.3 KiB
PHP
<?php
|
|
|
|
use App\Events\User\TwoFactorDisabled;
|
|
use App\Events\User\TwoFactorEnabled;
|
|
use App\Models\User;
|
|
use Carbon\Carbon;
|
|
use Facades\Tests\Setup\UserFactory;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use PragmaRX\Google2FA\Google2FA;
|
|
use Tests\UpdatesSettings;
|
|
|
|
uses(RefreshDatabase::class);
|
|
uses(UpdatesSettings::class);
|
|
|
|
beforeEach(function () {
|
|
$this->artisan('db:seed');
|
|
});
|
|
|
|
test('the 2fa form is visible on profile page if 2fa is enabled', function () {
|
|
config(['services.authy.key' => 'test']);
|
|
|
|
$this->setSettings(['2fa.enabled' => false]);
|
|
|
|
// The tab is rendered client side from the shared setting, so that flag
|
|
// is what decides whether it appears rather than the markup.
|
|
$this->assertFalse(twoFactorAuthSetting('profile'));
|
|
|
|
$this->setSettings(['2fa.enabled' => true]);
|
|
|
|
$this->assertTrue(twoFactorAuthSetting('profile'));
|
|
});
|
|
|
|
test('the 2fa form is visible on edit user page if 2fa is enabled', function () {
|
|
config(['services.authy.key' => 'test']);
|
|
|
|
$this->setSettings(['2fa.enabled' => false]);
|
|
|
|
$user = UserFactory::create();
|
|
|
|
$this->assertFalse(twoFactorAuthSetting("/users/{$user->id}/edit"));
|
|
|
|
$this->setSettings(['2fa.enabled' => true]);
|
|
|
|
$this->assertTrue(twoFactorAuthSetting("/users/{$user->id}/edit"));
|
|
});
|
|
|
|
/**
|
|
* The `2fa.enabled` shared prop, which drives the Two-Factor tab.
|
|
*/
|
|
function twoFactorAuthSetting(string $url): bool
|
|
{
|
|
return (bool) test()->actingAsAdmin()
|
|
->get($url)
|
|
->viewData('page')['props']['settings']['2fa.enabled'];
|
|
}
|
|
|
|
test('enable 2fa from profile page', function () {
|
|
$this->setSettings(['2fa.enabled' => true]);
|
|
|
|
$user = UserFactory::user()->create();
|
|
|
|
$this->actingAs($user)
|
|
->post('/two-factor/enable')
|
|
->assertRedirect('/')
|
|
->assertSessionHas('tab', '2fa');
|
|
|
|
$this->assertTrue(
|
|
DB::table('users')
|
|
->where('id', $user->id)
|
|
->whereNotNull('two_factor_secret')
|
|
->exists()
|
|
);
|
|
});
|
|
|
|
test('enable 2fa from edit user page', function () {
|
|
$this->setSettings(['2fa.enabled' => true]);
|
|
|
|
$user = UserFactory::user()->create();
|
|
|
|
$formData = ['user' => $user->id];
|
|
|
|
$this->actingAsAdmin()
|
|
->post("users/{$user->id}/two-factor/enable", $formData)
|
|
->assertRedirect('/')
|
|
->assertSessionHas('tab', '2fa');
|
|
|
|
$this->assertTrue(
|
|
DB::table('users')
|
|
->where('id', $user->id)
|
|
->whereNotNull('two_factor_secret')
|
|
->exists()
|
|
);
|
|
});
|
|
|
|
test('users without appropriate permissions cannot enable 2fa for other users', function () {
|
|
$this->setSettings(['2fa.enabled' => true]);
|
|
|
|
$this->be(UserFactory::user()->create());
|
|
|
|
$user = UserFactory::user()->create();
|
|
|
|
$this->post('two-factor/enable', [
|
|
'user' => $user->id,
|
|
])->assertStatus(403);
|
|
|
|
$this->assertTrue(
|
|
DB::table('users')
|
|
->where('id', $user->id)
|
|
->whereNull('two_factor_secret')
|
|
->exists()
|
|
);
|
|
});
|
|
|
|
test('code field is required during 2fa verification', function () {
|
|
$this->setSettings(['2fa.enabled' => true]);
|
|
|
|
$user = UserFactory::user()->create();
|
|
$user->two_factor_secret = '123123';
|
|
$user->save();
|
|
|
|
$this->actingAs($user)
|
|
->post('two-factor/verify')
|
|
->assertSessionHasErrors('code');
|
|
});
|
|
|
|
test('the 2fa verification with wrong token will fail', function () {
|
|
$google2fa = new Google2FA;
|
|
$secret = encrypt($google2fa->generateSecretKey());
|
|
|
|
$this->withoutExceptionHandling();
|
|
$this->setSettings(['2fa.enabled' => true]);
|
|
|
|
$user = UserFactory::user()->create();
|
|
$user->two_factor_secret = $secret;
|
|
$user->save();
|
|
|
|
$this->actingAs($user)
|
|
->post('two-factor/verify', ['code' => '123123']);
|
|
|
|
$this->assertSessionHasError('Invalid 2FA token.');
|
|
});
|
|
|
|
test('successful 2fa code verification', function () {
|
|
$google2fa = new Google2FA;
|
|
$secret = encrypt($google2fa->generateSecretKey());
|
|
|
|
$this->setSettings(['2fa.enabled' => true]);
|
|
|
|
Event::fake([
|
|
TwoFactorEnabled::class,
|
|
]);
|
|
|
|
$user = UserFactory::user()->create();
|
|
$user->two_factor_secret = $secret;
|
|
$user->save();
|
|
|
|
$validCode = $google2fa->getCurrentOtp(decrypt($user->two_factor_secret));
|
|
|
|
$this->actingAs($user)
|
|
->post('two-factor/verify', ['code' => $validCode])
|
|
->assertRedirect('/profile');
|
|
|
|
$this->assertDatabaseHas('users', [
|
|
'id' => $user->id,
|
|
'two_factor_secret' => $secret,
|
|
]);
|
|
|
|
Event::assertDispatched(TwoFactorEnabled::class);
|
|
});
|
|
|
|
test('user can disable 2fa', function () {
|
|
$google2fa = new Google2FA;
|
|
$secret = encrypt($google2fa->generateSecretKey());
|
|
|
|
$this->setSettings(['2fa.enabled' => true]);
|
|
|
|
$user = UserFactory::user()->create();
|
|
$user->two_factor_secret = $secret;
|
|
$user->two_factor_confirmed_at = Carbon::now();
|
|
$user->save();
|
|
|
|
$this->be($user);
|
|
|
|
Event::fake([
|
|
TwoFactorDisabled::class,
|
|
]);
|
|
|
|
$this->from('/profile')
|
|
->post('two-factor/disable')
|
|
->assertRedirect('/profile');
|
|
|
|
$this->assertSessionHasSuccess('Two-Factor Authentication disabled successfully.');
|
|
|
|
Event::assertDispatched(TwoFactorDisabled::class);
|
|
});
|
|
|
|
test('user can disable 2fa for another user', function () {
|
|
$google2fa = new Google2FA;
|
|
$secret = encrypt($google2fa->generateSecretKey());
|
|
|
|
$this->setSettings(['2fa.enabled' => true]);
|
|
|
|
Event::fake([
|
|
TwoFactorDisabled::class,
|
|
]);
|
|
|
|
$this->beAdmin();
|
|
|
|
$user = UserFactory::user()->create();
|
|
$user->two_factor_secret = $secret;
|
|
$user->two_factor_confirmed_at = Carbon::now();
|
|
$user->save();
|
|
|
|
$this->from("/users/{$user->id}/edit")
|
|
->post("/users/{$user->id}/two-factor/disable", ['user' => $user->id])
|
|
->assertRedirect("/users/{$user->id}/edit");
|
|
|
|
$this->assertDatabaseHas('users', [
|
|
'id' => $user->id,
|
|
'two_factor_secret' => null,
|
|
]);
|
|
|
|
$this->assertSessionHasSuccess('Two-Factor Authentication disabled successfully.');
|
|
Event::assertDispatched(TwoFactorDisabled::class);
|
|
});
|
|
|
|
test('user without appropriate permissions cannot disable 2fa for another user', function () {
|
|
$this->setSettings(['2fa.enabled' => true]);
|
|
|
|
$this->be(UserFactory::user()->create());
|
|
|
|
$user = User::factory()->create();
|
|
|
|
$this->post('two-factor/disable', ['user' => $user->id])->assertForbidden();
|
|
});
|