Voici une librairie qui permet d’exécuter des portions de code sous l’identité d’un autre utilisateur. Peut être utile si vous avez besoin de copier des fichiers vers un dossier sur lequel vous n’avez pas les droits (une autre machine par exemple), ou encore pour exécuter une requête SQL ayant besoin d’un utilisateur particulier…
Le but est ici de pouvoir changer le contexte utilisateur pour un morceau de code particulier tout en s’assurant que la déconnexion se fait bien ;)

Remarque : le fait de changer de contexte fera exécuter ce code “en tant qu’un autre utilisateur”, si cet autre utilisateur n’a pas les droits sur votre poste ou si, par exemple, vous tentez d’accéder à des fichiers locaux, il faudra bien prendre ceci en compte : par exemple copier des fichiers de “c:\users\monuser\documents” vers “c:\users\monautreuser\documents” ne fonctionnera surement pas sans passer par un dossier temporaire avec des droits pour les 2 utilisateurs.

Voici donc deux exemples d’utilisation, suivi de la librairie.

CODE 1 :

private static void DemoForFileCopy()
{
  //Ce code fais une copie des fichiers .doc du dossier Documents (sans les sous-dossiers)
  //de l'utilisateur actuel vers l'utilisateur "OtherUser"
  //A cause de l'impersonation qui executera le code avec les droits
  //de l'utilisateur "OtherUser", nous devons copier les fichier dans
  //un dossier temporaire accessible aux deux utilisateurs!
  string tmpPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), @"DarkImpersonationDemo");
  if (!System.IO.Directory.Exists(tmpPath))
    System.IO.Directory.CreateDirectory(tmpPath);
  try
  {
    string OtherUser = "user2";
    string OtherUserPassword = "xxx";
    string OtherUserDomain = "dom";
    Console.WriteLine("Copy to a temp folder");
    foreach (var item in System.IO.Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "*.doc*"))
      System.IO.File.Copy(item, System.IO.Path.Combine(tmpPath, System.IO.Path.GetFileName(item)));
    Console.WriteLine("Copy to {0} doc folder", OtherUser);
    using (new DarkImpersonation.Logon(OtherUser, OtherUserPassword, OtherUserDomain, true))
    {
      foreach (var item in System.IO.Directory.GetFiles(tmpPath, "*.doc*"))
        System.IO.File.Copy(item, System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), System.IO.Path.GetFileName(item)), true);
    }
  }
  catch (Exception ex)
  {
    Console.WriteLine("Exception during demo : {0}", ex.Message);
  }
  finally
  {
    Console.WriteLine("Clean temp folder");
    System.IO.Directory.Delete(tmpPath, true);
  }
}

CODE 2 :

private static void DemoForSQLExec()
{
  //Pour la démo, nous utiliserons 2 "Quality Servers" utilisant le même utilisateur,
  //2 "Production Servers" utilisant un autre utilisateur
  //et 1 "Development Server" utilisant l'utilisateur actuel
  List<SQLServerDemo> SQLServers = new List<SQLServerDemo>(){
    new SQLServerDemo(){ Server="QSRV1", Domain="domain", User="user_quality", Password="mypass"   , ConnectionString="DataSource=xxx,..."},
    new SQLServerDemo(){ Server="QSRV2", Domain="domain", User="user_quality", Password="mypass"   , ConnectionString="DataSource=xxx,..."},
    new SQLServerDemo(){ Server="PSRV1", Domain="domain", User="user_production", Password="mypass", ConnectionString="DataSource=xxx,..."},
    new SQLServerDemo(){ Server="PSRV2", Domain="domain", User="user_production", Password="mypass", ConnectionString="DataSource=xxx,..."},
    new SQLServerDemo(){ Server="DSRV1"                                                            , ConnectionString="DataSource=xxx,..."}
  };
  string SQLToExecute = "select count(*) from tblQueue";
  Parallel.ForEach(SQLServers, server =>
  {
    try
    {
      using (new DarkImpersonation.Logon(server.User, server.Password, server.Domain, true))
      {
        System.Data.SqlClient.SqlConnection cnx = null;
        System.Data.SqlClient.SqlCommand cmd = null;
        try
        {
          cnx = new System.Data.SqlClient.SqlConnection(server.ConnectionString);
          cnx.Open();
          cmd = new System.Data.SqlClient.SqlCommand(SQLToExecute, cnx);
          server.Result = (int)cmd.ExecuteScalar();
        }
        catch (Exception ex)
        {
          throw ex;
        }
        finally
        {
          if (cmd != null)
            cmd.Dispose();
          if (cnx != null)
          {
            if (cnx.State == System.Data.ConnectionState.Open)
              cnx.Close();
            cnx.Dispose();
          }
        }
      }
    }
    catch (Exception ex)
    {
      server.Result = int.MinValue;
      Console.WriteLine("Server {0} : exception:{1}", server.Server, ex.Message);
    }
  });
  //Show Results
  foreach (var server in SQLServers.Where(t => t.Result != int.MinValue))
  {
    Console.WriteLine("Server {0} : {1}", server.Server, server.Result);
  }
}
class SQLServerDemo
{
  public string Server { get; set; }
  public string User { get; set; }
  public string Domain { get; set; }
  public string Password { get; set; }
  public string ConnectionString { get; set; }
  public int Result { get; set; }
}

La DLL DarkImpersonation : [LINK (zip)]

Le code source du projet complet (démo + dll) : [LINK]