mirror of
https://github.com/Bubka/2FAuth.git
synced 2025-02-16 10:29:16 +01:00
Add authentication log cleaning and associated tests
This commit is contained in:
parent
a9b1a20f30
commit
e73fbf658f
@ -9,6 +9,7 @@
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
@ -215,6 +216,13 @@ public function authentications(Request $request, User $user)
|
||||
{
|
||||
$this->authorize('view', $user);
|
||||
|
||||
// Here we purge the authentication log.
|
||||
// Running the purge command when someone fetchs the auth log
|
||||
// is not very elegant but it's straitforward compared
|
||||
// to a scheduled task, and the delete query is light.
|
||||
// => To enhance.
|
||||
Artisan::call('2fauth:purge-log');
|
||||
|
||||
$validated = $this->validate($request, [
|
||||
'period' => 'sometimes|numeric',
|
||||
'limit' => 'sometimes|numeric',
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
use App\Models\AuthLog;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class PurgeAuthLog extends Command
|
||||
{
|
||||
@ -41,17 +42,23 @@ class PurgeAuthLog extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description = 'Purge all authentication logs older than the configurable amount of days.';
|
||||
public $description = 'Delete all authentication log entries older than the configurable amount of days (see env vars).';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle() : void
|
||||
{
|
||||
$this->comment('Clearing authentication log...');
|
||||
$retentionTime = config('2fauth.config.authLogRetentionTime');
|
||||
$retentionTime = is_numeric($retentionTime) ? (int) $retentionTime : 365;
|
||||
$date = now()->subDays($retentionTime)->format('Y-m-d H:i:s');
|
||||
|
||||
$deleted = AuthLog::where('login_at', '<', now()->subDays(config('2fauth.authLogRetentionTime'))->format('Y-m-d H:i:s'))->delete();
|
||||
AuthLog::where('login_at', '<', $date)
|
||||
->orWhere('logout_at', '<', $date)
|
||||
->delete();
|
||||
|
||||
$this->info($deleted . ' authentication logs cleared.');
|
||||
Log::info('Authentication log purged');
|
||||
|
||||
$this->components->info('Authentication log purged successfully.');
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
'outgoingProxy' => env('PROXY_FOR_OUTGOING_REQUESTS', ''),
|
||||
'proxyLogoutUrl' => env('PROXY_LOGOUT_URL', null),
|
||||
'appSubdirectory' => env('APP_SUBDIRECTORY', ''),
|
||||
'authLogRetentionTime' => env('AUTHENTICATION_LOG_RETENTION', 365),
|
||||
'authLogRetentionTime' => envUnlessEmpty('AUTHENTICATION_LOG_RETENTION', 365),
|
||||
],
|
||||
|
||||
/*
|
||||
|
@ -28,6 +28,24 @@ public function definition()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the model has login before last year.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\AuthLog>
|
||||
*/
|
||||
public function daysAgo(int $days)
|
||||
{
|
||||
return $this->state(function (array $attributes) use ($days) {
|
||||
$loginDate = now()->subDays($days);
|
||||
$logoutDate = $loginDate->addHours(1);
|
||||
|
||||
return [
|
||||
'login_at' => $loginDate,
|
||||
'logout_at' => $logoutDate,
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the model is a failed login.
|
||||
*
|
||||
|
142
tests/Feature/Console/PurgeLogTest.php
Normal file
142
tests/Feature/Console/PurgeLogTest.php
Normal file
@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Console;
|
||||
|
||||
use App\Models\AuthLog;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Carbon;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use Tests\FeatureTestCase;
|
||||
|
||||
class PurgeLogTest extends FeatureTestCase
|
||||
{
|
||||
/**
|
||||
* @var \App\Models\User|\Illuminate\Contracts\Auth\Authenticatable
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function setUp() : void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->user = User::factory()->create();
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_purgeLog_completes()
|
||||
{
|
||||
$this->artisan('2fauth:purge-log')
|
||||
->assertSuccessful();
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_purgeLog_defaults_to_one_year()
|
||||
{
|
||||
$oneYearOldLog = AuthLog::factory()->daysAgo(366)->for($this->user, 'authenticatable')->create();
|
||||
$sixMonthsOldLog = AuthLog::factory()->daysAgo(364)->for($this->user, 'authenticatable')->create();
|
||||
|
||||
$this->artisan('2fauth:purge-log');
|
||||
|
||||
$this->assertDatabaseHas('auth_logs', [
|
||||
'id' => $sixMonthsOldLog->id
|
||||
]);
|
||||
$this->assertDatabaseMissing('auth_logs', [
|
||||
'id' => $oneYearOldLog->id
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_purgeLog_deletes_records_older_than_retention_time()
|
||||
{
|
||||
$retention = 180;
|
||||
config(['2fauth.config.authLogRetentionTime' => $retention]);
|
||||
$log = AuthLog::factory()->daysAgo($retention + 1)->for($this->user, 'authenticatable')->create();
|
||||
|
||||
$this->artisan('2fauth:purge-log');
|
||||
|
||||
$this->assertDatabaseMissing('auth_logs', [
|
||||
'id' => $log->id
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_purgeLog_deletes_logout_only_records_older_than_retention_time()
|
||||
{
|
||||
$retention = 180;
|
||||
config(['2fauth.config.authLogRetentionTime' => $retention]);
|
||||
$log = AuthLog::factory()->logoutOnly()->for($this->user, 'authenticatable')->create();
|
||||
|
||||
$this->travelTo(Carbon::now()->addDays($retention + 1));
|
||||
$this->artisan('2fauth:purge-log');
|
||||
|
||||
$this->assertDatabaseMissing('auth_logs', [
|
||||
'id' => $log->id
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function test_purgeLog_does_not_delete_records_younger_than_retention_time()
|
||||
{
|
||||
$retention = 180;
|
||||
config(['2fauth.config.authLogRetentionTime' => $retention]);
|
||||
$log = AuthLog::factory()->daysAgo($retention - 1)->for($this->user, 'authenticatable')->create();
|
||||
|
||||
$this->artisan('2fauth:purge-log');
|
||||
|
||||
$this->assertDatabaseHas('auth_logs', [
|
||||
'id' => $log->id
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
#[DataProvider('provideInvalidConfig')]
|
||||
public function test_purgeLog_with_invalid_config_defaults_to_one_year($config)
|
||||
{
|
||||
config(['2fauth.config.authLogRetentionTime' => $config]);
|
||||
$oneYearOldLog = AuthLog::factory()->daysAgo(366)->for($this->user, 'authenticatable')->create();
|
||||
$sixMonthsOldLog = AuthLog::factory()->daysAgo(364)->for($this->user, 'authenticatable')->create();
|
||||
|
||||
$this->artisan('2fauth:purge-log');
|
||||
|
||||
$this->assertDatabaseHas('auth_logs', [
|
||||
'id' => $sixMonthsOldLog->id
|
||||
]);
|
||||
$this->assertDatabaseMissing('auth_logs', [
|
||||
'id' => $oneYearOldLog->id
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide invalid config for validation test
|
||||
*/
|
||||
public static function provideInvalidConfig() : array
|
||||
{
|
||||
return [
|
||||
'NULL' => [
|
||||
null
|
||||
],
|
||||
'EMPTY' => [
|
||||
''
|
||||
],
|
||||
'STRING' => [
|
||||
'ljhkjh'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user