#929 - Impersonation di utente per l'esecuzione di codice in una pagina ASP.NET

In applicazioni che richiedono diverse procedure ed un alto grado di sicurezza, si può avere la necessità di eseguire un blocco di codice con un utente differente rispetto a quello del thread principale.
Questo è richiesto in quanto si deve avere la certezza che una certa procedura non vada a toccare parti sensibili o possa accedere solo in quel caso a delle share di rete non accessibili dall'utente con cui gira il processo.

Purtroppo il Framework .NET non ci mette a disposizione niente di pronto, quindi dobbiamo creare qualcosa che ci aiuti in questo.

Per prima cosa dobbiamo importare nella nostra classe 2 diverse componenti e 4 metodi come mostrato nello snippet seguente:

[DllImport("advapi32.dll")]
  public static extern int LogonUserA(String lpszUserName,
  String lpszDomain,
  String lpszPassword,
  int dwLogonType,
  int dwLogonProvider,
  ref IntPtr phToken);

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken,
  int impersonationLevel,
  ref IntPtr hNewToken);

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();

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

A questo punto è neccessario creare due metodi che si occupino di cambiare l'utente corrente con quello con cui vogliamo eseguire l'operazione e reimpostare l'utente principale, come mostrato dallo snippet seguente:

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

private WindowsImpersonationContext impersonationContext;

private bool ImpersonateValidUser(String userName, String domain, String password)
{
  WindowsIdentity tempWindowsIdentity;
  IntPtr token = IntPtr.Zero;
  IntPtr tokenDuplicate = IntPtr.Zero;

  if (RevertToSelf())
  {
    if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
      LOGON32_PROVIDER_DEFAULT, ref token) != 0)
    {
      if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
      {
        tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
        impersonationContext = tempWindowsIdentity.Impersonate();
        if (impersonationContext != null)
        {
          CloseHandle(token);
          CloseHandle(tokenDuplicate);
          return true;
        }
      }
    }
  }
  if (token != IntPtr.Zero)
    CloseHandle(token);

  if (tokenDuplicate != IntPtr.Zero)
    CloseHandle(tokenDuplicate);

  return false;
}

private void UndoImpersonation()
{
  impersonationContext.Undo();
}

Si può quindi utilizzare il metodo come mostrato nel seguente snippet:

protected override void OnLoad(EventArgs e)
{
  base.OnLoad(e);

  string principalThreadUsername = System.Security.Principal.WindowsIdentity.GetCurrent().Name
  if (ImpersonateValidUser("username", "dominio", "password"))
  {
    string impersonatingUserName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
   
    //inserire qui il codice che ha necessità di girare con credenziali differenti


    UndoImpersonation();
  }
  else
  {
    //i dati dell'utente specificato sono errati

  }
}

Come si può notare dallo snippet precendente sono state create due variabili (principalThreadUsername, impersonatingUserName) che mostrano lo username dell'utente prima e dopo l'impersonate.
Questo è fattibile grazie alla classe WindowsIdentity ed al suo metodo GetCurrent.


Approfondimenti

Commenti

Esprimi il tuo giudizio su questo script:

Per procedere devi essere autenticato.

pietro09 scrive:
#929 - Impersonation di utente per l'esecuzione di codice in una pagina ASP.NET

Ho provato il codice e funziona perfettamente.Poi ho provato, con utente Administrator, ad accedere ad una directory di rete (connessione di rete già ...
lunedì 4 febbraio 2008 | 3 risposte

Per inserire un commento, devi registrarti alla nostra community.




IN EVIDENZA
MISC