]> granicus.if.org Git - curl/commitdiff
Curl_http_input_auth: handle multiple auths in WWW-Authenticate
authorDaniel Stenberg <daniel@haxx.se>
Thu, 20 Oct 2011 11:05:09 +0000 (13:05 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 20 Oct 2011 11:12:02 +0000 (13:12 +0200)
The fix is pretty much the one Nick Zitzmann provided, just edited to do
the right indent levels and with test case 1204 added to verify the fix.

Bug: http://curl.haxx.se/mail/lib-2011-10/0190.html
Reported by: Nick Zitzmann

lib/http.c
tests/data/Makefile.am
tests/data/test1204 [new file with mode: 0644]

index 5b30f8aa097aa79cce4821f6c45b53da0e9c221a..e41cb7af3c6ed4c6798ef3e337d1baa1eea1ce34 100644 (file)
@@ -731,95 +731,73 @@ CURLcode Curl_http_input_auth(struct connectdata *conn,
    *
    */
 
+  while(*start) {
 #ifdef USE_HTTP_NEGOTIATE
-  if(checkprefix("GSS-Negotiate", start) ||
-      checkprefix("Negotiate", start)) {
-    int neg;
-    *availp |= CURLAUTH_GSSNEGOTIATE;
-    authp->avail |= CURLAUTH_GSSNEGOTIATE;
-
-    if(data->state.negotiate.state == GSS_AUTHSENT) {
-      /* if we sent GSS authentication in the outgoing request and we get this
-         back, we're in trouble */
-      infof(data, "Authentication problem. Ignoring this.\n");
-      data->state.authproblem = TRUE;
-    }
-    else {
-      neg = Curl_input_negotiate(conn, (httpcode == 407)?TRUE:FALSE, start);
-      if(neg == 0) {
-        DEBUGASSERT(!data->req.newurl);
-        data->req.newurl = strdup(data->change.url);
-        if(!data->req.newurl)
-          return CURLE_OUT_OF_MEMORY;
-        data->state.authproblem = FALSE;
-        /* we received GSS auth info and we dealt with it fine */
-        data->state.negotiate.state = GSS_AUTHRECV;
-      }
-      else {
+    if(checkprefix("GSS-Negotiate", start) ||
+       checkprefix("Negotiate", start)) {
+      int neg;
+      *availp |= CURLAUTH_GSSNEGOTIATE;
+      authp->avail |= CURLAUTH_GSSNEGOTIATE;
+
+      if(data->state.negotiate.state == GSS_AUTHSENT) {
+        /* if we sent GSS authentication in the outgoing request and we get
+           this back, we're in trouble */
+        infof(data, "Authentication problem. Ignoring this.\n");
         data->state.authproblem = TRUE;
       }
-    }
-  }
-  else
-#endif
-#ifdef USE_NTLM
-    /* NTLM support requires the SSL crypto libs */
-    if(checkprefix("NTLM", start)) {
-      *availp |= CURLAUTH_NTLM;
-      authp->avail |= CURLAUTH_NTLM;
-      if(authp->picked == CURLAUTH_NTLM ||
-         authp->picked == CURLAUTH_NTLM_WB) {
-        /* NTLM authentication is picked and activated */
-        CURLcode ntlm =
-          Curl_input_ntlm(conn, (httpcode == 407)?TRUE:FALSE, start);
-        if(CURLE_OK == ntlm) {
+      else {
+        neg = Curl_input_negotiate(conn, (httpcode == 407)?TRUE:FALSE, start);
+        if(neg == 0) {
+          DEBUGASSERT(!data->req.newurl);
+          data->req.newurl = strdup(data->change.url);
+          if(!data->req.newurl)
+            return CURLE_OUT_OF_MEMORY;
           data->state.authproblem = FALSE;
-#ifdef NTLM_WB_ENABLED
-          if(authp->picked == CURLAUTH_NTLM_WB) {
-            *availp &= ~CURLAUTH_NTLM;
-            authp->avail &= ~CURLAUTH_NTLM;
-            *availp |= CURLAUTH_NTLM_WB;
-            authp->avail |= CURLAUTH_NTLM_WB;
-
-            /* Get the challenge-message which will be passed to
-             * ntlm_auth for generating the type 3 message later */
-            while(*start && ISSPACE(*start))
-              start++;
-            if(checkprefix("NTLM", start)) {
-              start += strlen("NTLM");
-              while(*start && ISSPACE(*start))
-                start++;
-              if(*start)
-                if((conn->challenge_header = strdup(start)) == NULL)
-                  return CURLE_OUT_OF_MEMORY;
-            }
-          }
-#endif
+          /* we received GSS auth info and we dealt with it fine */
+          data->state.negotiate.state = GSS_AUTHRECV;
         }
         else {
-          infof(data, "Authentication problem. Ignoring this.\n");
           data->state.authproblem = TRUE;
         }
       }
     }
     else
 #endif
-#ifndef CURL_DISABLE_CRYPTO_AUTH
-      if(checkprefix("Digest", start)) {
-        if((authp->avail & CURLAUTH_DIGEST) != 0) {
-          infof(data, "Ignoring duplicate digest auth header.\n");
-        }
-        else {
-          CURLdigest dig;
-          *availp |= CURLAUTH_DIGEST;
-          authp->avail |= CURLAUTH_DIGEST;
-
-          /* We call this function on input Digest headers even if Digest
-           * authentication isn't activated yet, as we need to store the
-           * incoming data from this header in case we are gonna use Digest. */
-          dig = Curl_input_digest(conn, (httpcode == 407)?TRUE:FALSE, start);
-
-          if(CURLDIGEST_FINE != dig) {
+#ifdef USE_NTLM
+      /* NTLM support requires the SSL crypto libs */
+      if(checkprefix("NTLM", start)) {
+        *availp |= CURLAUTH_NTLM;
+        authp->avail |= CURLAUTH_NTLM;
+        if(authp->picked == CURLAUTH_NTLM ||
+           authp->picked == CURLAUTH_NTLM_WB) {
+          /* NTLM authentication is picked and activated */
+          CURLcode ntlm =
+            Curl_input_ntlm(conn, (httpcode == 407)?TRUE:FALSE, start);
+          if(CURLE_OK == ntlm) {
+            data->state.authproblem = FALSE;
+#ifdef NTLM_WB_ENABLED
+            if(authp->picked == CURLAUTH_NTLM_WB) {
+              *availp &= ~CURLAUTH_NTLM;
+              authp->avail &= ~CURLAUTH_NTLM;
+              *availp |= CURLAUTH_NTLM_WB;
+              authp->avail |= CURLAUTH_NTLM_WB;
+
+              /* Get the challenge-message which will be passed to
+               * ntlm_auth for generating the type 3 message later */
+              while(*start && ISSPACE(*start))
+                start++;
+              if(checkprefix("NTLM", start)) {
+                start += strlen("NTLM");
+                while(*start && ISSPACE(*start))
+                  start++;
+                if(*start)
+                  if((conn->challenge_header = strdup(start)) == NULL)
+                    return CURLE_OUT_OF_MEMORY;
+              }
+            }
+#endif
+          }
+          else {
             infof(data, "Authentication problem. Ignoring this.\n");
             data->state.authproblem = TRUE;
           }
@@ -827,19 +805,51 @@ CURLcode Curl_http_input_auth(struct connectdata *conn,
       }
       else
 #endif
-      if(checkprefix("Basic", start)) {
-        *availp |= CURLAUTH_BASIC;
-        authp->avail |= CURLAUTH_BASIC;
-        if(authp->picked == CURLAUTH_BASIC) {
-          /* We asked for Basic authentication but got a 40X back
-             anyway, which basically means our name+password isn't
-             valid. */
-          authp->avail = CURLAUTH_NONE;
-          infof(data, "Authentication problem. Ignoring this.\n");
-          data->state.authproblem = TRUE;
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+        if(checkprefix("Digest", start)) {
+          if((authp->avail & CURLAUTH_DIGEST) != 0) {
+            infof(data, "Ignoring duplicate digest auth header.\n");
+          }
+          else {
+            CURLdigest dig;
+            *availp |= CURLAUTH_DIGEST;
+            authp->avail |= CURLAUTH_DIGEST;
+
+            /* We call this function on input Digest headers even if Digest
+             * authentication isn't activated yet, as we need to store the
+             * incoming data from this header in case we are gonna use
+             * Digest. */
+            dig = Curl_input_digest(conn, (httpcode == 407)?TRUE:FALSE, start);
+
+            if(CURLDIGEST_FINE != dig) {
+              infof(data, "Authentication problem. Ignoring this.\n");
+              data->state.authproblem = TRUE;
+            }
+          }
         }
-      }
+        else
+#endif
+          if(checkprefix("Basic", start)) {
+            *availp |= CURLAUTH_BASIC;
+            authp->avail |= CURLAUTH_BASIC;
+            if(authp->picked == CURLAUTH_BASIC) {
+              /* We asked for Basic authentication but got a 40X back
+                 anyway, which basically means our name+password isn't
+                 valid. */
+              authp->avail = CURLAUTH_NONE;
+              infof(data, "Authentication problem. Ignoring this.\n");
+              data->state.authproblem = TRUE;
+            }
+          }
 
+    /* there may be multiple methods on one line, so keep reading */
+    while(*start && *start != ',') /* read up to the next comma */
+      start++;
+    if(*start == ',') /* if we're on a comma, skip it */
+      start++;
+    while(*start && ISSPACE(*start))
+      start++;
+  }
   return CURLE_OK;
 }
 
index 2030e0bcadba44e16f894232aa7d4b9623b246f6..8471736ca1107642c579954eb43a82ef5f596e2b 100644 (file)
@@ -73,8 +73,9 @@ test1094 test1095 test1096 test1097 test1098 test1099 test1100 test1101       \
 test1102 test1103 test1104 test1105 test1106 test1107 test1108 test1109        \
 test1110 test1111 test1112 test1113 test1114 test1115 test1116 test1117        \
 test1118 test1119 test1120 test1121 test1122 test1123 test1124 test1125        \
-test1126 test1127 test1128 test1129 test1130 test1131 test1200 test1201        \
-test1202 test1203 test1300 test1301 test1302 test1303 test1304 test1305        \
+test1126 test1127 test1128 test1129 test1130 test1131 \
+test1200 test1201 test1202 test1203 test1204 \
+test1300 test1301 test1302 test1303 test1304 test1305  \
 test1306 test1307 test1308 test1309 test1310 test1311 test1312 test1313 \
 test1314 \
 test2000 test2001 test2002 test2003 test2004
diff --git a/tests/data/test1204 b/tests/data/test1204
new file mode 100644 (file)
index 0000000..02502fb
--- /dev/null
@@ -0,0 +1,79 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+HTTP Basic auth
+--anyauth
+</keywords>
+</info>
+# Server-side
+<reply>
+<data>
+HTTP/1.1 401 Authorization Required swsbounce\r
+Server: Apache/1.3.27 (Darwin) PHP/4.1.2\r
+WWW-Authenticate: X-MobileMe-AuthToken realm="Newcastle", Basic realm="fun fun  fun"\r
+Content-Type: text/html; charset=iso-8859-1\r
+Content-Length: 26\r
+\r
+This is not the real page
+</data>
+
+# This is supposed to be returned when the server gets the second request
+<data1>
+HTTP/1.1 200 OK\r
+Server: Apache/1.3.27 (Darwin) PHP/4.1.2\r
+Content-Type: text/html; charset=iso-8859-1\r
+Content-Length: 23\r
+\r
+This IS the real page!
+</data1>
+
+<datacheck>
+HTTP/1.1 401 Authorization Required swsbounce\r
+Server: Apache/1.3.27 (Darwin) PHP/4.1.2\r
+WWW-Authenticate: X-MobileMe-AuthToken realm="Newcastle", Basic realm="fun fun  fun"\r
+Content-Type: text/html; charset=iso-8859-1\r
+Content-Length: 26\r
+\r
+HTTP/1.1 200 OK\r
+Server: Apache/1.3.27 (Darwin) PHP/4.1.2\r
+Content-Type: text/html; charset=iso-8859-1\r
+Content-Length: 23\r
+\r
+This IS the real page!
+</datacheck>
+
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+ <name>
+HTTP with WWW-Authenticate and multiple auths in a single line
+ </name>
+ <command>
+http://%HOSTIP:%HTTPPORT/1204 -u testuser:testpass --anyauth
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<strip>
+^User-Agent:.*
+</strip>
+<protocol>
+GET /1204 HTTP/1.1\r
+Host: %HOSTIP:%HTTPPORT\r
+Accept: */*\r
+\r
+GET /1204 HTTP/1.1\r
+Authorization: Basic dGVzdHVzZXI6dGVzdHBhc3M=\r
+Host: %HOSTIP:%HTTPPORT\r
+Accept: */*\r
+\r
+</protocol>
+</verify>
+</testcase>