diff --git a/app/Audit.php b/app/Audit.php index 86769df98..4e5a1b85e 100644 --- a/app/Audit.php +++ b/app/Audit.php @@ -17,10 +17,21 @@ public function getTimeDateAttribute() { } public static function newAudit(string $message): void { + $impersonated_by_id = null; + $impersonation_string = ''; + if (session()->has('impersonating_user')) { + $impersonated_by_id = session('impersonating_user'); + $impersonation_user = User::find($impersonated_by_id); + + $impersonation_string = 'IMPERSONATED BY ' . (is_null($impersonation_user) ? 'UNKNOWN' : $impersonation_user->full_name) . ': '; + } + $impersonated_by_id = session()->has('impersonating_user') ? session('impersonating_user') : null; + $audit = new Audit; $audit->cid = Auth::id(); + $audit->impersonated_by_id = $impersonated_by_id; $audit->ip = $_SERVER['REMOTE_ADDR']; - $audit->what = Auth::user()->full_name . ' ' . $message; + $audit->what = $impersonation_string . Auth::user()->full_name . ' ' . $message; $audit->save(); } } diff --git a/app/Http/Controllers/ImpersonationController.php b/app/Http/Controllers/ImpersonationController.php new file mode 100644 index 000000000..af688b507 --- /dev/null +++ b/app/Http/Controllers/ImpersonationController.php @@ -0,0 +1,33 @@ +user_id); + $is_impersonating = session()->has('impersonate'); + if (is_null($user)) { + return redirect()->back()->with('error', 'That user does not exist'); + } + + if ($is_impersonating) { + return redirect()->back()->with('error', 'You must first stop impersonating your current user before beginning a new session'); + } + + session()->put('impersonate', $user->id); + + Audit::newAudit('started impersonating user ' . $user->impersonation_name . '.'); + return redirect('/dashboard')->with('warning', 'Successfully started impersonationg ' . $user->full_name . '. CAUTION: Impersonating actively logs you into the user\'s REAL account. Changes made while impersonating will be reflected on the user\'s actual account. PROCEED WITH CARE.'); + } + + public function stop() { + Audit::newAudit('impersonation session ending...'); + + session()->forget('impersonate'); + return redirect('/dashboard'); + } +} diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 869e64d7e..a86084528 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -35,6 +35,7 @@ class Kernel extends HttpKernel { \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, + \App\Http\Middleware\Impersonation::class, ], 'api' => [ diff --git a/app/Http/Middleware/Impersonation.php b/app/Http/Middleware/Impersonation.php new file mode 100644 index 000000000..880b45299 --- /dev/null +++ b/app/Http/Middleware/Impersonation.php @@ -0,0 +1,24 @@ +has('impersonate') && Auth::user()->isAbleTo('snrStaff')) { + session()->put('impersonating_user', Auth::id()); + Auth::onceUsingId(session('impersonate')); + } + + return $next($request); + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 01e6b2750..d25d7db14 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,11 +2,13 @@ namespace App\Providers; +use App\View\Composers\ImpersonationComposer; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\Paginator; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Blade; use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Facades\View; use Illuminate\Support\Facades\Vite; use Illuminate\Support\ServiceProvider; @@ -24,6 +26,8 @@ public function boot(): void { return toggleEnabled($toggle_name); }); + View::composer('inc.dashboard_head', ImpersonationComposer::class); + /** * Paginate a standard Laravel Collection. * diff --git a/app/User.php b/app/User.php index 08bb784ff..837ac01e4 100644 --- a/app/User.php +++ b/app/User.php @@ -73,6 +73,22 @@ public function getFullNameRatingAttribute() { return $this->full_name . ' - ' . $this->rating_short; } + public function getImpersonationNameAttribute() { + $roles = array_reduce($this->roles->toArray(), function ($role_string, $role) { + return $role_string . $role['name'] . ', '; + }, ''); + + if ($this->visitor) { + $roles = 'visitor'; + } + + if ($roles != '') { + $roles = ' (' . trim($roles, ', ') . ')'; + } + + return $this->backwards_name . ' ' . $this->id . ' - ' . $this->rating_short . $roles; + } + public static $RatingShort = [ 0 => 'N/A', 1 => 'OBS', 2 => 'S1', diff --git a/app/View/Composers/ImpersonationComposer.php b/app/View/Composers/ImpersonationComposer.php new file mode 100644 index 000000000..97e347e53 --- /dev/null +++ b/app/View/Composers/ImpersonationComposer.php @@ -0,0 +1,32 @@ +has('impersonate'); + + if (Auth::user()->isAbleTo('snrStaff')) { + $users = User::where('status', 1)->orderBy('lname', 'ASC')->get()->pluck('impersonation_name', 'id'); + } + + $view->with('users', $users)->with('is_impersonating', $is_impersonating); + } + } +} diff --git a/resources/views/inc/dashboard_head.blade.php b/resources/views/inc/dashboard_head.blade.php index 4efd8d2aa..ddfbcd3f5 100644 --- a/resources/views/inc/dashboard_head.blade.php +++ b/resources/views/inc/dashboard_head.blade.php @@ -1,26 +1,30 @@ - + @else + {{ Auth::user()->full_name }} - {{ Auth::user()->rating_short }} + @endif + + + diff --git a/resources/views/inc/messages.blade.php b/resources/views/inc/messages.blade.php index 35a72786d..d50b64a62 100644 --- a/resources/views/inc/messages.blade.php +++ b/resources/views/inc/messages.blade.php @@ -17,6 +17,13 @@ @endif + @if(session('warning')) +
+
+ {{ session('warning') }} +
+ @endif + @if(session('error'))
diff --git a/routes/web.php b/routes/web.php index 43187ccaa..3a6a1e7f5 100644 --- a/routes/web.php +++ b/routes/web.php @@ -333,6 +333,11 @@ Route::prefix('monitor')->middleware('permission:staff')->group(function () { Route::get('/', 'AdminDash@backgroundMonitor'); }); + + Route::prefix('impersonation')->middleware('toggle:impersonation')->group(function () { + Route::post('/', 'ImpersonationController@start')->middleware('permission:snrStaff')->name('startImpersonation'); + Route::get('/stop', 'ImpersonationController@stop')->name('stopImpersonation'); + }); }); }); /*