[#7258][Web]: Support multiple proxy auth methods.
authorMartin Baulig <martin.baulig@xamarin.com>
Fri, 19 Oct 2012 01:56:16 +0000 (03:56 +0200)
committerMartin Baulig <martin.baulig@xamarin.com>
Fri, 19 Oct 2012 01:56:16 +0000 (03:56 +0200)
* AuthenticationManager.EnsureModules(): Swap the order of the
  modules, putting the strongest ones first.

* WebConnection.CreateTunnel(): Pass the proxy's address to
  AuthenticationManager to support CredentialsCache.  Only attempt
  one single authentication method.

I've done some extensive testing with different squid configurations
(digest only, ntlm only, digest and ntlm, ntlm and digest) and the
.NET runtime only attempts one single authentication method.

If you provide credentials like this:

var proxy = new WebProxy (proxyUrl, false);
proxy.Credentials = new NetworkCredential ("user", "pass", "domain");

then these must match the server's first authentication method.

You can also use a CredentialsCache like this:

var ntlm_cred = new NetworkCredential ("u1", "p1", "d1");
var digest_cred = new NetworkCredential ("u2", "u3", "d2");

var cc = new CredentialCache ();
cc.Add (proxy_uri, "NTLM", ntlm_cred);
cc.Add (proxy_uri, "Digest", digest_cred);

var proxy = new WebProxy (proxy_uri, false);
proxy.Credentials = cc;

mcs/class/System/System.Net/AuthenticationManager.cs
mcs/class/System/System.Net/WebConnection.cs

index 0c87dbef56f263716ce23dd55b99ad0c720d0c07..4ffe5f00efadcfe9db8ed212ca04176144c63412 100644 (file)
@@ -56,9 +56,9 @@ namespace System.Net
                                
                                modules = new ArrayList ();
 #if NET_2_1
-                               modules.Add (new BasicClient ());
-                               modules.Add (new DigestClient ());
                                modules.Add (new NtlmClient ());
+                               modules.Add (new DigestClient ());
+                               modules.Add (new BasicClient ());
 #elif CONFIGURATION_DEP
                                object cfg = ConfigurationManager.GetSection ("system.net/authenticationModules");
                                AuthenticationModulesSection s = cfg as AuthenticationModulesSection;
index 47e5a8ac9039a2882aa8b0d9fa6d056441f3c01a..a12509b53ec17be1072e4c40392e3d033e018cfc 100644 (file)
@@ -256,7 +256,8 @@ namespace System.Net
                        }
                }
 
-               bool CreateTunnel (HttpWebRequest request, Stream stream, out byte[] buffer)
+               bool CreateTunnel (HttpWebRequest request, Uri connectUri,
+                                  Stream stream, out byte[] buffer)
                {
                        StringBuilder sb = new StringBuilder ();
                        sb.Append ("CONNECT ");
@@ -287,18 +288,20 @@ namespace System.Net
 
                                if (connect_request == null) {
                                        // create a CONNECT request to use with Authenticate
-                                       connect_request = (HttpWebRequest)WebRequest.Create ("http://" + request.Address.Host + ":" + request.Address.Port + "/");
+                                       connect_request = (HttpWebRequest)WebRequest.Create (
+                                               connectUri.Scheme + "://" + connectUri.Host + ":" + connectUri.Port + "/");
                                        connect_request.Method = "CONNECT";
                                        connect_request.Credentials = creds;
                                }
 
                                for (int i = 0; i < challenge.Length; i++) {
                                        var auth = AuthenticationManager.Authenticate (challenge [i], connect_request, creds);
-                                       if (auth != null) {
-                                               ntlm = (auth.Module.AuthenticationType == "NTLM");
-                                               sb.Append ("\r\nProxy-Authorization: ");
-                                               sb.Append (auth.Message);
-                                       }
+                                       if (auth == null)
+                                               continue;
+                                       ntlm = (auth.Module.AuthenticationType == "NTLM");
+                                       sb.Append ("\r\nProxy-Authorization: ");
+                                       sb.Append (auth.Message);
+                                       break;
                                }
                        }
 
@@ -416,7 +419,7 @@ namespace System.Net
                                        if (!reused || nstream == null || nstream.GetType () != sslStream) {
                                                byte [] buffer = null;
                                                if (sPoint.UseConnect) {
-                                                       bool ok = CreateTunnel (request, serverStream, out buffer);
+                                                       bool ok = CreateTunnel (request, sPoint.Address, serverStream, out buffer);
                                                        if (!ok)
                                                                return false;
                                                }