views:

417

answers:

2

I would like to temporarily impersonate a domain user account to read in a file on a network drive from an ASP.NET site.

I would rather not set up impersonation for the entire site or set up a mapped drive on the server.

+4  A: 

I ended up using code from Michiel van Otegem: WindowsImpersonationContext made easy and added an implementation of IDisposable. I found this in another question about impersonation in ASP.NET.

Usage:

using (WindowsImpersonationContextFacade impersonationContext
     = new WindowsImpersonationContextFacade(
                    Settings.Default.ImpersonationDomain, 
                    Settings.Default.ImpersonationUser,
                    Settings.Default.ImpersonationPass))
                {
                    transactions  = TransactionLoader.Load(filePath);
                }

Code:

using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;
using System.ComponentModel;

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

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

        private const int LOGON32_PROVIDER_DEFAULT = 0;
        private const int LOGON32_LOGON_INTERACTIVE = 2;

        private string m_Domain;
        private string m_Password;
        private string m_Username;
        private IntPtr m_Token;

        private WindowsImpersonationContext m_Context = null;

        protected bool IsInContext
        {
            get { return m_Context != null; }
        }

        public WindowsImpersonationContextFacade(string domain, string username, string password)
        {
            m_Domain = domain;
            m_Username = username;
            m_Password = password;
            Enter();
        }

        [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
        private void Enter()
        {
            if (this.IsInContext) return;
            m_Token = IntPtr.Zero;
            bool logonSuccessfull = LogonUser(
                m_Username,
                m_Domain,
                m_Password,
                LOGON32_LOGON_INTERACTIVE,
                LOGON32_PROVIDER_DEFAULT,
                ref m_Token);
            if (logonSuccessfull == false)
            {
                int error = Marshal.GetLastWin32Error();
                throw new Win32Exception(error);
            }
            WindowsIdentity identity = new WindowsIdentity(m_Token);
            m_Context = identity.Impersonate();
        }

        [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
        private void Leave()
        {
            if (this.IsInContext == false) return;
            m_Context.Undo();

            if (m_Token != IntPtr.Zero) CloseHandle(m_Token);
            m_Context = null;
        }

        public void Dispose()
        {
            Leave();
        }
    }
}
Even Mien
Personally, I wouldn't be a fan of this since you have dllimports and other items, and overall you can get by without doing it.
Mitchel Sellers
A: 

Actually, the process is quite easy, you can use code like this;

using System.Security.Principal;
...
// Obtain the authenticated user's Identity
WindowsIdentity winId = (WindowsIdentity)HttpContext.Current.User.Identity;
WindowsImpersonationContext ctx = null;
try
{
  // Start impersonating
  ctx = winId.Impersonate();
  // Now impersonating
  // Access resources using the identity of the authenticated user
}
// Prevent exceptions from propagating
catch
{
}
finally
{
  // Revert impersonation
  if (ctx != null)
    ctx.Undo();
}
// Back to running under the default ASP.NET process identity

Your code goes in the "Now impersonating" section. the KEY is the finally block, this is VERY important. You can view this MSDN article for full details on how this works.

Mitchel Sellers
Can this also be used by passing in a domain, username and password?
Even Mien
Yes, you just need to create a new windows identity.
Mitchel Sellers