How to pass Webcredentials from active user to Windows Service?

◇◆丶佛笑我妖孽 提交于 2019-12-23 04:57:09

问题


I need to get the default credentials from the current logged in user and pass them to my Windows service to check the internet connectivity and upload files to Dropbox. I don't want the user to confirm his/her credentials every time. So how is it possible to get the currently active user's proxy settings + username + password?

This is my Code to retrieve the current User

private static string UserName()
    {
        string userName = null;
        ManagementScope ms = new ManagementScope();
        ObjectQuery qry = new ObjectQuery("Select * from Win32_ComputerSystem");
        ManagementObjectSearcher search = new ManagementObjectSearcher(ms, qry);
        ManagementObjectCollection result = search.Get();
        foreach (ManagementObject rec in result)
            userName = rec["UserName"] as string;
        string[] buffer = userName.Split('\\');
        return buffer[1];
    }

and this Code is in use for getting the WindowsIdentity:

private static WindowsIdentity GetWindowsIdentity()
    {
        string userName = UserName();
        PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
        using (UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, userName) ??
          UserPrincipal.FindByIdentity(UserPrincipal.Current.Context, IdentityType.UserPrincipalName, userName))
        {
            return user == null
              ? null
              : new WindowsIdentity(user.UserPrincipalName);
        }
    }

This is what I want to do via service:

    System.Diagnostics.Debugger.Launch(); //launch debugger when service runs

            WindowsImpersonationContext impersonationContext;
            impersonationContext = GetWindowsIdentity().Impersonate();
 //try to use the currently logged in user's credentials
            WebRequest.DefaultWebProxy.Credentials = CredentialCache.DefaultCredentials;
            try
            {
                WebClient wClient = new WebClient();
                string xx = wClient.DownloadString(@"https://dropbox.com");
                if (xx == "") //just download the sourcecode to chek if this page is available
                    return false;
            }
            catch (Exception ex)
            {
                using (StreamWriter sw = new StreamWriter(@"C:\Users\Testuser\Desktop\DownloadError.txt", true))
                {
                    sw.WriteLine(ex.ToString());
                }
                return false;
            }
            impersonationContext.Undo(); 

The errorLog always shows, that the service was unable to connect. When i run this from an console or WinForms applications, it works without any problems.

Errorlog:

    System.Net.WebException: Unable to connect to the remote server  ---> System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it 172.217.17.238:80
   at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Exception& exception)
   --- End of inner exception stack trace ---
   at System.Net.WebClient.DownloadDataInternal(Uri address, WebRequest& request)
   at System.Net.WebClient.DownloadString(Uri address)
   at System.Net.WebClient.DownloadString(String address)
   at BeeShotService.Sender.TrySend(String s) in C:\Users\Testuser\Documents\Visual Studio 2017\Projects\Project_BackupUploder\UploaderService\Sender.cs:Zeile 70.

回答1:


I've managed to solve the problem for simple webRequests with an additional Class:

class GetProxySettings
{
    private const int INTERNET_OPTION_PROXY = 38;

    [DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool InternetQueryOption(IntPtr hInternet, uint dwOption, IntPtr lpBuffer, ref int lpdwBufferLength);

    /// <summary>
    /// Access types supported by InternetOpen function.
    /// </summary>        
   private enum InternetOpenType
    {
        INTERNET_OPEN_TYPE_PRECONFIG = 0,
        INTERNET_OPEN_TYPE_DIRECT = 1,
        INTERNET_OPEN_TYPE_PROXY = 3,
    }

    /// <summary>
    /// Contains information that is supplied with the INTERNET_OPTION_PROXY value
    /// to get or set proxy information on a handle obtained from a call to 
    /// the InternetOpen function.
    /// </summary>
    private struct INTERNET_PROXY_INFO
    {
        public InternetOpenType DwAccessType
        {
            get; set;
        }
        public string LpszProxy
        {
            get; set;
        }
        public string LpszProxyBypass
        {
            get; set;
        }
    }
    internal string[] GetV(WindowsIdentity windowsIdentity)
    {
        string[] settings = new string[] { "", "" };
        using (windowsIdentity.Impersonate())
        {

            int bufferLength = 0;
            IntPtr buffer = IntPtr.Zero;

            InternetQueryOption(IntPtr.Zero, INTERNET_OPTION_PROXY, IntPtr.Zero,
                                ref bufferLength);
            try
            {
                buffer = Marshal.AllocHGlobal(bufferLength);
                if (InternetQueryOption(IntPtr.Zero, INTERNET_OPTION_PROXY, buffer,
                                        ref bufferLength))
                {
                    INTERNET_PROXY_INFO proxyInfo = (INTERNET_PROXY_INFO)
                    // Converting structure to IntPtr.
                    Marshal.PtrToStructure(buffer, typeof(INTERNET_PROXY_INFO));
                    // Getting the proxy details.
                    settings[0] = proxyInfo.LpszProxy.Split(':')[0];
                    settings[1] = proxyInfo.LpszProxy.Split(':')[1];
                }
            }
            catch { }
        }
        return settings;
    }
}

You need to add the WindowsIdentity of the currently logged-on user and will return a string[] with [0] = proxystring & [1] = proxy port. The following works well as a service:

            WebClient wClient = new WebClient();
            wClient.Proxy = new WebProxy( GetProxySettings.GetV(GetWindowsIdentity())[0],GetProxySettings.GetV(GetWindowsIdentity())[1]);
            string xx = wClient.DownloadString(@"https://www.dropbox.com");


来源:https://stackoverflow.com/questions/46112248/how-to-pass-webcredentials-from-active-user-to-windows-service

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!