Search code examples
c#windowsimpersonation

Windows Impersonation: A Flaw in the Ointment


In my journey to master the nuances of user impersonation in Windows I first had an issue about getting impersonation to a remote database to occur at all (see this SO question) but I finally figured that out. My next hurdle is undoing/cancelling/reverting (choose your favorite verb) impersonation.

I have tried a couple different impersonation libraries that seem credible to me:

The results are identical with both libraries. Best practices dictate using the LOGON32_LOGON_NEW_CREDENTIALS logon type (see the Windows API LogonUser function) for a remote DB connection. When I do that here is what my sample code produces:

// SCENARIO A
BEGIN impersonation.
Local user = MyDomain\MyUser
DB reports: MyDomain\ImpersonatedUser
END impersonation.
Local user = MyDomain\MyUser
DB reports: MyDomain\ImpersonatedUser << NOT EXPECTED HERE!!

The only workaround I have found is to use the LOGON32_LOGON_INTERACTIVE logon type and then I get this:

// SCENARIO B
BEGIN impersonation.
Local user = MyDomain\ImpersonatedUser << EXPECTED, BUT NOT WANTED!
DB reports: MyDomain\ImpersonatedUser
END impersonation.
Local user = MyDomain\MyUser
DB reports: MyDomain\MyUser

From the terse description of the WindowsImpersonationContext.Undo method it sure seems like it should have worked in Scenario A.

Is it possible to revert using the LOGON32_LOGON_NEW_CREDENTIALS logon type?


Solution

  • Thanks to input from Harry Johnston (in comments attached to the question) and Phil Harding (in separate communication) I was able to determine that SQL Server connection pooling was the culprit here. Since pooling is determined by uniqueness of the connection string, by slightly varying the connection string (e.g. reversing order of parameters within, or even just adding a space on the end) I then observed the behaviors I expected.

    ===== TEST WITH SAME CONN STRING: True
    BEGIN impersonation
    Local user: MyDomain\msorens
    DB reports: MyDomain\testuser
    END impersonation
    Local user: MyDomain\msorens
    DB reports: MyDomain\testuser <<<<< still impersonating !!
    
    ===== TEST WITH SAME CONN STRING: False
    BEGIN impersonation
    Local user: MyDomain\msorens
    DB reports: MyDomain\testuser
    END impersonation
    Local user: MyDomain\msorens
    DB reports: MyDomain\msorens  <<<<< this is what I wanted to get