How do you pass user credentials from one process

2019-06-08 17:08发布

问题:

I have a Windows Service (written in .NET 1.1) running under a specific user account and instances of the service running on several servers.

I would like to pass user credentials (username, password, domain) to the service from a WinForms application and have the service read/write files in the server's local file system impersonating the passed-in credentials.

Is it better to pass the username, domain, and password and have the Windows Service perform the Impersonation? I don't see how to serialize a WindowsIdentity and pass one as a parameter to have the service then perform the Impersonate() and Undo() around the I/O.

As a container object, System.Net.NetworkCredential is not marked serializable so passing the three individual parameters seems logical. I'm essentially using the Impersonation routine found in KB306158.

回答1:

The short answer is: don't pass the credentials at all. That approach is insecure.

Instead you should be looking to leverage the secure mechanism provided by the OS for achieving what you are wanting to do. It is called SSPI (Security Support Provider Interface). Using this the processes exchange a series of tokens generated by an OS-level security provider, to set up a security context without the need for passing credentials in user mode code.

If you were able to upgrade your service to use .NET 3.5, you could use WCF to do the IPC, and, appropriately configured, it would take care of the details of the SSPI handshake, and enable impersonation straightforwardly.

If you are stuck with .NET 1.1, then take a look at the articles and sample code provided here and here, which show how to invoke SSPI from managed code and use it to secure a .NET remoting channel.



回答2:

I dont know how directly this correlates to your needs but this is a snippet of the impersonation code I used in an application that accesses the registry and file system of remote machines given valid credentials. The LogonUser method takes username password and servername as args which you could pass via your winform app.

edit You will have to set up a form of inter-process communication between your winform app and the services running on the separate computers. My apologies I thought this was a question about how to impersonate not how to send information to your process. As far as methods for IPC go there are quite a few options. Take a look at this site, it will provide far more information than I can. Your best bet is going to be using named pipes.

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

IntPtr admin_token = IntPtr.Zero;
WindowsIdentity wid = WindowsIdentity.GetCurrent();
WindowsIdentity wid_admin;  
WindowsImpersonationContext wic;

if (LogonUser(user, servername, pass, 9, 0, ref admin_token))
{
    wid_admin = new WindowsIdentity(admin_token);
    wic = wid_admin.Impersonate();
    //do stuff with new creds here
}


回答3:

I don't think you can pass the Network Credential object directly to another process, it's based on an underlying windows api and I'm guessing there would be all kinds of bad juju involved in letting processes pass around their auth tokens.

I would take the approach you mentioned, if possible, and pass the log on credentials (user/pass) to the service and let it use those for the impersonation.