Replaces the insecure token-in-localStorage approach with a header-based impersonation system backed by cache sessions and MFA verification. Key changes: - New impersonation_sessions audit table (immutable, ULID PK) - MFA verification required to start impersonation (TOTP/email/backup) - X-Impersonate-User header + HandleImpersonation middleware - Per-request auth context swap (admin session never modified) - IP pinning, sensitive route blocking, no nesting, sliding 60-min TTL - Activity log auto-tagged with impersonated_by during sessions - Frontend: sessionStorage, BroadcastChannel sync, countdown timer - ImpersonateDialog with reason + MFA verification flow - 26 comprehensive tests covering core, middleware, audit, lifecycle Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
48 lines
1.4 KiB
PHP
48 lines
1.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Providers;
|
|
|
|
use App\Models\Person;
|
|
use App\Observers\PersonObserver;
|
|
use Illuminate\Auth\Notifications\ResetPassword;
|
|
use Illuminate\Support\ServiceProvider;
|
|
use Spatie\Activitylog\Models\Activity;
|
|
|
|
class AppServiceProvider extends ServiceProvider
|
|
{
|
|
public function register(): void
|
|
{
|
|
//
|
|
}
|
|
|
|
public function boot(): void
|
|
{
|
|
Person::observe(PersonObserver::class);
|
|
|
|
ResetPassword::createUrlUsing(function ($user, string $token) {
|
|
return config('crewli.portal_url') . '/wachtwoord-resetten?token=' . $token . '&email=' . urlencode($user->email);
|
|
});
|
|
|
|
// Tag activity log entries with impersonation context
|
|
Activity::saving(function (Activity $activity) {
|
|
$request = request();
|
|
|
|
$impersonator = $request->attributes->get('impersonator');
|
|
$session = $request->attributes->get('impersonation_session');
|
|
|
|
if ($impersonator && $session) {
|
|
$properties = $activity->properties?->toArray() ?? [];
|
|
$properties['impersonated_by'] = [
|
|
'user_id' => $impersonator->id,
|
|
'name' => $impersonator->full_name,
|
|
'email' => $impersonator->email,
|
|
];
|
|
$properties['impersonation_session_id'] = $session->id;
|
|
$activity->properties = collect($properties);
|
|
}
|
|
});
|
|
}
|
|
}
|