The code in the following class was adapted from the code in
http://msdn2.microsoft.com/en-us/librar ... text(VS.71).aspx.
If you incorporate this code into a DLL, be sure to demand FullTrust.
public class WindowsImpersonation
{
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public static WindowsIdentity GetWindowsIdentity(string domainName, string userName, string password)
{
IntPtr tokenHandle = IntPtr.Zero;
IntPtr dupeTokenHandle = IntPtr.Zero;
try
{
const int SecurityImpersonation = 2;
tokenHandle = IntPtr.Zero;
dupeTokenHandle = IntPtr.Zero;
if (!LogonUser(userName, domainName, password, (int)LogonSessionType.Interactive, (int)LogonProvider.Default, ref tokenHandle))
throw new ImpersonationException("Could not log on user {0}\\{1} (LogonUser). Error was {2}",
domainName, userName, GetErrorMessage(Marshal.GetLastWin32Error()));
if (!DuplicateToken(tokenHandle, SecurityImpersonation, ref dupeTokenHandle))
throw new ImpersonationException("Could not log on user {0}\\{1} (DuplicateToken). Error was {2}",
domainName, userName, GetErrorMessage(Marshal.GetLastWin32Error()));
// The token that is passed to the following constructor must
// be a primary token in order to use it for impersonation.
return new WindowsIdentity(dupeTokenHandle);
}
catch (Exception ex)
{
throw new ImpersonationException(ex, "Error while authenticating user {0}\\{1}", domainName, userName);
}
finally
{
if (tokenHandle != IntPtr.Zero)
CloseHandle(tokenHandle);
if (dupeTokenHandle != IntPtr.Zero)
CloseHandle(dupeTokenHandle);
}
}
private enum LogonSessionType : uint
{
Interactive = 2,
Network,
Batch,
Service,
Proxy,
Unlock,
NetworkCleartext,
NewCredentials,
RemoteInteractive,
CachedInteractive,
CachedRemoteInteractive,
CachedUnlock
}
private enum LogonProvider : uint
{
Default = 0, // default for platform (use this!)
WinNT35, // sends smoke signals to authority
WinNT40, // uses NTLM
WinNT50 // negotiates Kerb or NTLM
}
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private unsafe static extern int FormatMessage(int dwFlags, ref IntPtr lpSource,
int dwMessageId, int dwLanguageId, ref String lpBuffer, int nSize, IntPtr* Arguments);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private extern static bool CloseHandle(IntPtr handle);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
// GetErrorMessage formats and returns an error message
// corresponding to the input errorCode.
private unsafe static string GetErrorMessage(int errorCode)
{
int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
//int errorCode = 0x5; //ERROR_ACCESS_DENIED
//throw new System.ComponentModel.Win32Exception(errorCode);
int messageSize = 255;
String lpMsgBuf = "";
int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
IntPtr ptrlpSource = IntPtr.Zero;
IntPtr prtArguments = IntPtr.Zero;
int retVal = FormatMessage(dwFlags, ref ptrlpSource, errorCode, 0, ref lpMsgBuf, messageSize, &prtArguments);
if (0 == retVal)
{
throw new Exception("Failed to format message for error code " + errorCode + ". ");
}
return lpMsgBuf;
}
}
public class ImpersonationException : Exception
{
public ImpersonationException(Exception innerException, string message, params object[] args)
: base(string.Format(message, args), innerException)
{
}
public ImpersonationException(string message, params object[] args)
: this(null, message, args)
{
}
}