C# – HTTP 407 (Proxy Authentication Required)

authenticationchttphttpwebrequest

I have some basic questions on HTTP authentication

1) How does client know about Server's authentication type (Basic/Digest/NTLM) of HTTP ?
is this configurable at HTTP Server side?

My Answer: Server will be set with which authentication type it has to perform with the client.
So our client API(in C# HttpWebRequest API) will automatically take care of it.
Best use of Wireshrk with applying HTTP filter; you will get source and Destination IP at Internet Protocol layer. And src and dest port at Transmission control protocol and athentication type at http layer.

2) If i place squid linux proxy in between client and Server; is there any need from my client code should know about authentication type of proxy also? or authentication type is only related to the end HTTP server?

My Answer: If squid proxy is placed in between Client and Server; it wont use HTTP authentication. It may use a) DB: Uses a SQL database b) LDAP: Uses the Lightweight Directory Access Protocol. c) RADIUS: Uses a RADIUS server for login validation. and etc..
So we have to mention proxy authentication credentials in HTTP Headers.

3) Using WireShark found that there are three request from Browser to Server to fulfill single request.

a) Browser sends a request without any authentication credentials; So server responded with 401 along with relam and nonce.

WWW-Authenticate: Digest realm="realm", qop="auth", nonce="MTM1OTYyMzkyNDU4MzpiOWM0OWY0NmMzMzZlMThkMDJhMzRhYmU5NjgwNjkxYQ=="\r\n <BR>

b) The second time Browser sends request with credentials, relam, nonce, cnonce; but still server responded with 401;

WWW-Authenticate: Digest realm="realm", qop="auth", nonce="MTM1OTYyMzk0OTAyMTo3Njk3MDNhZTllZDQyYzQ5MGUxYzI5MWY2MGU5ZDg0Yw==", stale="true"\r\n

c) The third time Browser send the same request with same credentials, relam, nonce, cnonce. This time Server sends 200 ok.

My Question is in the second and third time Browser send the same request; why Server failed at second time and success at the third time. Is this because of my server implementation ? (I am having REST Java server with SPRING Security filter).

I have C# HTTP client;

where in the first time HttpWebRequest is sent without credentials though the System.Net.NetworkCredentials is set; so clinet got 407 with relam, and nonce.
The second time HttpWebRequest is scuccess. There is no third request from this client like browser.

Why this difference between the browser and C# client?

My Answer: I am still don't know what is happening here: Q3.

4) Now the real issue i am facing is When SQUID LINUX PROXY came in between our Client and HTTP Server, Browser did the same three request authentication and succeeded. However C# HttpWebRequest is failed (401) at the second request and reached the cache(exception){} block and not tried for the third time.

Could you please anyone clarify me how to resolve this issue in C# client when PROXY SERVER is in between?

Below code is doing the GET Request.

  HttpWebRequest request = WebRequest.Create("url") as HttpWebRequest;
  request.Credentials = new NetworkCredential(loginUserName, password);
  WebResponse response = request.GetResponse(); 

Note that our request to proxy is send via TCP protocol not with HTTP protocol. Then from PROXY to SERVER is communicated with HTTP protocol.
But HTTP request from Proxy has the info about our client ip in the HTTP header X-Forwarded-For.

Below are the possible solutions

These solutions only required if your proxy requires any authentication else ignore it.

Solution 1: working for me

request.Proxy.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;

Solution 2:

  IWebProxy proxy = WebRequest.GetSystemWebProxy();
  proxy.Credentials = new NetworkCredential(UserName, UserPassword, UserDomain);
  request.Proxy = proxy;

Solution 3 given by Martin:

  var proxy = new WebProxy ("http://localhost:3128/");
  proxy.Credentials = new NetworkCredential (UserName, UserPassword, UserDomain);
  request.Proxy = proxy;

Learn more about proxy authentication at
http://wiki.squid-cache.org/Features/Authentication

Best Answer

It's a challenge/response protocol. Usually, the client makes an initial request without any authentication headers (you may set request.PreAuthenticate = true to send the credentials with the first request).

Then, the server responds with a list of authentication methods that it supports.

If the user did not explicitly specify an authentication method using CredentialsCache, the runtime will try them all, from strongest to weakest. Some protocols (NTLM, for instance) require multiple requests from client to server. In theory, Digest should work with a single one, no idea why it's sending the request twice.

Regarding your proxy question, there are two different kinds of authentication:

  1. The target web server's authentication, a proxy simply passes this though and you don't need any special code in your client.
  2. In addition to that, the proxy itself may also require authentication - which may be different from the one of target web server.

You specify these using

var proxy = new WebProxy ("http://localhost:3128/");
proxy.Credentials = new NetworkCredential ("username", "password");

and then

WebRequest.DefaultWebProxy = proxy;

or

request.Proxy = proxy;

Don't set any credentials on the WebProxy if your proxy server doesn't use any authentication.

If you can't get authentication working while using a proxy server, look at the actual requests that are being sent between the three parties (web server, proxy, client) with Wireshark.