DCSIMG
Back to Basic – ASP.NET Runtime Impersonation - Gil Fink's Blog

Gil Fink's Blog

Fink about IT

News

Microsoft MVP

My Facebook Profile My Twitter Profile My Linkedin Profile

Locations of visitors to this page

Creative Commons License

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.
© Copyright 2012 Gil Fink

Hebrew Articles

Index Pages

My OSS Projects

English Articles

Back to Basic – ASP.NET Runtime Impersonation

Back to Basic – ASP.NET Runtime Impersonation

Today I got a question from one of the developers at my main customer. .Net Framework New LogoThe question was how to move an uploaded file from an ASP.NET server to a file server on the network. The answer is of course by impersonating. In this post I’ll explain how you can make ASP.NET impersonation and in more details how to make runtime impersonation.

Impersonation in ASP.NET

When we are doing I/O operations, the operation system makes security checks to understand if the user is authorized to do the operation. The same thing happens when you try to do operations on another machine in your network. Impersonation in ASP.NET occurs when ASP.NET executes code in the context of an authenticated and authorized user. By default, ASP.NET run in the ASPNET account. By using impersonation we can impersonate the ASPNET account to another account that has access to resources which aren’t granted in the internet security permission. One way to impersonate a user is by using the identity element in the web.config. When you use the following code in your web.config, ASP.NET impersonates to the authenticated user or to an anonymous internet user account:

<identity impersonate="true" />

If you want to impersonate to a specific user you can use the following configuration:

<identity impersonate="true" userName="domain\username" password="password" />

Runtime Impersonation

At my customer the previous configuration examples weren’t an option. The second way to impose impersonation is by runtime. This option can be achieved by using the System.Security.Principal and the WindowsIdentity class. The WindowsIdentity class has a method that makes impersonation and returns a WindowsImpersonationContext. The problem with this class is that you need to supply to it an IntPtr which is a security access token of the user that you wish to impersonate to. The solution is to use P/Invoke and call the LogonUser Win32 API. After you get the impersonation context you can run the network operations that you seek to perform. After you finish to do your operations you need to undo the impersonation. The following code shows an example of an impersonation service class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.InteropServices;
using System.Security.Principal;
 
namespace WebApplication1
{
    public class ImpersonationService
    {
        #region Consts
 
        public const int LOGON32_LOGON_INTERACTIVE = 2;
        public const int LOGON32_PROVIDER_DEFAULT = 0;
 
        #endregion
 
        #region External API
 
        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern int LogonUser(
            string lpszUsername,
            string lpszDomain,
            string lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            out IntPtr phToken
            );
 
        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool RevertToSelf();
 
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern int CloseHandle(IntPtr hObject);
 
        #endregion
 
        #region Methods
 
        public void PerformImpersonatedTask(string username, string domain, string password, 
            int logonType, int logonProvider, Action methodToPerform)
        {
            IntPtr token = IntPtr.Zero;
            if (RevertToSelf())
            {
                if (LogonUser(username, domain, password, logonType,
                    logonProvider, out token) != 0)
                {
                    var identity = new WindowsIdentity(token);
                    var impersonationContext = identity.Impersonate();
                    if (impersonationContext != null)
                    {
                        methodToPerform.Invoke();
                        impersonationContext.Undo();
                    }
                }
                else
                {
                    // do logging
                }
            }
            if (token != IntPtr.Zero)
            {
                CloseHandle(token);
            }
        }
 
        #endregion
    }
}

Here is an example of how to use the class in your ASP.NET application:

using System;
using System.IO;
 
namespace WebApplication1
{
    public partial class _Default : System.Web.UI.Page
    {       
        #region Page Events
 
        private void Page_Load(object sender, System.EventArgs e)
        {
            var service = new ImpersonationService();
            service.PerformImpersonatedTask("username", "domain", "password",
                ImpersonationService.LOGON32_LOGON_INTERACTIVE, ImpersonationService.LOGON32_PROVIDER_DEFAULT, new Action(MethodToPerform));
        }
 
        #endregion
 
        #region Methods
 
        public void MethodToPerform()
        {
            var serverPath = @"\\ServerName\test";
            var dirInfo = new DirectoryInfo(serverPath);
            Response.Write(dirInfo.Exists);
        }
 
        #endregion
    }
}

Summary

In the post I showed a simple way to implement a class that impersonate to a relevant account in order to achieve some functionality that internet security permissions don’t allow.  You should consider to use the web.config instead since it does all the communication with Win32 API instead of the supplied code. The impersonation isn’t limited only to ASP.NET and can be used also in other frameworks.

Comments

The Morning Brew - Chris Alcock » The Morning Brew #681 said:

Pingback from  The Morning Brew - Chris Alcock  &raquo; The Morning Brew #681

# September 8, 2010 10:21 AM

Craig said:

Or you change the anonymous user in IIS to a domain account and grant that domain account access to the required resources, whatever they may be (network shares, databases, printers, etc). In my opinion that would be the preferred approach over using an impersonation approach that requires I store the password of the account I'm impersonating either in code or a configuration file.

# September 8, 2010 6:10 PM

Jinal said:

Hi,

Can you please provide information about first option ? Why first option not worked on your case ?

Thanks.

# September 13, 2010 10:13 AM

Back to Basic – ASP.NET Runtime Impersonation said:

Pingback from  Back to Basic &#8211; ASP.NET Runtime Impersonation

# September 13, 2010 12:40 PM

Gil Fink said:

@Jinal,

At the specific customer, which is mentioned in the post, the user with the credentials is changed very often. Since this is the case they wanted a runtime solution and not a configuration solution.  

# September 13, 2010 2:43 PM

David said:

You have to use impersonate with Mosso Cloud hosting also to write files and create directories. Instead of a network/username and password, you use a cloudsite/ftp username and password.  

# September 13, 2010 9:30 PM

Twitter Trackbacks for Back to Basic ??? ASP.NET Runtime Impersonation - Gil Fink on .Net [microsoft.co.il] on Topsy.com said:

Pingback from  Twitter Trackbacks for                 Back to Basic ??? ASP.NET Runtime Impersonation - Gil Fink on .Net         [microsoft.co.il]        on Topsy.com

# September 14, 2010 8:41 AM

Shekhar said:

Remind me of my old days.

# September 14, 2010 11:33 AM

Thanigainathan said:

Like you said web.config change is the best one. When building framework's it will be better if we go with the impersonation code. But even then username and password has to be passed from config file.

Thanks,

Thani

# September 18, 2010 7:31 AM