Logging impersonation data

Two Laravel packages I use often are packages to impersonate a user and packages to log activity (including model changes).

Both are useful, but there’s typically one piece missing. Activity log packages will log *who* initiated a change, but not who the person may have been impersonated by. If I log in as me, then impersonate user X, then make changes, the activity log will typically just show ‘user X made these changes’. However, it was really *me* doing it on behalf of person X.

There’s a few ways one could handle this, and I’d initially looked at request middleware (and still might move in that direction), but with the Spatie activitylog package, I added a ‘pipe’ during the call to initialize logging options.

Here’s a bit of code I use with the Spatie Activitylog package and the laravel-impersonate package.

<?php

namespace App\Services\ActivityLog\Pipes;

use Closure;
use Spatie\Activitylog\Contracts\LoggablePipe;
use Spatie\Activitylog\EventLogBag;

class AddImpersonatorPipe implements LoggablePipe
{
    public function __construct(protected string $field)
    {
    }

    public function handle(EventLogBag $event, Closure $next): EventLogBag
    {
        $manager = app('impersonate');
        if ($manager->isImpersonating()) {
            $impersonatorId = $manager->getImpersonatorId();
            $event->changes[$this->field] = $impersonatorId;
        }

        return $next($event);
    }
}

As you can see, I’m simply adding the originating impersonator ID to the ‘change’ list. It’s not a separated activity log property, nor a separate column in the database table where logged activity lives. That’s certainly possible, but I was trying to handle this without any database changes at this point.

On each model I log changes on, I have a ‘getActivitylogOptions’ method (via a trait) that adds the pipe code above to the logger’s pipeline.

    public function getActivitylogOptions(): LogOptions
    {
        self::addLogChange(new AddImpersonatorPipe('impersonator_id'));

        return LogOptions::defaults()
            ->logAll();
    }

What I’ve not tested yet is if non-model ‘activity’ log behaviour would still have the impersonation processing in place if it’s no model is invoked in the request. For example, just logging that an api call was made. However, pretty much every request has at least the User model invoked, which has the getActivitylogOptions() call in place, so I’m not sure there’s ever a time that would not be invoked.

Also… reviewing this out loud… the self::addLogChange() call may be being invoked once per object instantiation (or at least initial model instantiation) which may be redundant. I’ll need to investigate more.

There doesn’t seem to be a standard process for this, but it’s definitely useful information to log, even if you choose to log it a separate way.

Similar Posts

  • Bad I9 PDF form

    Have been needing to programmatically fill out an I9 PDF, retrieved from gov site. Should be fairly straightforward, right? Well… the field names are… a mess. Field names like topmostSubform[0].Page1[0].U\.S\._Social_Security_Number__Last_4_numbers_[0]topmostSubform[0].Page1[0].expiration_date__if_applicable__mm_dd_yyyy[0] topmostSubform[0].Page2[0].Employers_Business_or_Organization_Address_Street_Number_and_Name[0] and so on make it pretty… not straightforward to create a usable key/value combination to search and replace. But… today, I noticed it got…

  • Laravel down migrations

    I get an email newsletter from Martin Joo every week or so. The newsletters generally have some useful tips around the Laravel framework or sometimes just general development tips. I’ve learned a couple of neat tricks here and there, and will continue to receive. This morning I received an email with a Laravel ‘tip’ regarding…

  • Importance of backups

    Well… here we are.  10 years later, and … no backups.  Or… none of the data that’s important. Recently had a drive crash in my main server where this blog is hosted.  Had it happen 2 years ago, but the data was recovered, and I put everything on automatic backups.  Using virtualmin, a great control…

  • Identity and habits

    “Your present identity should not constrain your future habits”. For this quote from the audio book “Hello, Habits“. Obviously the book is about ‘habits’, but the phrase could easily have been “Your present identity should not constrain your future self”. In either reading of this, it’s been stuck in my head for while now.  How…

  • Four Thousand Weeks

    I’m starting to read “Four Thousand Weeks” from Oliver Burkeman. I initially listened to much of the audio book, then bought a copy (link above to Amazon – no affiliate link). Have not finished yet, but the core message of the book seems to be There’s certainly more to it than this, and again, I’m…

Leave a Reply

Your email address will not be published. Required fields are marked *