Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Impersonation using C#

Impersonation using C#

Scheduled Pinned Locked Moved C#
securitycsharpdatabasetutorialworkspace
5 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    JohnLBevan
    wrote on last edited by
    #1

    Hi Guys, I'm working on a windows service which runs under a given service account. It writes files to shared areas on other machines, but needs to change the owner of these files to a different account. I can do this using the SetAccessControl as below:

    //call SetOwner(@"\\servername\share\filename.ext",@"domain\username");
    public static void SetOwner(string uri, string account)
    {
    System.Security.AccessControl.FileSecurity security = File.GetAccessControl(uri);
    IdentityReference owner = new NTAccount(account);
    security.SetOwner(owner);
    File.SetAccessControl(uri, security);
    }

    However, this only works if the service account which I'm using is an administrator or backup operator on the remote machine (unless it's setting the owner to itself). I'd like to avoid giving this service account rights to too many machines, since that puts too much power in the hands of one account. Instead, I'd like to provide a username and password for the account which will be the owner of the file, and have the service impersonate this account when assigning ownership (e.g. in a similar way to how you could have credentials in a connection string for a database connection which didn't use trusted authentication). I'm looking for something like the code below, but have so far been unable to find an understandable example to work from.

    //call SetOwner(@"\\servername\share\filename.ext",@"domain\username");
    public static void SetOwner(string uri, string account)
    {
    StartImpersonating(account);
    System.Security.AccessControl.FileSecurity security = File.GetAccessControl(uri);
    IdentityReference owner = new NTAccount(account);
    security.SetOwner(owner);
    File.SetAccessControl(uri, security);
    StopImpersonating();
    }
    static void StartImpersonating(string account, string password)
    {
    System.Security.Principal.WindowsIdentity.Impersonate(account, password);
    }
    static void StartImpersonating(string account)
    {
    string password = GetPasswordFromSecureStore(account);
    StartImpersonating(account, password);
    }
    static void StartImpersonating(string domain, string username)
    {
    StartImpersonating(string.Format("{0}\\{1}",domain,username));
    }
    static void StopImpersonating()
    {
    StartImpersonating(System.Environment.UserDomainName,System.Environment.UserName);
    }

    NB: the above code is just for illustrative purposes to show the sort of thing I'm looking for; I've no idea whether what's there is even close to w

    A M 2 Replies Last reply
    0
    • J JohnLBevan

      Hi Guys, I'm working on a windows service which runs under a given service account. It writes files to shared areas on other machines, but needs to change the owner of these files to a different account. I can do this using the SetAccessControl as below:

      //call SetOwner(@"\\servername\share\filename.ext",@"domain\username");
      public static void SetOwner(string uri, string account)
      {
      System.Security.AccessControl.FileSecurity security = File.GetAccessControl(uri);
      IdentityReference owner = new NTAccount(account);
      security.SetOwner(owner);
      File.SetAccessControl(uri, security);
      }

      However, this only works if the service account which I'm using is an administrator or backup operator on the remote machine (unless it's setting the owner to itself). I'd like to avoid giving this service account rights to too many machines, since that puts too much power in the hands of one account. Instead, I'd like to provide a username and password for the account which will be the owner of the file, and have the service impersonate this account when assigning ownership (e.g. in a similar way to how you could have credentials in a connection string for a database connection which didn't use trusted authentication). I'm looking for something like the code below, but have so far been unable to find an understandable example to work from.

      //call SetOwner(@"\\servername\share\filename.ext",@"domain\username");
      public static void SetOwner(string uri, string account)
      {
      StartImpersonating(account);
      System.Security.AccessControl.FileSecurity security = File.GetAccessControl(uri);
      IdentityReference owner = new NTAccount(account);
      security.SetOwner(owner);
      File.SetAccessControl(uri, security);
      StopImpersonating();
      }
      static void StartImpersonating(string account, string password)
      {
      System.Security.Principal.WindowsIdentity.Impersonate(account, password);
      }
      static void StartImpersonating(string account)
      {
      string password = GetPasswordFromSecureStore(account);
      StartImpersonating(account, password);
      }
      static void StartImpersonating(string domain, string username)
      {
      StartImpersonating(string.Format("{0}\\{1}",domain,username));
      }
      static void StopImpersonating()
      {
      StartImpersonating(System.Environment.UserDomainName,System.Environment.UserName);
      }

      NB: the above code is just for illustrative purposes to show the sort of thing I'm looking for; I've no idea whether what's there is even close to w

      A Offline
      A Offline
      Adam R Harris
      wrote on last edited by
      #2

      Seek and ye shall find Windows Impersonation using C#[^]. It's from '03 but im sure the pricipals are still the same, you are going to have to call the Windows API to get done but the above link should help you out.

      Don't comment your code - it was hard to write, it should be hard to read!

      1 Reply Last reply
      0
      • J JohnLBevan

        Hi Guys, I'm working on a windows service which runs under a given service account. It writes files to shared areas on other machines, but needs to change the owner of these files to a different account. I can do this using the SetAccessControl as below:

        //call SetOwner(@"\\servername\share\filename.ext",@"domain\username");
        public static void SetOwner(string uri, string account)
        {
        System.Security.AccessControl.FileSecurity security = File.GetAccessControl(uri);
        IdentityReference owner = new NTAccount(account);
        security.SetOwner(owner);
        File.SetAccessControl(uri, security);
        }

        However, this only works if the service account which I'm using is an administrator or backup operator on the remote machine (unless it's setting the owner to itself). I'd like to avoid giving this service account rights to too many machines, since that puts too much power in the hands of one account. Instead, I'd like to provide a username and password for the account which will be the owner of the file, and have the service impersonate this account when assigning ownership (e.g. in a similar way to how you could have credentials in a connection string for a database connection which didn't use trusted authentication). I'm looking for something like the code below, but have so far been unable to find an understandable example to work from.

        //call SetOwner(@"\\servername\share\filename.ext",@"domain\username");
        public static void SetOwner(string uri, string account)
        {
        StartImpersonating(account);
        System.Security.AccessControl.FileSecurity security = File.GetAccessControl(uri);
        IdentityReference owner = new NTAccount(account);
        security.SetOwner(owner);
        File.SetAccessControl(uri, security);
        StopImpersonating();
        }
        static void StartImpersonating(string account, string password)
        {
        System.Security.Principal.WindowsIdentity.Impersonate(account, password);
        }
        static void StartImpersonating(string account)
        {
        string password = GetPasswordFromSecureStore(account);
        StartImpersonating(account, password);
        }
        static void StartImpersonating(string domain, string username)
        {
        StartImpersonating(string.Format("{0}\\{1}",domain,username));
        }
        static void StopImpersonating()
        {
        StartImpersonating(System.Environment.UserDomainName,System.Environment.UserName);
        }

        NB: the above code is just for illustrative purposes to show the sort of thing I'm looking for; I've no idea whether what's there is even close to w

        M Offline
        M Offline
        Manfred Rudolf Bihy
        wrote on last edited by
        #3

        Hi JB, I used this in a small test I composed on impersonation:

            static void TestProcessLogs(string path)
            {
                AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
                IntPtr token;
                #region User / Password
                String user = "xxxxxx";
                String domain = "xxxxx";
                String pass = "xxxxxxx";
                #endregion
                if (LogonUser(user, domain, pass, 9, 0, out token))
                {
                    WindowsIdentity fromIdentity = new WindowsIdentity(token);
                    WindowsImpersonationContext context = fromIdentity.Impersonate();
        
                    ProcessLog(@"\\\\xxxxxxx.xxxxxxx.xxxxxx\\f$\\Connector\\LNWorkerDir\\705-SORL9002-PGBU-WEC-US-productn-octtic\\peqdLN02\\all.log");
                    //ProcessLog(path);
        
                    context.Undo();
                }
            }
        

        and here comes the definition of LogonUser. Place this within a class definition:

           \[DllImport("advapi32.dll", SetLastError = true)\]
            public static extern bool LogonUser(string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);
        

        Best regards Manfred

        J 1 Reply Last reply
        0
        • M Manfred Rudolf Bihy

          Hi JB, I used this in a small test I composed on impersonation:

              static void TestProcessLogs(string path)
              {
                  AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
                  IntPtr token;
                  #region User / Password
                  String user = "xxxxxx";
                  String domain = "xxxxx";
                  String pass = "xxxxxxx";
                  #endregion
                  if (LogonUser(user, domain, pass, 9, 0, out token))
                  {
                      WindowsIdentity fromIdentity = new WindowsIdentity(token);
                      WindowsImpersonationContext context = fromIdentity.Impersonate();
          
                      ProcessLog(@"\\\\xxxxxxx.xxxxxxx.xxxxxx\\f$\\Connector\\LNWorkerDir\\705-SORL9002-PGBU-WEC-US-productn-octtic\\peqdLN02\\all.log");
                      //ProcessLog(path);
          
                      context.Undo();
                  }
              }
          

          and here comes the definition of LogonUser. Place this within a class definition:

             \[DllImport("advapi32.dll", SetLastError = true)\]
              public static extern bool LogonUser(string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);
          

          Best regards Manfred

          J Offline
          J Offline
          JohnLBevan
          wrote on last edited by
          #4

          That's perfect. Thanks to both of you for the link & code sample; very much appreciated. I've put this code into a disposable object, so that you can easily swap contexts, using the using statement to control when you impersonate another account. Hopefully this will be of use to anyone following this thread in future. e.g.

          class Program
          {
              static void Main(string\[\] args)
              {
                  XmlDocument doc = new XmlDocument();
                  doc.LoadXml("<demo />");
                  doc.Save(@"\\\\server\\share\\demo1.xml"); //created with owner set to Administrators (assuming current account has access)
                  using (Impersonator impersonate = new Impersonator(@"domain\\user"))
                  {
                      doc.Save(@"\\\\server\\share\\xjbdemo2.xml"); //created with owner set to domain\\user (assuming domain\\user has access)
                  }
                  doc.Save(@"\\\\server\\share\\xjbdemo3.xml"); //created with owner set to Administrators (assuming current account has access)
          
                  Console.WriteLine("Done");
                  Console.ReadKey();
              }
          }
          
          /// &lt;summary&gt;
          /// Allows impersonation to be done easily via the code below
          /// using (Impersonator impersonate = new Impersonator("domain\\user", "pass")
          /// {
          ///     //do stuff as other user
          /// }
          /// &lt;/summary&gt;
          public class Impersonator: IDisposable
          {
          
              #region windows api reference
              #region enums
              //thanks to http://www.pinvoke.net/default.aspx/advapi32.logonuser
              public enum LogonType
              {
                  /// &lt;summary&gt;
                  /// This logon type is intended for users who will be interactively using the computer, such as a user being logged on  
                  /// by a terminal server, remote shell, or similar process.
                  /// This logon type has the additional expense of caching logon information for disconnected operations; 
                  /// therefore, it is inappropriate for some client/server applications,
                  /// such as a mail server.
                  /// &lt;/summary&gt;
                  LOGON32\_LOGON\_INTERACTIVE = 2,
          
                  /// &lt;summary&gt;
                  /// This logon type is intended for high performance servers to authenticate plaintext passwords.
          
                  /// The LogonUser function does not cache credentials for this logon type.
                  /// &lt;/summary&gt;
                  LOGON32\_LOGON\_NETWORK = 3,
          
          M 1 Reply Last reply
          0
          • J JohnLBevan

            That's perfect. Thanks to both of you for the link & code sample; very much appreciated. I've put this code into a disposable object, so that you can easily swap contexts, using the using statement to control when you impersonate another account. Hopefully this will be of use to anyone following this thread in future. e.g.

            class Program
            {
                static void Main(string\[\] args)
                {
                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml("<demo />");
                    doc.Save(@"\\\\server\\share\\demo1.xml"); //created with owner set to Administrators (assuming current account has access)
                    using (Impersonator impersonate = new Impersonator(@"domain\\user"))
                    {
                        doc.Save(@"\\\\server\\share\\xjbdemo2.xml"); //created with owner set to domain\\user (assuming domain\\user has access)
                    }
                    doc.Save(@"\\\\server\\share\\xjbdemo3.xml"); //created with owner set to Administrators (assuming current account has access)
            
                    Console.WriteLine("Done");
                    Console.ReadKey();
                }
            }
            
            /// &lt;summary&gt;
            /// Allows impersonation to be done easily via the code below
            /// using (Impersonator impersonate = new Impersonator("domain\\user", "pass")
            /// {
            ///     //do stuff as other user
            /// }
            /// &lt;/summary&gt;
            public class Impersonator: IDisposable
            {
            
                #region windows api reference
                #region enums
                //thanks to http://www.pinvoke.net/default.aspx/advapi32.logonuser
                public enum LogonType
                {
                    /// &lt;summary&gt;
                    /// This logon type is intended for users who will be interactively using the computer, such as a user being logged on  
                    /// by a terminal server, remote shell, or similar process.
                    /// This logon type has the additional expense of caching logon information for disconnected operations; 
                    /// therefore, it is inappropriate for some client/server applications,
                    /// such as a mail server.
                    /// &lt;/summary&gt;
                    LOGON32\_LOGON\_INTERACTIVE = 2,
            
                    /// &lt;summary&gt;
                    /// This logon type is intended for high performance servers to authenticate plaintext passwords.
            
                    /// The LogonUser function does not cache credentials for this logon type.
                    /// &lt;/summary&gt;
                    LOGON32\_LOGON\_NETWORK = 3,
            
            M Offline
            M Offline
            Manfred Rudolf Bihy
            wrote on last edited by
            #5

            Hi JB, thanks for sharing your class with us. I have some issues with your design though: 1. In the constructor I would not call Impersonate(...) straight away. There are two reasons for this: a.) Code in a constructor that will likely cause an exception is a real pain in the a**e. b.) Let the user of your library decide when Impersonation starts and ends. Store user account and domain in instance variables. Password should not be stored in the class (as you have already done) but could be retrieved via GetPassword() (see 2.). I would make an additional overload Impersonate() a public function and add another function like Revert() that will call context.Undo() and set context = null. bool IsImpersonating() would be nifty (context != null) too. 2. Move the function GetPassword to a separate class that implements an interface say IStringPasswordProvider. Have a property that allows the user of your library to inject an instance of his or her own implementation of IPasswordProvider.

            public interface IStringPasswordProvider
            {
            String GetPassword(String account);
            String GetPassword(String account, String domain);
            }

            public class DefaultPasswordProvider : IStringPasswordProvider
            {
            string GetPassword(string account)
            {
            string[] accountSplit = SplitAccount(account);
            return GetPassword(accountSplit[0], accountSplit[1]);
            }
            string GetPassword(string domain, string user)
            {
            string pass = string.Empty;
            pass = "todo"; //todo:add code here to return the password for the given user from the secure store.
            return pass;
            }
            }

            A password provider might read passwords from a DB or may be the app.config (web.config) file. Please let me know what you think of these changes. Best Regards Manfred

            1 Reply Last reply
            0
            Reply
            • Reply as topic
            Log in to reply
            • Oldest to Newest
            • Newest to Oldest
            • Most Votes


            • Login

            • Don't have an account? Register

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • World
            • Users
            • Groups