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.

9 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
  4. YES!!!! Thank u very much! I was totally stuck whit this.

    ReplyDelete
  5. Niiiiiiiiiice ! Works really great :)

    ReplyDelete
  6. I still got this error "Additional information: Logon failure: unknown user name or bad password."
    the following is my code
    openFileDialog1.Multiselect = true;
    if (openFileDialog1.ShowDialog() == DialogResult.OK)
    {
    using (new SoddingNetworkAuth(@"administrator", @"user", @"pass"))
    {

    File.Copy(openFileDialog1.FileName, @"\\abc\user data\San\text.txt");
    MessageBox.Show("Copy Successfully");
    }
    }

    ReplyDelete
    Replies
    1. Have you tested the username and password in Windows Explorer?

      Delete
    2. Also check the parameters that you are passing to SoddingNetworkAuth, they must be the following items in the following order; User Name, Server Name, Password

      Delete
  7. This comment has been removed by a blog administrator.

    ReplyDelete