287 lines
8.1 KiB
PHP
287 lines
8.1 KiB
PHP
<?php
|
|
|
|
use App\Events\User\LoggedIn;
|
|
use App\Models\User;
|
|
use Carbon\Carbon;
|
|
use Facades\Tests\Setup\UserFactory;
|
|
use Illuminate\Cache\RateLimiter;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Testing\TestResponse;
|
|
use Inertia\Testing\AssertableInertia as Assert;
|
|
use PragmaRX\Google2FA\Google2FA;
|
|
use Tests\UpdatesSettings;
|
|
|
|
uses(RefreshDatabase::class);
|
|
uses(UpdatesSettings::class);
|
|
|
|
beforeEach(function () {
|
|
$this->setSettings([
|
|
'throttle_enabled' => false,
|
|
]);
|
|
});
|
|
|
|
test('successful login', function () {
|
|
$user = UserFactory::withCredentials('foo', 'bar')->create();
|
|
|
|
loginUser('foo', 'bar')
|
|
->assertRedirect('/');
|
|
|
|
$this->assertTrue(auth()->check());
|
|
$this->assertTrue($user->is(auth()->user()));
|
|
});
|
|
|
|
test('last login timestamp is updated after successful login', function () {
|
|
$testDate = Carbon::now();
|
|
|
|
Carbon::setTestNow($testDate);
|
|
|
|
$user = UserFactory::withCredentials('foo', 'bar')->create();
|
|
|
|
$this->assertNull($user->last_login);
|
|
|
|
loginUser('foo', 'bar');
|
|
|
|
$this->assertEquals($testDate->timestamp, $user->fresh()->last_login->timestamp);
|
|
});
|
|
|
|
test('login with wrong credentials will fail', function () {
|
|
loginUser('foo', 'bar')
|
|
->assertRedirect('/login');
|
|
|
|
$this->assertFalse(auth()->check());
|
|
});
|
|
|
|
test('country id remains the same after login', function () {
|
|
$user = User::factory()->create([
|
|
'username' => 'foo',
|
|
'password' => 'bar',
|
|
'country_id' => 688,
|
|
]);
|
|
|
|
loginUser('foo', 'bar')
|
|
->assertRedirect('/');
|
|
|
|
$this->assertEquals(688, $user->fresh()->country_id);
|
|
});
|
|
|
|
test('throttling', function () {
|
|
$this->setSettings([
|
|
'throttle_enabled' => true,
|
|
'throttle_attempts' => 3,
|
|
'throttle_lockout_time' => 2, // 2 minutes
|
|
]);
|
|
|
|
for ($i = 0; $i < 3; $i++) {
|
|
loginUser('foo', 'bar');
|
|
}
|
|
|
|
loginUser('foo', 'bar')
|
|
->assertRedirect('login')
|
|
->assertSessionHasErrors('username');
|
|
|
|
$this->assertTrue(app(RateLimiter::class)->tooManyAttempts('foo|127.0.0.1', 3));
|
|
});
|
|
|
|
test('login with remember', function () {
|
|
$user = UserFactory::withCredentials('foo', 'bar')->create();
|
|
|
|
Setting::set('remember_me', false);
|
|
|
|
$this->get('login')
|
|
->assertInertia(fn (Assert $page) => $page
|
|
->component('auth/Login')
|
|
->where('settings.remember_me', false)
|
|
);
|
|
|
|
Setting::set('remember_me', true);
|
|
|
|
$this->get('login')
|
|
->assertInertia(fn (Assert $page) => $page
|
|
->component('auth/Login')
|
|
->where('settings.remember_me', true)
|
|
);
|
|
|
|
loginUser('foo', 'bar', true)
|
|
->assertRedirect('/');
|
|
|
|
$this->assertNotNull($user->fresh()->remember_token);
|
|
$this->assertNotNull($user->fresh()->last_login);
|
|
});
|
|
|
|
test('login max number of sessions reached', function () {
|
|
$user = UserFactory::withCredentials('foo', 'bar')->create();
|
|
|
|
Setting::set('max_active_sessions', 1);
|
|
|
|
DB::table('sessions')->insert([
|
|
'id' => Str::random(),
|
|
'user_id' => $user->id,
|
|
'ip_address' => fake()->ipv4,
|
|
'user_agent' => fake()->userAgent,
|
|
'payload' => 'test',
|
|
'last_activity' => Carbon::now()->timestamp,
|
|
]);
|
|
|
|
loginUser('foo', 'bar')
|
|
->assertRedirect('/login');
|
|
|
|
$this->assertSessionHasError(trans('auth.max_sessions_reached'));
|
|
|
|
$this->assertFalse(Auth::check());
|
|
});
|
|
|
|
test('banned user cannot log in', function () {
|
|
UserFactory::withCredentials('foo', 'bar')->banned()->create();
|
|
|
|
loginUser('foo', 'bar')
|
|
->assertRedirect('/login');
|
|
|
|
$this->assertSessionHasError('Your account is banned by administrator.');
|
|
});
|
|
|
|
test('login with 2fa enabled', function () {
|
|
$google2fa = new Google2FA;
|
|
$secret = encrypt($google2fa->generateSecretKey());
|
|
|
|
$this->withoutExceptionHandling();
|
|
$this->setSettings(['2fa.enabled' => true, 'throttle_enabled' => false]);
|
|
|
|
Event::fake([LoggedIn::class]);
|
|
|
|
$user = UserFactory::withCredentials('foo', 'bar')->create();
|
|
$user->two_factor_secret = $secret;
|
|
$user->two_factor_confirmed_at = Carbon::now();
|
|
$user->save();
|
|
|
|
$validCode = $google2fa->getCurrentOtp(decrypt($user->two_factor_secret));
|
|
|
|
loginUser('foo', 'bar')
|
|
->assertRedirect('auth/two-factor-authentication')
|
|
->assertSessionHas('auth.2fa.id', $user->id);
|
|
|
|
$this->post('auth/two-factor-authentication', ['code' => $validCode])
|
|
->assertRedirect('/');
|
|
|
|
$this->assertTrue(auth()->check());
|
|
|
|
Event::assertDispatched(LoggedIn::class);
|
|
});
|
|
|
|
test('login with 2fa enabled redirect to custom page', function () {
|
|
$google2fa = new Google2FA;
|
|
$secret = encrypt($google2fa->generateSecretKey());
|
|
|
|
$this->withoutExceptionHandling();
|
|
$this->setSettings(['2fa.enabled' => true, 'throttle_enabled' => false]);
|
|
|
|
Event::fake([LoggedIn::class]);
|
|
|
|
$user = UserFactory::withCredentials('foo', 'bar')->create();
|
|
$user->two_factor_secret = $secret;
|
|
$user->two_factor_confirmed_at = Carbon::now();
|
|
$user->save();
|
|
|
|
$validCode = $google2fa->getCurrentOtp(decrypt($user->two_factor_secret));
|
|
|
|
loginUser('foo', 'bar', redirectTo: 'https://google.com')
|
|
->assertRedirect('auth/two-factor-authentication')
|
|
->assertSessionHas('auth.2fa.id', $user->id);
|
|
|
|
$this->post('auth/two-factor-authentication', ['code' => $validCode])
|
|
->assertRedirect('https://google.com');
|
|
|
|
$this->assertTrue(auth()->check());
|
|
|
|
Event::assertDispatched(LoggedIn::class);
|
|
});
|
|
|
|
test('login with wrong 2fa token', function () {
|
|
$google2fa = new Google2FA;
|
|
$secret = encrypt($google2fa->generateSecretKey());
|
|
|
|
$this->setSettings(['2fa.enabled' => true, 'throttle_enabled' => false]);
|
|
|
|
$user = UserFactory::withCredentials('foo', 'bar')->create();
|
|
$user->two_factor_secret = $secret;
|
|
$user->two_factor_confirmed_at = Carbon::now();
|
|
$user->save();
|
|
|
|
loginUser('foo', 'bar')
|
|
->assertRedirect('auth/two-factor-authentication')
|
|
->assertSessionHas('auth.2fa.id', $user->id);
|
|
|
|
$this->post('auth/two-factor-authentication', ['code' => '123123'])->assertRedirect('login');
|
|
|
|
$this->assertSessionHasError('Invalid 2FA token.');
|
|
});
|
|
|
|
test('login with wrong 2fa token when custom redirect page is provided', function () {
|
|
$google2fa = new Google2FA;
|
|
$secret = encrypt($google2fa->generateSecretKey());
|
|
|
|
$this->setSettings(['2fa.enabled' => true, 'throttle_enabled' => false]);
|
|
|
|
$user = UserFactory::withCredentials('foo', 'bar')->create();
|
|
$user->two_factor_secret = $secret;
|
|
$user->two_factor_confirmed_at = Carbon::now();
|
|
$user->save();
|
|
|
|
loginUser('foo', 'bar', redirectTo: 'https://google.com')
|
|
->assertRedirect('auth/two-factor-authentication')
|
|
->assertSessionHas('auth.2fa.id', $user->id);
|
|
|
|
$this->post('auth/two-factor-authentication', ['code' => '123'])
|
|
->assertRedirect('login?to=https://google.com');
|
|
|
|
$this->assertSessionHasError('Invalid 2FA token.');
|
|
});
|
|
|
|
test('force password change on login', function () {
|
|
$this->setSettings(['password-change.enabled' => true]);
|
|
|
|
$user = User::factory()->create([
|
|
'username' => 'foo',
|
|
'password' => 'bar',
|
|
'force_password_change' => true,
|
|
]);
|
|
|
|
$this->assertDatabaseHas('users', [
|
|
'id' => $user->id,
|
|
'force_password_change' => true,
|
|
]);
|
|
|
|
loginUser('foo', 'bar')
|
|
->assertRedirect('/');
|
|
|
|
$this->get('/')->assertRedirect('/profile');
|
|
|
|
$this->from('/profile')
|
|
->put('/profile/login-details', [
|
|
'email' => 'john@doe.com',
|
|
'username' => 'milos',
|
|
'password' => '123123123',
|
|
'password_confirmation' => '123123123',
|
|
])
|
|
->assertRedirect('/profile');
|
|
|
|
$this->assertDatabaseHas('users', [
|
|
'id' => $user->id,
|
|
'force_password_change' => false,
|
|
]);
|
|
});
|
|
|
|
function loginUser($username, $password, $remember = false, $redirectTo = null): TestResponse
|
|
{
|
|
$url = 'login';
|
|
|
|
if ($redirectTo) {
|
|
$url .= '?to='.urlencode($redirectTo);
|
|
}
|
|
|
|
return test()->post($url, [
|
|
'username' => $username,
|
|
'password' => $password,
|
|
'remember' => $remember,
|
|
]);
|
|
}
|