Am Samstag, 22. November 2014, 16:24:18 schrieb Darshit Shah:
> Another reason why I never got around to implementing this feature is that
> it is required by almost no one. The issue at hand is that when a Server
> responds with two possible authentication methods, the client is expected
> to choose the strongest one it knows. Instead Wget chooses the first one it
> knows. This violates the RFC and hence I marked it up as a bug. I'll
> probably add all this information into the test file in a while and push
> it.

Hi Darshit,

I just made up a patch to

1. Parse multiple challenges from WWW-Authenticate
2. Select the strongest auth scheme

Please have a look at it.

Tim
From a4c9939376cd8327e55111af3b190dd2e91f5746 Mon Sep 17 00:00:00 2001
From: Tim Ruehsen <tim.rueh...@gmx.de>
Date: Sat, 22 Nov 2014 22:00:28 +0100
Subject: [PATCH] Select most secure auth challenge

---
 src/http.c                         | 67 ++++++++++++++++++++++++++++++++------
 testenv/server/http/http_server.py |  2 +-
 2 files changed, 58 insertions(+), 11 deletions(-)

diff --git a/src/http.c b/src/http.c
index 87ceffd..832707d 100644
--- a/src/http.c
+++ b/src/http.c
@@ -2380,26 +2380,64 @@ read_header:
              the value "negotiate", and other(s) with data.  Loop over
              all the occurrences and pick the one we recognize.  */
           int wapos;
+          char *buf;
+          const char *www_authenticate = NULL;
           const char *wabeg, *waend;
-          char *www_authenticate = NULL;
-          for (wapos = 0;
-               (wapos = resp_header_locate (resp, "WWW-Authenticate", wapos,
+          const char *digest = NULL, *basic = NULL, *ntlm = NULL;
+          for (wapos = 0; !ntlm
+               && (wapos = resp_header_locate (resp, "WWW-Authenticate", wapos,
                                             &wabeg, &waend)) != -1;
                ++wapos)
-            if (known_authentication_scheme_p (wabeg, waend))
-              {
-                BOUNDED_TO_ALLOCA (wabeg, waend, www_authenticate);
-                break;
-              }
+            {
+              param_token name, value;
+
+              BOUNDED_TO_ALLOCA (wabeg, waend, buf);
+              www_authenticate = buf;
+
+              for (;!ntlm;)
+                {
+                  /* extract the auth-scheme */
+                  while (c_isspace (*www_authenticate)) www_authenticate++;
+                  name.e = name.b = www_authenticate;
+                  while (*name.e && !c_isspace (*name.e)) name.e++;
+
+                  if (name.b == name.e)
+                    break;
+
+                  DEBUGP (("Auth scheme found '%.*s'\n", (int) (name.e - name.b), name.b));
+
+                  if (known_authentication_scheme_p (name.b, name.e))
+                    {
+                      if (BEGINS_WITH (name.b, "NTLM"))
+                        {
+                          ntlm = name.b;
+                          break; // most secure
+                        }
+                      else if (!digest && BEGINS_WITH (name.b, "Digest"))
+                        digest = name.b;
+                      else if (!basic && BEGINS_WITH (name.b, "Basic"))
+                        basic = name.b;
+                    }
+
+                  /* now advance over the auth-params */
+                  www_authenticate = name.e;
+                  DEBUGP (("Auth param list '%s'\n", www_authenticate));
+                  while (extract_param (&www_authenticate, &name, &value, ',', NULL) && name.b && value.b)
+                    {
+                      DEBUGP (("Auth param %.*s=%.*s\n",
+                               (int) (name.e - name.b), name.b, (int) (value.e - value.b), value.b));
+                    }
+                }
+            }

-          if (!www_authenticate)
+          if (!basic && !digest && !ntlm)
             {
               /* If the authentication header is missing or
                  unrecognized, there's no sense in retrying.  */
               logputs (LOG_NOTQUIET, _("Unknown authentication scheme.\n"));
             }
           else if (!basic_auth_finished
-                   || !BEGINS_WITH (www_authenticate, "Basic"))
+                   || !basic)
             {
               char *pth = url_full_path (u);
               const char *value;
@@ -2407,6 +2445,15 @@ read_header:
               auth_stat = xmalloc (sizeof (uerr_t));
               *auth_stat = RETROK;

+              if (ntlm)
+                www_authenticate = ntlm;
+              else if (digest)
+                www_authenticate = digest;
+              else
+                www_authenticate = basic;
+
+              logprintf (LOG_NOTQUIET, _("Authentication selected: %s\n"), www_authenticate);
+
               value =  create_authorization_line (www_authenticate,
                                                   user, passwd,
                                                   request_method (req),
diff --git a/testenv/server/http/http_server.py b/testenv/server/http/http_server.py
index 52c4913..9128b3e 100644
--- a/testenv/server/http/http_server.py
+++ b/testenv/server/http/http_server.py
@@ -207,8 +207,8 @@ class _Handler (BaseHTTPRequestHandler):
     def send_challenge (self, auth_type):
         auth_type = auth_type.lower()
         if auth_type == "both":
-            self.send_challenge ("digest")
             self.send_challenge ("basic")
+            self.send_challenge ("digest")
             return
         if auth_type == "basic":
             challenge_str = 'BasIc realm="Wget-Test"'
--
2.1.3

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to