Questa classe incapsula una serie di dichiarazioni
P/INVOKE per la modifica a runtime dell'utente loggato al sistema, utile ad
esempio se da una pagina ASP.NET occorre accedere
MOMENTANEAMENTE a risorse accessibili solo come
utente != ASP.NET...
Chiaramente occhio a quello che fate...
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
namespace GisSharpBlog.Logging
{
/// <summary>
/// Changes the account logged to system.
/// </summary>
public class ImpersonationChanger : IDisposable
{
#region STATIC P/INVOKE DECLARATIONS
[DllImport("advapi32.dll")]
private static extern int LogonUser(string userName, string domain, string password,
int logonType, int logonProvider, ref IntPtr token);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern int DuplicateToken(IntPtr token, int impersonationLevel, ref IntPtr newToken);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern bool CloseHandle(IntPtr handle);
#endregion
#region PARAMETERS
private const int LOGON32_LOGON_NETWORK = 3;
private const int LOGON32_PROVIDER_DEFAULT = 0;
#endregion
#region CLASS IMPL
private WindowsImpersonationContext impersonationContext = null;
private string domain = String.Empty;
private string username = String.Empty;
private string password = String.Empty;
public ImpersonationChanger(string domain, string username, string password)
{
this.domain = domain;
this.username = username;
this.password = password;
}
/// <summary>
/// Log to system with modified user informations.
/// </summary>
/// <exception cref="ApplicationException">If wrong user parameters are used.</exception>
public WindowsImpersonationContext ImpersonateValidUser()
{
WindowsIdentity windowsIdentity = null;
IntPtr token = IntPtr.Zero;
if(RevertToSelf())
{
if(LogonUser(username, domain, password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, ref token) != 0)
{
windowsIdentity = new WindowsIdentity(token);
impersonationContext = windowsIdentity.Impersonate();
if (impersonationContext != null)
{
CloseHandle(token);
return impersonationContext;
}
}
}
if(token != IntPtr.Zero)
CloseHandle(token);
throw new ApplicationException("Should never reach here!");
}
/// <summary>
/// Revert changes.
/// </summary>
/// <param name="impersonationContext"></param>
public void UndoImpersonation()
{
if(impersonationContext != null)
impersonationContext.Undo();
impersonationContext = null;
}
#endregion
#region IDISPOSABLE IMPL
/// <summary>
///
/// </summary>
public virtual void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
UndoImpersonation();
impersonationContext = null;
}
~ImpersonationChanger()
{
Dispose (false);
}
#endregion
}
}
download code
Ecco come si usa:
using(new GisSharpBlog.Logging.ImpersonationChanger("domain", "username", "password"))
{
// Do work with new log user credentials...
}
// Continue with old credentials...
Difficile, no? Sia benedetto il pattern Dispose...
Posto un paio di configurazioni: questo codice mi serviva
per accedere a dei files in rete locale da un WebService, cosa che l'utente
normale ASP.NET non permette di fare; ora, non sono riuscito a compiere tale
operazione utilizzando questa classe (da alcuni post trovati su internet pare
che non sia possibile se non modificando il file machine.config, cosa che è una autentica pazzia come pure
Lorenzo non ha mancato di farmi
notare...), ma apparentemente la fase di log funziona correttamente... nel
caso abbiate voglia di fare dei test segnalatemi pure eventuali
problemi.
Buon lavoro
powered by IMHO 1.3