C # WebClient NTLM authentication starting for each request

Consider a simple C # NET Framework 4.0 application that:

  • uses webclient
  • Authenticated using NTLM (tested on IIS 6.0 and IIS 7.5)
  • extract string from URL several times using DownloadString ()

Here's a sample that works great:

using System; using System.Net; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string URL_status = "http://localhost/status"; CredentialCache myCache = new CredentialCache(); myCache.Add(new Uri(URL_status), "NTLM", new NetworkCredential("username", "password", "domain")); WebClient WebClient = new WebClient(); WebClient.Credentials = myCache; for (int i = 1; i <= 5; i++) { string Result = WebClient.DownloadString(new Uri(URL_status)); Console.WriteLine("Try " + i.ToString() + ": " + Result); } Console.Write("Done"); Console.ReadKey(); } } } 

Problem:

When I enable tracing, I see that NTLM authentication is not saved.

Each time Webclient.DownloadString is called, NTLM authentication is started (the server returns the WWW-Authenticate: NTLM header and the entire authentication / authorization process is repeated, there is no "Connection: close" header).

Shouldn't NTLM authenticate the connection, not the request?

Is there a way to force WebClient to reuse an existing connection in order to avoid re-authenticating each request?

+5
source share
2 answers

After 10 days of trying everything that I could think of and learn a lot in the process, I finally decided to fix this problem.

The trick is to enable UnsafeAuthenticatedConnectionSharing by overriding HttpWebRequest and setting the property to true.

You can combine this property with ConnectionGroupName to avoid potential use of the connection by unauthenticated applications.

Here is an example from a question that works as expected. It opens one completed NTLM connection and reuses it:

 using System; using System.Net; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string URL_status = "http://localhost/status"; CredentialCache myCache = new CredentialCache(); myCache.Add(new Uri(URL_status), "NTLM", new NetworkCredential("username", "password", "domain")); MyWebClient WebClient = new MyWebClient(); WebClient.Credentials = myCache; for (int i = 1; i <= 5; i++) { string Result = WebClient.DownloadString(new Uri(URL_status)); Console.WriteLine("Try " + i.ToString() + ": " + Result); } Console.Write("Done"); Console.ReadKey(); } } public class MyWebClient : WebClient { protected override WebRequest GetWebRequest(Uri address) { WebRequest request = (WebRequest)base.GetWebRequest(address); if (request is HttpWebRequest) { var myWebRequest = request as HttpWebRequest; myWebRequest.UnsafeAuthenticatedConnectionSharing = true; myWebRequest.KeepAlive = true; } return request; } } } 

At this point, I would also like to thank @Falco Alexander for his help; although his suggestions didn’t work for me, he pointed me in the right direction to search and finally find the answer.

+3
source

check your IIS settings, for example, although this should be the default.

 <windowsAuthentication enabled="True" authPersistSingleRequest="False" UseKernelMode> </windowsAuthentication> 

Link: https://msdn.microsoft.com/en-us/library/aa347472.aspx

Have you checked your local IIS zone? This was also a client-side error in the past when working with WinInet. Check the default behavior for WebClient.


Edit:

After reproducing the error, I could find out if there is no WebLient NTLM preauthentication implementation that keeps you from a single 401 request:

 var WebClient = new PreAuthWebClient(); WebClient.Credentials = new NetworkCredential("user", "pass","domain"); //Do your GETs Public class PreAuthWebClient: WebClient { protected override WebRequest GetWebRequest (Uri address) { WebRequest request = (WebRequest) base.GetWebRequest (address); request.PreAuthenticate = true; return request; } } 
+1
source

Source: https://habr.com/ru/post/1257502/


All Articles