Michiel van Otegem, IT Composer

Wednesday, January 11, 2006

WindowsImpersonationContext: kan dat niet makkelijker?

Soms kom je dingen tegen dat je denkt... hadden ze dat nou niet ff makkelijker kunnen maken in het framework? Vandaag had ik er weer zo een, namelijk met de WindowsImpersonationContext. An sich is de context heel handig, gewapend met een zogenaamde token handle van een gebruikersaccount kun je de betreffende gebruiker impersoniseren. Dat is bijvoorbeeld nodig als toegang tot een netwerk share wilt delegeren, terwijl de rest van je applicatie gewoon werkt op basis van de ingelogde gebruiker. Dit komt met name in web scenario's nog wel eens voor.

Het probleem is dat je om de token handle te krijgen op basis van een gebruikersnaam en wachtwoord je een Win32 call moet maken. Met andere woorden je moet unmanaged code aanroepen (help!). Het is niet echt heel moelijk, maar je moet weten welke referenties naar DLLs je moet maken, een IntPtr gebruiken, enzovoorts. Allemaal niet waar wij als ontwikkelaars op zitten te wachten. En dat terwijl het niet eens zo ingewikkeld is om de ontwikkelaar daarvan af te schermen door een simpele wrapper class. Voordeel daarvan zou ook meteen weer zijn dat er niet met /unsafe gecompileerd hoeft te worden, wat voor de meeste mensen toch wel eng is. Met zo'n wrapper class zou de gemiddelde ontwikkelaar het volgende maar hoeven te doen:

Console.WriteLine("Huidige gebruiker: " + WindowsIdentity.GetCurrent().Name);
WrapperImpersonationContext context = new WrapperImpersonationContext(domain, username, password);
context.Enter();

// Voer code uit in context van ander gebruikersaccount
Console.WriteLine("Huidige gebruiker: " + WindowsIdentity.GetCurrent().Name);
context.Leave();
Console.WriteLine("Huidige gebruiker: " + WindowsIdentity.GetCurrent().Name);


Nu vraag je je natuurlijk af hoe die wrapper class er dan uit zou moeten zien. Wel... als volgt:

public class WrapperImpersonationContext
{
[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
=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)]
public extern static bool CloseHandle(IntPtr handle);

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

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;

[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public void Enter()
{
if(this.IsInContext) return;
m_Token = new IntPtr(0);
try
{
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();
}
catch (Exception exception)
{
// Catch exceptions here
}
}

public void Leave()
{
if (this.IsInContext == false) return;
m_Context.Undo();

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

2 Comments:

  • Handige class, echt iets om vaker te gebruiken, maar moer er niet iets van
    using System.Runtime.InteropServices;
    bovenaan ? want de DLLImport kent ie niet.
    Daarna krijg ik de melding :
    C:\Documents and Settings\Administrator\My Documents\ImpersonationWrapper\ImpersonationWrapper.cs(34): The type or namespace name 'WindowsImpersonationContext' could not be found (are you missing a using directive or an assembly reference?)

    By Anonymous Anonymous, at 07 July, 2006 13:33  

  • Je hebt volkomen gelijk. Sterker nog, er missen nog een paar kleine zaken. Ik heb het in m'n nieuwe blog gezet: WindowsImpersonationContext made easy. Wellicht dat ik 'm ook nog in het Nederlands plaats.

    By Blogger Michiel van Otegem, at 07 July, 2006 21:25  

Post a Comment

<< Home