Click here to Skip to main content
6,822,123 members and growing! (17,751 online)
Email Password   helpLost your password?
Languages » C# » General     Intermediate

Windows Impersonation using C#

By Marc Merritt

An article demonstrating how to use Windows impersonation in your C# code
C#, Windows, .NET1.0, .NET1.1, Dev
Posted:29 Apr 2003
Views:223,514
Bookmarked:80 times
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
32 votes for this article.
Popularity: 6.26 Rating: 4.16 out of 5
6 votes, 18.8%
1

2

3
6 votes, 18.8%
4
20 votes, 62.5%
5

Impersonation

Introduction

I've been a member of the CodeProject for over 3 years now, and still haven't contributed any articles - until now.

While designing a Windows Forms-based application, to administrate containers in our Active Directory, I needed a way to allow binding to the AD using alternate credentials. Windows impersonation was the answer. This sample app demonstrates how to use unmanaged code by calling LogonUser() contained within the advapi32.dll, and pass a token handle back to your .NET application using WindowsImpersonationContext.

One of the downfalls to the LogonUser()function is that the password get passed in clear-text.

Partial Source Code

using System.Runtime.InteropServices; // DllImport

using System.Security.Principal; // WindowsImpersonationContext

using System.Security.Permissions; // PermissionSetAttribute

...

public WindowsImpersonationContext 
    ImpersonateUser(string sUsername, string sDomain, string sPassword)
{
    // initialize tokens

    IntPtr pExistingTokenHandle = new IntPtr(0);
    IntPtr pDuplicateTokenHandle = new IntPtr(0);
    pExistingTokenHandle = IntPtr.Zero;
    pDuplicateTokenHandle = IntPtr.Zero;
    
    // if domain name was blank, assume local machine

    if (sDomain == "")
        sDomain = System.Environment.MachineName;

    try
    {
        string sResult = null;

        const int LOGON32_PROVIDER_DEFAULT = 0;

        // create token

        const int LOGON32_LOGON_INTERACTIVE = 2;
        //const int SecurityImpersonation = 2;


        // get handle to token

        bool bImpersonated = LogonUser(sUsername, sDomain, sPassword, 
            LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, 
                ref pExistingTokenHandle);

        // did impersonation fail?

        if (false == bImpersonated)
        {
            int nErrorCode = Marshal.GetLastWin32Error();
            sResult = "LogonUser() failed with error code: " + 
                nErrorCode + "\r\n";

            // show the reason why LogonUser failed

            MessageBox.Show(this, sResult, "Error", 
                MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        // Get identity before impersonation

        sResult += "Before impersonation: " + 
            WindowsIdentity.GetCurrent().Name + "\r\n";

        bool bRetVal = DuplicateToken(pExistingTokenHandle, 
            (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, 
                ref pDuplicateTokenHandle);

        // did DuplicateToken fail?

        if (false == bRetVal)
        {
            int nErrorCode = Marshal.GetLastWin32Error();
            // close existing handle

            CloseHandle(pExistingTokenHandle); 
            sResult += "DuplicateToken() failed with error code: " 
                + nErrorCode + "\r\n";

            // show the reason why DuplicateToken failed

            MessageBox.Show(this, sResult, "Error", 
                MessageBoxButtons.OK, MessageBoxIcon.Error);
            return null;
        }
        else
        {
            // create new identity using new primary token

            WindowsIdentity newId = new WindowsIdentity
                                        (pDuplicateTokenHandle);
            WindowsImpersonationContext impersonatedUser = 
                                        newId.Impersonate();

            // check the identity after impersonation

            sResult += "After impersonation: " + 
                WindowsIdentity.GetCurrent().Name + "\r\n";
            
            MessageBox.Show(this, sResult, "Success", 
                MessageBoxButtons.OK, MessageBoxIcon.Information);
            return impersonatedUser;
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        // close handle(s)

        if (pExistingTokenHandle != IntPtr.Zero)
            CloseHandle(pExistingTokenHandle);
        if (pDuplicateTokenHandle != IntPtr.Zero) 
            CloseHandle(pDuplicateTokenHandle);
    }
}

Points of Interest

This code won't work on Windows 98 or ME because they do not utilize user tokens. Code was built and run using Visual Studio.NET 2002 on Windows XP Service Pack 1.

One of the other uses for this code I've found is, for instantiating COM components that must run in an alternate security context to that of the logged-on user.

If anyone has a more secure method of achieving the same thing, please let me know.

History

  • Version 1.0 - 04.25.03 - First release version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Marc Merritt


Member
Doing my own consulting gig these days. It's so fun to work in your pajamas and act professional.

I live in southeastern Pennsylvania, USA with my lovely wife and two beautiful daughters. Life is good.
Occupation: Web Developer
Location: United States United States

Other popular C# articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 25 of 46 (Total in Forum: 46) (Refresh)FirstPrevNext
GeneralCreate a folder on a remote computer PinmemberShlomo2:52 6 Jan '10  
GeneralWindows 2008 server Pinmembersmithafebinkal19:45 3 Dec '08  
GeneralThis process not working with a WPF application!!! PinmemberArshad Kunnath2:36 31 Jul '08  
GeneralRe: This process not working with a WPF application!!! PinmemberMarc Merritt3:59 31 Jul '08  
QuestionIt may be.... PinmemberWillian.BR9:55 15 May '08  
GeneralWindows CE .net Pinmemberquestions_c3:28 1 Oct '07  
GeneralRe: Windows CE .net PinmemberMarc Merritt16:18 1 Oct '07  
GeneralRe: Windows CE .net PinmemberPram_Singh415:22 20 Jul '09  
GeneralError Code 1326 [modified] Pinmembercollapo1:56 21 Aug '07  
GeneralRe: Error Code 1326 Pinmembermirh2:59 10 Oct '07  
GeneralError 1314 Pinmemberm.aldegheri7:28 3 Aug '06  
GeneralRe: Error 1314 Pinmemberm.aldegheri23:23 3 Aug '06  
GeneralRe: Error 1314 PinmemberMunkieFish8:49 11 Apr '07  
AnswerRe: Error 1314 Pinmemberuppals14:06 12 Apr '07  
GeneralHelp needed Windows 2000 SP4 still getting 1314! -- Re: Error 1314 Pinmemberdevvvy21:41 21 Feb '08  
GeneralRe: Help needed Windows 2000 SP4 still getting 1314! -- Re: Error 1314 PinmemberMarc Merritt4:02 26 Feb '08  
Generalhow to use this in case of a local account? Pinmemberyossof elnaggar21:29 27 Jun '06  
GeneralRe: how to use this in case of a local account? Pinmemberhk1120:04 12 Jul '07  
GeneralFirst call takes too long Pinmemberschweeneh7:04 4 Apr '06  
GeneralRe: First call takes too long PinmemberMarc Merritt3:24 12 Jun '06  
GeneralA similar article PinsitebuilderUwe Keim0:59 24 Apr '05  
GeneralRe: A similar article Pinmembercraigg756:57 3 Nov '06  
GeneralRe: A similar article PinsitebuilderUwe Keim7:14 3 Nov '06  
GeneralImpersonation Pinmemberchriskoiak6:13 16 Mar '04  
QuestionRe: Impersonation Pinmembertee_jay23:08 10 Apr '06  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

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

PermaLink | Privacy | Terms of Use
Last Updated: 29 Apr 2003
Editor: Nishant Sivakumar
Copyright 2003 by Marc Merritt
Everything else Copyright © CodeProject, 1999-2010
Web18 | Advertise on the Code Project