18

I would like my Apex code to know the difference between me being actually logged in as a particular Salesforce user, versus being logged in as an administrator and impersonating the user (because I clicked on his name and selected "Login").

I cannot find a documented way to do this, and knowing that this is the nature of impersonation, don't necessarily expect to find a documented API call that tells me this. But Salesforce definitely knows the difference, at least in the UI, and Logout while you're impersonating just stops the impersonation but leaves you logged in as the administrator again.

So, is there a way for Apex code to tell that it is actually an administrator impersonating a user?

4
  • Why do you want to do this? Commented Dec 20, 2013 at 14:23
  • I'm going to guess maybe you want to find out if an end user is actually performing certain actions or changes, vs. an admin logged in as them? If not, I agree with @ReidCarlberg, why do you want to do this? Commented Dec 20, 2013 at 14:28
  • This is a good question: Salesforce-UI clearly can distinguish between the two cases, but I'm not sure if it's accessible via SFDC. I suggest trying some test cases: create/edit records while logged in as another user, and see who the resulting Record Owners are, who the Last Modified By are, etc. Do all the forensics you normally would do. Commented Dec 20, 2013 at 16:00
  • I would only want to know so I can log that the request was from impersonation. I have a logging object where I record some permanent logging information.
    – dwright01
    Commented Dec 21, 2013 at 0:14

5 Answers 5

11

No. As far as the code is concerned, the effective user is the user performing the action. Any records created by an administrator logged in as a user will have their createdby and lastmodifiedby audit fields set to that user, and userinfo.getuserid() will return the user being logged in as. This is the same behavior as System.runAs() in test methods, with the exception that code can detect if it is being run in a test method. There's nothing you can do, such as examining the session ID, etc, that would give you any clue at all, unless you know how to decrypt the session ID (hypothetically; presumably this is how the UI knows).

17

Adding on to Daniel's post, there is a different class called SessionManagement that will return some, if not all of the AuthSession attributes for the current session. This way, you can determine the type of session for the current session.

Map<String,String> currentSessionAttributes = Auth.SessionManagement.getCurrentSession();
String sessionType = currentSessionAttributes.get('SessionType');
//If sessionType == 'SubstituteUser', act on logged-in-as user.

Details on the SessionManagement class can be found here.

12

It's not foolproof, but querying the AuthSession looks promising.

Unfortunately, there doesn't appear to be an easy way to find the AuthSession records that correspond to the current SessionID - How can I find the AuthSession that corresponds with the current Session Id?

However, an impersonator will get AuthSession SessionType of SubstituteUser.

SubstituteUser
A session created when one user logs in via another user. For example, if an administrator logs in as another user, a SubstituteUser session is created. Source

They will also lack LoginHistoryId, LoginType, LogoutUrl, and LoginGeoId field values. The former is particularly interesting, as it shows they never really "logged in".

As a very rudimentary check from Apex:

List<AuthSession> authSession = [Select Id from AuthSession where UsersId = :UserInfo.getUserId() and SessionType = 'SubstituteUser'];
Boolean hasLoggedInUser = !authSession.isEmpty();

Of course, this won't handle cases where the actual user is also logged in at the same time. You could do some additional checks to see if there are other active sessions for the same UsersId.


Alternatively, on the client side you could check for the presence of a RSID cookie. If this exists then the current session is using the login as functionality.

Unfortunately you can't directly check for the presence of this cookie in Apex as it doesn't have the apex_ prefix. Maybe write a new Apex accessible cookie client side if RSID is detected.

2
  • This is an interesting theory. I think I'll try it out.
    – sfdcfox
    Commented Apr 26, 2017 at 2:57
  • how could we check impersonation in lightning component because document .cookie not access in component? Commented Nov 15, 2017 at 17:30
3

The SessionType value retrieved from Auth.SessionManagement.getCurrentSession() cannot be relied upon to determine if the user is a Substitute User or not.

This is because every user that is logged into the org will have multiple entries in the AuthSession table. The SessionType value returned by getCurrentSession() reflects an entry in the AuthSession table where the value of IsCurrent = true. In most cases, the SessionType value returned here will be 'UI', 'Aura' or 'Visualforce'.

However, the other entries for the session in the AuthSession table for this particular login still exist.

Retrieve the LoginHistoryId using Auth.SessionManagement.getCurrentSession(). All entries for this specific login in the AuthSession table will have the same value for LoginHistoryId.

Then query the AuthSession table using the LoginHistoryId value and determine whether or not there is at least one entry where SessionType = 'SubstituteUser'. If there is at least one, then this particular session is an admin logged in as a user.

1

Answer for anyone who is interested, thoroughly this is the code that will give you your "real" user Id:

Id realUserId = [
        SELECT Id, UserId
        FROM LoginHistory
        WHERE Id IN (SELECT LoginHistoryId FROM AuthSession WHERE IsCurrent = TRUE)
    ]
    .UserId;

If you want to check if someone is "logged in as" another user:

Boolean isLoggedInAs = [
        SELECT Id, UserId
        FROM LoginHistory
        WHERE Id IN (SELECT LoginHistoryId FROM AuthSession WHERE IsCurrent = TRUE)
    ]
    .UserId != UserInfo.getUserId();

Or you can build few util functions:

/**
 * @description method to get your user Id even if you are logged in as another user
 * @returns your "real" User Id
 */
private static Id realUserId; // cache
public static Id getRealUserId() {
    if (realUserId == null) {
        realUserId = [
            SELECT Id, UserId
            FROM LoginHistory
            WHERE Id IN (SELECT LoginHistoryId FROM AuthSession WHERE IsCurrent = TRUE)
        ]
        .UserId;
    }
    return realUserId;
}

public static Boolean isLoggedInAs() {
    return getRealUserId() != UserInfo.getUserId();
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .