Thursday, August 19, 2010

Impersonation in Console/Windows Application

In this post I tried to cover the way to implement Impersonation in Console or Windows application. In Web application by setting Impersonation="True" in web.config we can do Impersonation but in Windows/Console it is not that straight-forward.

Here in Windows/Console we have to perform following steps [as per me]:
1. Write un-managed LogonUser function that will return UserToken based on passed input parameters
2. Get UserToken using LogonUser function
3. Pass UserToken to WindowsIdentity's constructor
4. Do the Impersonation
5. Do the required stuff using Impersonated Identity
6. Undo the Impersonation [Important]


Code Snippet:


using System;
using System.Data;
using System.Data.SqlClient;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace ImpersonationSample
{
class Program
{
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(String lpszUsername,
String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);


static void Main(string[] args)
{
IntPtr tokenHandle = new IntPtr(0);

const int LOGON32_PROVIDER_DEFAULT = 0;
//This parameter causes LogonUser to create a primary token.
const int LOGON32_LOGON_INTERACTIVE = 2;

tokenHandle = IntPtr.Zero;

string userName = "UserName";
string domainName = "DomainName";
string password = "UserPassword";

// Call LogonUser to obtain a handle to an access token.
bool returnValue = LogonUser(userName, domainName, password,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
ref tokenHandle);

// Retrieve the Windows identity using the specified token.
WindowsIdentity windowsIdentity = new WindowsIdentity(tokenHandle);

// Create a WindowsImpersonationContext object
// by impersonating the Windows identity.
WindowsImpersonationContext impersonationContext =
windowsIdentity.Impersonate();


string connectionString =
"Data Source=[Server-Name];" +
"Initial Catalog=[Database-Name];" +
"Trusted_Connection=True;" +
"Integrated Security=SSPI;" +
"User Id=[DomainName\\UserName];" +
"password= [UserPassword]";

using (SqlConnection cn = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand("SELECT COUNT(*) FROM MyTable", cn);
cn.Open();
SqlDataReader rdr
= cmd.ExecuteReader(CommandBehavior.CloseConnection);
rdr.Read();
Console.WriteLine(rdr[0].ToString()); //read a value
}

Console.WriteLine("Name of the identity after impersonation: "
+ WindowsIdentity.GetCurrent().Name + ".");
Console.WriteLine(windowsIdentity.ImpersonationLevel);


// Stop impersonating the user.
impersonationContext.Undo();

// Check the identity name.
Console.Write("Name of the identity after performing an Undo on the");
Console.WriteLine(" impersonation: " +
WindowsIdentity.GetCurrent().Name);

Console.ReadLine();
}
}
}





References:
MSDN Impersonation 1
MSDN Impersonation 1
MSDN Impersonation 1
SQL Connection String Types

Google