Run Code by impersonating user privilege

Background

In my previous post I have explained that how to perform operations on local system using ASP.NET. After using it and putting the same code in testing environment I realize that I throws access denied error when normal user tries to change its password.

Problem

The main problem was that the change password functionality of windows is available to logged in users only or to administrator. And when normal user tried changing their password they encounter following error.

“Access Denied”

Solution

In order to solve this issue .NET framework has provided an solution of impersonating user privilege. Though being Security Developer I will not recommend this 🙂 To impersonate user privilege we have to provide the domain name, username and password of that user. Following code will explain the usage of the same.

public partial class ChangePassword : Page
{
	public const int LOGON32_LOGON_INTERACTIVE = 2;
	public const int LOGON32_PROVIDER_DEFAULT = 0;

	WindowsImpersonationContext impersonationContext;

	[DllImport("advapi32.dll")]
	public static extern int LogonUserA(String lpszUserName,
		String lpszDomain,
		String lpszPassword,
		int dwLogonType,
		int dwLogonProvider,
		ref IntPtr phToken);

	[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
	public static extern int DuplicateToken(IntPtr hToken,
		int impersonationLevel,
		ref IntPtr hNewToken);

	[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
	public static extern bool RevertToSelf();

	[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
	public static extern bool CloseHandle(IntPtr handle);

	protected void Page_Load(object sender, EventArgs e)
	{
		if (!IsPostBack)
		{
			if (impersonateValidUser("user", "domain/systemname", "password"))
			{
				// your code goes here
				undoImpersonation();
			}
			else
			{
				// fail safe code goes here
			}
		}
	}

	private bool impersonateValidUser(String userName, String domain, String password)
	{
		WindowsIdentity tempWindowsIdentity;
		IntPtr token = IntPtr.Zero;
		IntPtr tokenDuplicate = IntPtr.Zero;

		if (RevertToSelf())
		{
			if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
				LOGON32_PROVIDER_DEFAULT, ref token) != 0)
			{
				if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
				{
					tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
					impersonationContext = tempWindowsIdentity.Impersonate();
					if (impersonationContext != null)
					{
						CloseHandle(token);
						CloseHandle(tokenDuplicate);
						return true;
					}
				}
			}
		}
		if (token != IntPtr.Zero)
			CloseHandle(token);
		if (tokenDuplicate != IntPtr.Zero)
			CloseHandle(tokenDuplicate);
		return false;
	}

	private void undoImpersonation()
	{
		impersonationContext.Undo();
	}
}

Reference

How to implement impersonation in an ASP.NET application
http://support.microsoft.com/kb/306158#3

Posted in ASP.NET, Programming Language, Secure .NET Coding, Security, Sharepoint Security Tagged with: ,