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

di Ugo Lattanzi, in ASP.NET 2.0, Security,

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.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi