Click here to Skip to main content
15,886,026 members
Articles / Web Development / IIS

A small C# Class for impersonating a User

Rate me:
Please Sign up or sign in to vote.
4.94/5 (127 votes)
11 Apr 2005CPOL3 min read 1.3M   52.4K   243   192
Introduced a class that simplifies Windows Impersonation in C#.

Introduction

The term "Impersonation" in a programming context refers to a technique that executes the code under another user context than the user who originally started an application, i.e. the user context is temporarily changed once or multiple times during the execution of an application.

The reason for doing this is to perform tasks that the current user context of an application is not allowed to do. Of course you could grant the user executing an application more privileges, but usually this is a bad idea (due to security constraints) or impossible (e.g. if you don't have full administrative access to a machine to do so).

This article presents an easy-to-use class to impersonate a user. While writing this, I found out that Marc Merrit had written an article ("Windows Impersonation using C#") that uses the same Microsoft knowledge base code (from Q306158) that I have used. The code presented in my article differs in the fact that you could use it inside a using-block to safely release resources and that I use slightly more exceptions to report errors. But from a first look, both his and my article do the same job, so it's up to you to decide what to do.

(For the latest changes, please see the History section below).

Background

I wrote the Impersonator class because of a need to write a web page with ASP.NET to make a server reboot. In order to do this, I needed to impersonate the part of my code that does the actual reboot.

The constructor of the class internally calls the Windows function LogonUser through P/Invoke. Please see the MSDN documentation of the function for a full description of all three parameters (username, domain, password) to the constructor.

Please note: The user context that initiates the impersonation (i.e. not the user context to which it is switched to) needs to have the "Act as part of operating system" privilege set.

Using the code

To use the code, you simply construct the Impersonator class and pass the username, the domain and the password to the constructor. If you place an instance of the class inside a using-block, you need no further steps.

The following is a schematic example of how to use the class:

C#
... 
using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
{
   ...
   
   <code that executes under the new context>
  
   ...
}
  
...

An example project demonstrating the technique is included in the download of this article (please look at the "Program.cs" for the main demonstration source file). Also the complete source code of the class is included inside the source file "Impersonator.cs".

To include the Impersonator class into your project, simply copy and add the source file "Impersonator.cs" to your project, so that it gets compiled with your project.

Conclusion

In this article, I've shown you a small class to quickly and easily impersonate a part of your code to run under another user context. Hopefully you'll find this class useful.

For questions, comments and remarks, please use the commenting section at the bottom of this article.

References

In addition to the links in the article, the following references might be of interest:

  1. Google search for "Windows Impersonation"

History

  • 2005-04-11: Created first version of article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer Zeta Software GmbH
Germany Germany
Uwe does programming since 1989 with experiences in Assembler, C++, MFC and lots of web- and database stuff and now uses ASP.NET and C# extensively, too. He has also teached programming to students at the local university.

➡️ Give me a tip 🙂

In his free time, he does climbing, running and mountain biking. In 2012 he became a father of a cute boy and in 2014 of an awesome girl.

Some cool, free software from us:

Windows 10 Ereignisanzeige  
German Developer Community  
Free Test Management Software - Intuitive, competitive, Test Plans.  
Homepage erstellen - Intuitive, very easy to use.  
Offline-Homepage-Baukasten

Comments and Discussions

 
GeneralRe: Does not work for remote local accounts Pin
Uwe Keim13-Mar-08 19:01
sitebuilderUwe Keim13-Mar-08 19:01 
GeneralRe: Does not work for remote local accounts Pin
D Waterworth29-May-08 13:36
D Waterworth29-May-08 13:36 
QuestionRe: Does not work for remote local accounts Pin
A_Mano28-Jul-08 9:39
A_Mano28-Jul-08 9:39 
GeneralGetting invalid logon [modified] Pin
deerinb23-Jan-08 10:26
deerinb23-Jan-08 10:26 
GeneralUnfortunately doesn't work in asp.net Pin
vytas z.12-Dec-07 1:35
vytas z.12-Dec-07 1:35 
GeneralRe: Unfortunately doesn't work in asp.net Pin
Chris Maunder8-Jan-08 1:00
cofounderChris Maunder8-Jan-08 1:00 
GeneralSimple, Easy and working properly.... Pin
Ricardo Casquete10-Dec-07 10:53
Ricardo Casquete10-Dec-07 10:53 
GeneralConverted to VB.NET Pin
Zyxil9-Nov-07 7:45
Zyxil9-Nov-07 7:45 
in case anybody wants it...

<code>
'class designed to impersonate a user
'based on code from: http://www.codeproject.com/csharp/zetaimpersonator.asp

Imports System
Imports System.Security.Principal
Imports System.Runtime.InteropServices
Imports System.ComponentModel

Public Class Impersonator
Implements IDisposable

Public Sub New(ByVal DomainName As String, ByVal UserName As String, _
ByVal Password As String)
ImpersonateValidUser(UserName, DomainName, Password)
End Sub

Private impersonationContext As WindowsImpersonationContext = Nothing

Private Sub ImpersonateValidUser(ByVal UserName As String, _
ByVal DomainName As String, ByVal Password As String)
Dim tempWindowsIdentity As WindowsIdentity = Nothing
Dim token As IntPtr = IntPtr.Zero
Dim tokenDuplicate As IntPtr = IntPtr.Zero

Try
If RevertToSelf() Then
If LogonUser(UserName, DomainName, Password, _
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, _
token) <> 0 Then
If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
impersonationContext = tempWindowsIdentity.Impersonate
Else
Throw New Win32Exception(Marshal.GetLastWin32Error)
End If
Else
Throw New Win32Exception(Marshal.GetLastWin32Error)
End If
Else
Throw New Win32Exception(Marshal.GetLastWin32Error)
End If

Finally
If token <> IntPtr.Zero Then
CloseHandle(token)
End If
If tokenDuplicate <> IntPtr.Zero Then
CloseHandle(tokenDuplicate)
End If

End Try
End Sub

Private Sub UndoImpersonation()
If impersonationContext IsNot Nothing Then
impersonationContext.Undo()
End If
End Sub

#Region " P/Invoke "
Private Const LOGON32_LOGON_INTERACTIVE As Integer = 2
Private Const LOGON32_PROVIDER_DEFAULT As Integer = 0

<DllImport("advapi32.dll", SetLastError:=True)> _
Private Shared Function LogonUser(ByVal lpszUserName As String, _
ByVal lpszDomain As String, ByVal lpszPassword As String, _
ByVal dwLogonType As Integer, ByVal dwLogonProvider As Integer, _
ByRef phToken As IntPtr) As Integer
End Function

<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Private Shared Function DuplicateToken(ByVal hToken As IntPtr, _
ByVal impersonationLevel As Integer, ByRef hNewToken As IntPtr) As Integer
End Function


<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Private Shared Function RevertToSelf() As Boolean
End Function

<DllImport("kernel32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function CloseHandle(ByVal handle As IntPtr) As Boolean
End Function
#End Region



#Region " IDisposable Support "
Private disposedValue As Boolean = False ' To detect redundant calls

' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
UndoImpersonation()
End If
End If
Me.disposedValue = True
End Sub

' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region

End Class
</code>

-John
QuestionImpersonator and DSOFile Pin
Daniele Perilli7-Nov-07 23:46
Daniele Perilli7-Nov-07 23:46 
GeneralThanks! Pin
boo13-Oct-07 14:12
boo13-Oct-07 14:12 
GeneralRe: Thanks! Pin
Uwe Keim13-Oct-07 20:23
sitebuilderUwe Keim13-Oct-07 20:23 
QuestionCreateProcessWithTokenW Pin
Harkamal Singh16-Jul-07 5:47
Harkamal Singh16-Jul-07 5:47 
GeneralImpersonation in ASPNET not working Pin
Talal Sultan4-Jun-07 3:46
Talal Sultan4-Jun-07 3:46 
QuestionTested on Vista? Pin
Neil Baliga2-Jun-07 17:19
Neil Baliga2-Jun-07 17:19 
AnswerRe: Tested on Vista? Pin
Uwe Keim2-Jun-07 19:37
sitebuilderUwe Keim2-Jun-07 19:37 
AnswerRe: Tested on Vista? Pin
rob.iles21-Feb-08 20:05
rob.iles21-Feb-08 20:05 
GeneralRe: Tested on Vista? Pin
Uwe Keim22-Feb-08 2:39
sitebuilderUwe Keim22-Feb-08 2:39 
GeneralRe: Tested on Vista? Pin
rob.iles22-Feb-08 2:48
rob.iles22-Feb-08 2:48 
AnswerRe: Tested on Vista? Pin
Uwe Eichkorn5-Mar-08 0:01
Uwe Eichkorn5-Mar-08 0:01 
GeneralRe: Tested on Vista? Pin
ru551an9-Apr-08 12:47
ru551an9-Apr-08 12:47 
GeneralError when compiling code [modified] Pin
cpltek14-Mar-07 9:07
cpltek14-Mar-07 9:07 
GeneralRe: Error when compiling code Pin
Eradikator26-Mar-07 0:11
Eradikator26-Mar-07 0:11 
GeneralRe: Error when compiling code Pin
cpltek26-Mar-07 8:54
cpltek26-Mar-07 8:54 
Questionhow to create file in denyaccess folder using c# Pin
Member 38880247-Mar-07 1:49
Member 38880247-Mar-07 1:49 
QuestionI still have the same problem Pin
Vince Zhou21-Feb-07 14:27
Vince Zhou21-Feb-07 14:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.