Sunday, September 9, 2012

C# accessing or copying files over a network that requires authentication




I was working on a project with the requirement that I copy files over a network connection that needed username and password  authentication. The big problem that I found was that the .NET framework did not natively expose the win32 API needed to do this, so I had to write my own wrapper using P/Invoke.

You can learn more about P/Invoke on MSDN or check out the pinvoke.net wiki for tons of great resources.

Here is the class
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Web;  
 using System.ComponentModel;  
 using System.Runtime.InteropServices;  
 using System.Security.Principal;  
 namespace MyAppName  
 {  
 Public class SoddingNetworkAuth : IDisposable  
   {  
         [DllImport("advapi32.dll", SetLastError=true)]  
 Private static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);  
     [DllImport("kernel32", SetLastError = true )]  
 Privatestaticexternbool CloseHandle(IntPtr hObject);  
 Private IntPtr userHandle = IntPtr.Zero;  
 Private WindowsImpersonationContext impersonationContext;  
 Public SoddingNetworkAuth(string user, string domain, string password)  
     {  
 if ( ! string.IsNullOrEmpty( user ) )  
         {  
 // Call LogonUser to get a token for the user  
 Bool loggedOn = LogonUser( user, domain, password,  
                 9 /*(int)LogonType.LOGON32_LOGON_NEW_CREDENTIALS*/,  
                 3 /*(int)LogonProvider.LOGON32_PROVIDER_WINNT50*/,  
 Out userHandle );  
 if ( !loggedOn )  
 throw new Win32Exception( Marshal.GetLastWin32Error() );  
 // Begin impersonating the user  
 impersonationContext = WindowsIdentity.Impersonate( userHandle );  
         }  
     }  
 Public void Dispose()  
     {  
 if ( userHandle != IntPtr.Zero )  
 CloseHandle(userHandle );  
 if ( impersonationContext != null )  
 impersonationContext.Undo();  
     }  
   }  
 }  

Then you consume the class as follows
 using (new SoddingNetworkAuth(@"UserName", @"ServerName", @"Password"))  
 {  
      //Do something  
 }  

It’s that easy!

Let me know if this class helped or even if I just got you pointed in the right direction to solve your own unique problem.

3 comments:

  1. Thanks for the help!

    Marcel - Brazil

    ReplyDelete
  2. Many thanks,
    the best solution I ever found!

    ReplyDelete
  3. Thanks that help me a lot!

    César-From México.

    ReplyDelete