From fc6eff13b5414caf6edf22d73a3239e074a04216 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 4 May 2004 07:52:53 +0000 Subject: [PATCH] General HTTP authentication cleanup and fixes --- CHANGES | 13 ++ RELEASE-NOTES | 5 +- lib/http.c | 428 +++++++++++++++++++++-------------------- lib/http.h | 6 +- lib/http_digest.c | 76 +++++--- lib/http_digest.h | 5 +- lib/http_ntlm.c | 14 +- lib/transfer.c | 50 +++-- lib/url.c | 22 ++- lib/urldata.h | 22 ++- tests/data/Makefile.am | 41 ++-- tests/data/test16 | 2 +- tests/data/test167 | 62 ++++++ tests/data/test168 | 82 ++++++++ tests/data/test169 | 107 +++++++++++ tests/data/test503 | 2 +- tests/data/test63 | 2 +- tests/data/test80 | 2 +- tests/data/test82 | 2 +- tests/data/test85 | 2 +- 20 files changed, 636 insertions(+), 309 deletions(-) create mode 100644 tests/data/test167 create mode 100644 tests/data/test168 create mode 100644 tests/data/test169 diff --git a/CHANGES b/CHANGES index 15e066f06..0c291a0b5 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,19 @@ Changelog +Daniel (3 May 2004) +- Rewritten HTTP authentication code. The previous code could not properly + deal with the added test cases 167, 168 and 169. I've now rewritten the code + to better separate host and proxy authentication and not re-use the same + variables as much as before as it proved non working in the more involved + cases. All the current tests run OK now, and so do the new ones. The curl + tool got a new option named --proxy-digest to enable HTTP Digest + authentication with the proxy. I also made the library support it. + +- Gisle Vanem made the LDAP code work with wldap32.dll as supplied with + Win-98/ME/2000/XP, so no extra .dlls are required when curl/libcurl is used + on these Windows versions. + Daniel (30 April 2004) - runtests.pl now scans the valgrind log for valgrind-detected memory leaks after each test case if valgrind was found and used. diff --git a/RELEASE-NOTES b/RELEASE-NOTES index da90af910..eeecfc955 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -2,12 +2,14 @@ Curl and libcurl 7.12.0. Public curl release number: 81 Releases counted from the very beginning: 108 - Available command line options: 94 + Available command line options: 95 Available curl_easy_setopt() options: 113 Number of public functions in libcurl: 35 This release includes the following changes: + o curl --proxy-digest is a new command line option + o the Windows version of libcurl can use wldap32.dll for LDAP o curl_easy_strerror(), curl_multi_strerror() and curl_share_strerror() o IPv6-enabled Windows hosts now resolves names threaded/asynch as well o configure --with-libidn can be used to point out the root dir of a libidn @@ -16,6 +18,7 @@ This release includes the following changes: This release includes the following bugfixes: + o HTTP Digest authentication with the proxy works o mulipart formposting with -F and file names with spaces work again o curl_easy_duphandle() now works when ares-enabled o HTTP Digest authentication works a lot more like the RFC says diff --git a/lib/http.c b/lib/http.c index fb538e516..b8243b35a 100644 --- a/lib/http.c +++ b/lib/http.c @@ -103,8 +103,6 @@ #include "memdebug.h" #endif -static CURLcode Curl_output_basic_proxy(struct connectdata *conn); - /* * checkheaders() checks the linked list of custom HTTP headers for a * particular header (prefix). @@ -124,23 +122,39 @@ static char *checkheaders(struct SessionHandle *data, const char *thisheader) } /* - * Curl_output_basic() sets up an Authorization: header for HTTP Basic - * authentication. It uses the conn->user, conn->passwd fields for it. + * Curl_output_basic() sets up an Authorization: header (or the proxy version) + * for HTTP Basic authentication. * * Returns CURLcode. */ -static CURLcode Curl_output_basic(struct connectdata *conn) +static CURLcode Curl_output_basic(struct connectdata *conn, bool proxy) { char *authorization; struct SessionHandle *data=conn->data; + char **userp; + char *user; + char *pwd; - sprintf(data->state.buffer, "%s:%s", conn->user, conn->passwd); - if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer), + if(proxy) { + userp = &conn->allocptr.proxyuserpwd; + user = conn->proxyuser; + pwd = conn->proxypasswd; + } + else { + userp = &conn->allocptr.userpwd; + user = conn->user; + pwd = conn->passwd; + } + + sprintf(data->state.buffer, "%s:%s", user, pwd); + if(Curl_base64_encode(data->state.buffer, + strlen(data->state.buffer), &authorization) > 0) { - if(conn->allocptr.userpwd) - free(conn->allocptr.userpwd); - conn->allocptr.userpwd = aprintf( "Authorization: Basic %s\015\012", - authorization); + if(*userp) + free(*userp); + *userp = aprintf( "%sAuthorization: Basic %s\015\012", + proxy?"Proxy-":"", + authorization); free(authorization); } else @@ -148,61 +162,74 @@ static CURLcode Curl_output_basic(struct connectdata *conn) return CURLE_OK; } -/* - * Curl_output_basic_proxy() sets up a proxy-Authorization: header for HTTP - * Basic proxy authentication. It uses the conn->proxyuser and - * conn->proxypasswd fields for it. +/* pickoneauth() selects the most favourable authentication method from the + * ones available and the ones we want. * - * Returns CURLcode. + * return TRUE if one was picked */ -static CURLcode Curl_output_basic_proxy(struct connectdata *conn) +static bool pickoneauth(struct auth *pick) { - char *authorization; - struct SessionHandle *data=conn->data; + bool picked; + if(pick->avail) { + /* only deal with authentication we want */ + long avail = pick->avail & pick->want; + picked = TRUE; - sprintf(data->state.buffer, "%s:%s", - conn->proxyuser, conn->proxypasswd); - if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer), - &authorization) > 0) { - Curl_safefree(conn->allocptr.proxyuserpwd); - conn->allocptr.proxyuserpwd = - aprintf("Proxy-authorization: Basic %s\015\012", authorization); - free(authorization); - } - else - return CURLE_OUT_OF_MEMORY; - return CURLE_OK; -} - -/* - * Curl_http_auth_act() checks what authentication methods that are available - * and decides which one (if any) to use. It will set 'newurl' if an auth - * metod was picked. - */ - -void Curl_http_auth_act(struct connectdata *conn) -{ - struct SessionHandle *data = conn->data; - - if(data->state.authavail) { /* The order of these checks is highly relevant, as this will be the order of preference in case of the existance of multiple accepted types. */ - if(data->state.authavail & CURLAUTH_GSSNEGOTIATE) - data->state.authwant = CURLAUTH_GSSNEGOTIATE; - else if(data->state.authavail & CURLAUTH_DIGEST) - data->state.authwant = CURLAUTH_DIGEST; - else if(data->state.authavail & CURLAUTH_NTLM) - data->state.authwant = CURLAUTH_NTLM; - else if(data->state.authavail & CURLAUTH_BASIC) - data->state.authwant = CURLAUTH_BASIC; - else - data->state.authwant = CURLAUTH_NONE; /* clear it */ - - if(data->state.authwant) - conn->newurl = strdup(data->change.url); /* clone URL */ - data->state.authavail = CURLAUTH_NONE; /* clear it here */ + if(avail & CURLAUTH_GSSNEGOTIATE) + pick->picked = CURLAUTH_GSSNEGOTIATE; + else if(avail & CURLAUTH_DIGEST) + pick->picked = CURLAUTH_DIGEST; + else if(avail & CURLAUTH_NTLM) + pick->picked = CURLAUTH_NTLM; + else if(avail & CURLAUTH_BASIC) + pick->picked = CURLAUTH_BASIC; + else { + pick->picked = CURLAUTH_NONE; /* none was picked clear it */ + picked = FALSE; + } + pick->avail = CURLAUTH_NONE; /* clear it here */ } - else if(!data->state.authdone && (data->info.httpcode < 400)) { + else + return FALSE; + + return picked; +} + +/* + * Curl_http_auth_act() gets called when a all HTTP headers have been received + * and it checks what authentication methods that are available and decides + * which one (if any) to use. It will set 'newurl' if an auth metod was + * picked. + */ + +CURLcode Curl_http_auth_act(struct connectdata *conn) +{ + struct SessionHandle *data = conn->data; + bool pickhost; + bool pickproxy; + CURLcode code = CURLE_OK; + + if(data->state.authproblem) + return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK; + + if(conn->bits.user_passwd) { + pickhost = pickoneauth(&data->state.authhost); + if(!pickhost && (conn->keep.httpcode == 401)) + data->state.authproblem = TRUE; + } + if(conn->bits.proxy_user_passwd) { + pickproxy = pickoneauth(&data->state.authproxy); + if(!pickproxy && (conn->keep.httpcode == 407)) + data->state.authproblem = TRUE; + } + + if(pickhost || pickproxy) + conn->newurl = strdup(data->change.url); /* clone URL */ + + else if((data->info.httpcode < 400) && + (!data->state.authhost.done)) { /* no (known) authentication available, authentication is not "done" yet and no authentication seems to be required and @@ -210,23 +237,34 @@ void Curl_http_auth_act(struct connectdata *conn) if((data->set.httpreq != HTTPREQ_GET) && (data->set.httpreq != HTTPREQ_HEAD)) { conn->newurl = strdup(data->change.url); /* clone URL */ - data->state.authdone = TRUE; + data->state.authhost.done = TRUE; } } + if (Curl_http_should_fail(conn)) { + failf (data, "The requested URL returned error: %d", + conn->keep.httpcode); + code = CURLE_HTTP_RETURNED_ERROR; + } + + return code; } /** - * http_auth_headers() setups the authentication headers for the host/proxy - * and the correct authentication method. conn->data->state.authdone is set to - * TRUE when authentication is done. + * Curl_http_output_auth() setups the authentication headers for the + * host/proxy and the correct authentication + * method. conn->data->state.authdone is set to TRUE when authentication is + * done. * * @param conn all information about the current connection * * Returns CURLcode */ -static CURLcode http_auth_headers(struct connectdata *conn, - char *request, - char *path) +static CURLcode +Curl_http_output_auth(struct connectdata *conn, + char *request, + char *path, + bool proxytunnel) /* TRUE if this is the request setting + up the proxy tunnel */ { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; @@ -234,19 +272,29 @@ static CURLcode http_auth_headers(struct connectdata *conn, curlassert(data); - if(!data->state.authstage) { - if(conn->bits.httpproxy && conn->bits.proxy_user_passwd) { - data->state.authdone = FALSE; - Curl_http_auth_stage(data, 407); - } - else if(conn->bits.user_passwd) { - data->state.authdone = FALSE; - Curl_http_auth_stage(data, 401); - } - else { - data->state.authdone = TRUE; - return CURLE_OK; /* no authentication with no user or password */ - } + if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) || + conn->bits.user_passwd) + /* continue please */ ; + else { + data->state.authhost.done = TRUE; + data->state.authproxy.done = TRUE; + return CURLE_OK; /* no authentication with no user or password */ + } + + if(data->state.authhost.want && + !data->state.authhost.picked) { + /* The app has selected one or more methods, but none has been picked + so far by a server round-trip. Then we set the picked one to the + want one, and if this is one single bit it'll be used instantly. */ + data->state.authhost.picked = data->state.authhost.want; + } + + if(data->state.authproxy.want && + !data->state.authproxy.picked) { + /* The app has selected one or more methods, but none has been picked + so far by a server round-trip. Then we set the picked one to the + want one, and if this is one single bit it'll be used instantly. */ + data->state.authproxy.picked = data->state.authproxy.want; } /* To prevent the user+password to get sent to other than the original @@ -256,10 +304,11 @@ static CURLcode http_auth_headers(struct connectdata *conn, curl_strequal(data->state.auth_host, conn->host.name) || data->set.http_disable_hostname_check_before_authentication) { - /* Send proxy authentication header if needed */ - if (data->state.authstage == 407) { + /* Send proxy authentication header if needed */ + if (conn->bits.httpproxy && + (data->set.tunnel_thru_httpproxy == proxytunnel)) { #ifdef USE_SSLEAY - if(data->state.authwant == CURLAUTH_NTLM) { + if(data->state.authproxy.want == CURLAUTH_NTLM) { auth=(char *)"NTLM"; result = Curl_output_ntlm(conn, TRUE); if(result) @@ -267,39 +316,52 @@ static CURLcode http_auth_headers(struct connectdata *conn, } else #endif - if(data->state.authwant == CURLAUTH_BASIC) { + if(data->state.authproxy.want == CURLAUTH_BASIC) { /* Basic */ if(conn->bits.proxy_user_passwd && !checkheaders(data, "Proxy-authorization:")) { auth=(char *)"Basic"; - result = Curl_output_basic_proxy(conn); + result = Curl_output_basic(conn, TRUE); if(result) return result; } - data->state.authdone = TRUE; - /* Switch to web authentication after proxy authentication is done */ - Curl_http_auth_stage(data, 401); + data->state.authproxy.done = TRUE; } + else if(data->state.authproxy.want == CURLAUTH_DIGEST) { + auth=(char *)"Digest"; + result = Curl_output_digest(conn, + TRUE, /* proxy */ + (unsigned char *)request, + (unsigned char *)path); + if(result) + return result; + } + infof(data, "Proxy auth using %s with user '%s'\n", auth, conn->proxyuser?conn->proxyuser:""); } + else + /* we have no proxy so let's pretend we're done authenticating + with it */ + data->state.authproxy.done = TRUE; + /* Send web authentication header if needed */ - if (data->state.authstage == 401) { + { auth = NULL; #ifdef HAVE_GSSAPI - if((data->state.authwant == CURLAUTH_GSSNEGOTIATE) && + if((data->state.authhost.want == CURLAUTH_GSSNEGOTIATE) && data->state.negotiate.context && !GSS_ERROR(data->state.negotiate.status)) { auth=(char *)"GSS-Negotiate"; result = Curl_output_negotiate(conn); if (result) return result; - data->state.authdone = TRUE; + data->state.authhost.done = TRUE; } else #endif #ifdef USE_SSLEAY - if(data->state.authwant == CURLAUTH_NTLM) { + if(data->state.authhost.picked == CURLAUTH_NTLM) { auth=(char *)"NTLM"; result = Curl_output_ntlm(conn, FALSE); if(result) @@ -308,26 +370,25 @@ static CURLcode http_auth_headers(struct connectdata *conn, else #endif { - if((data->state.authwant == CURLAUTH_DIGEST) && - data->state.digest.nonce) { + if(data->state.authhost.picked == CURLAUTH_DIGEST) { auth=(char *)"Digest"; result = Curl_output_digest(conn, + FALSE, /* not a proxy */ (unsigned char *)request, (unsigned char *)path); if(result) return result; - data->state.authdone = TRUE; } - else if(data->state.authwant == CURLAUTH_BASIC) {/* Basic */ + else if(data->state.authhost.picked == CURLAUTH_BASIC) { if(conn->bits.user_passwd && !checkheaders(data, "Authorization:")) { auth=(char *)"Basic"; - result = Curl_output_basic(conn); + result = Curl_output_basic(conn, FALSE); if(result) return result; } /* basic is always ready */ - data->state.authdone = TRUE; + data->state.authhost.done = TRUE; } } if(auth) @@ -336,21 +397,21 @@ static CURLcode http_auth_headers(struct connectdata *conn, } } else - data->state.authdone = TRUE; + data->state.authhost.done = TRUE; return result; } /* - * Curl_http_auth() deals with Proxy-Authenticate: and WWW-Authenticate: + * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate: * headers. They are dealt with both in the transfer.c main loop and in the * proxy CONNECT loop. */ -CURLcode Curl_http_auth(struct connectdata *conn, - int httpcode, - char *header) /* pointing to the first non-space */ +CURLcode Curl_http_input_auth(struct connectdata *conn, + int httpcode, + char *header) /* the first non-space */ { /* * This resource requires authentication @@ -359,23 +420,18 @@ CURLcode Curl_http_auth(struct connectdata *conn, long *availp; char *start; + struct auth *authp; if (httpcode == 407) { start = header+strlen("Proxy-authenticate:"); availp = &data->info.proxyauthavail; + authp = &data->state.authproxy; } else { start = header+strlen("WWW-Authenticate:"); availp = &data->info.httpauthavail; + authp = &data->state.authhost; } - /* - * Switch from proxy to web authentication and back if needed - */ - if (httpcode == 407 && data->state.authstage != 407) - Curl_http_auth_stage(data, 407); - - else if (httpcode == 401 && data->state.authstage != 401) - Curl_http_auth_stage(data, 401); /* pass all white spaces */ while(*start && isspace((int)*start)) @@ -394,7 +450,8 @@ CURLcode Curl_http_auth(struct connectdata *conn, if (checkprefix("GSS-Negotiate", start) || checkprefix("Negotiate", start)) { *availp |= CURLAUTH_GSSNEGOTIATE; - if(data->state.authwant == CURLAUTH_GSSNEGOTIATE) { + authp->avail |= CURLAUTH_GSSNEGOTIATE; + if(authp->picked == CURLAUTH_GSSNEGOTIATE) { /* if exactly this is wanted, go */ int neg = Curl_input_negotiate(conn, start); if (neg == 0) { @@ -406,9 +463,6 @@ CURLcode Curl_http_auth(struct connectdata *conn, data->state.authproblem = TRUE; } } - else - if(data->state.authwant & CURLAUTH_GSSNEGOTIATE) - data->state.authavail |= CURLAUTH_GSSNEGOTIATE; } else #endif @@ -416,76 +470,50 @@ CURLcode Curl_http_auth(struct connectdata *conn, /* NTLM support requires the SSL crypto libs */ if(checkprefix("NTLM", start)) { *availp |= CURLAUTH_NTLM; - if(data->state.authwant == CURLAUTH_NTLM) { - /* NTLM authentication is activated */ + authp->avail |= CURLAUTH_NTLM; + if(authp->picked == CURLAUTH_NTLM) { + /* NTLM authentication is picked and activated */ CURLntlm ntlm = Curl_input_ntlm(conn, (bool)(httpcode == 407), start); - if(CURLNTLM_BAD != ntlm) { - conn->newurl = strdup(data->change.url); /* clone string */ - data->state.authproblem = (conn->newurl == NULL); - } + if(CURLNTLM_BAD != ntlm) + data->state.authproblem = FALSE; else { infof(data, "Authentication problem. Ignoring this.\n"); data->state.authproblem = TRUE; } } - else - if(data->state.authwant & CURLAUTH_NTLM) - data->state.authavail |= CURLAUTH_NTLM; } else #endif if(checkprefix("Digest", start)) { + CURLdigest dig; *availp |= CURLAUTH_DIGEST; - if(data->state.authwant == CURLAUTH_DIGEST) { - /* Digest authentication is activated */ - CURLdigest dig = Curl_input_digest(conn, start); + 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, (bool)(httpcode == 407), start); - if(CURLDIGEST_FINE == dig) { - /* We act on it. Store our new url, which happens to be - the same one we already use! */ - conn->newurl = strdup(data->change.url); /* clone string */ - data->state.authproblem = (conn->newurl == NULL); - } - else { - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; - } - } - else - if(data->state.authwant & CURLAUTH_DIGEST) { - /* We don't know if Digest is what we're gonna use, but we - call this function anyway to store the digest data that - is provided on this line, to skip the extra round-trip - we need to do otherwise. We must sure to free this - data! */ - Curl_input_digest(conn, start); - data->state.authavail |= CURLAUTH_DIGEST; - } - } - else if(checkprefix("Basic", start)) { - *availp |= CURLAUTH_BASIC; - if((data->state.authwant == CURLAUTH_BASIC) && - (httpcode == data->state.authstage)) { - /* We asked for Basic authentication but got a 40X back - anyway, which basicly means our name+password isn't - valid. */ - data->state.authavail = CURLAUTH_NONE; + if(CURLDIGEST_FINE != dig) { infof(data, "Authentication problem. Ignoring this.\n"); data->state.authproblem = TRUE; } - else if(data->state.authwant & CURLAUTH_BASIC) { - data->state.authavail |= CURLAUTH_BASIC; - } else { - /* - ** We asked for something besides basic but got - ** Basic anyway. This is no good. - */ - infof(data, "Server expects Basic auth, but we're doing something else.\n"); - data->state.authproblem = TRUE; + } + else 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 basicly means our name+password isn't + valid. */ + authp->avail = CURLAUTH_NONE; + infof(data, "Authentication problem. Ignoring this.\n"); + data->state.authproblem = TRUE; } } + return CURLE_OK; } @@ -562,15 +590,16 @@ int Curl_http_should_fail(struct connectdata *conn) infof(data,"%s: authproblem = %d\n",__FUNCTION__,data->state.authproblem); #endif - if (data->state.authstage && - (data->state.authstage == k->httpcode)) - return (data->state.authdone || data->state.authproblem); - /* ** Either we're not authenticating, or we're supposed to ** be authenticating something else. This is an error. */ - return 1; + if((k->httpcode == 401) && !conn->bits.user_passwd) + return TRUE; + if((k->httpcode == 407) && !conn->bits.proxy_user_passwd) + return TRUE; + + return data->state.authproblem; } /* @@ -876,9 +905,9 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, char *hostname, int remote_port) { - int httpcode=0; int subversion=0; struct SessionHandle *data=conn->data; + struct Curl_transfer_keeper *k = &conn->keep; CURLcode result; int res; @@ -916,7 +945,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; /* Setup the proxy-authorization header, if any */ - result = http_auth_headers(conn, (char *)"CONNECT", host_port); + result = Curl_http_output_auth(conn, (char *)"CONNECT", host_port, TRUE); if(CURLE_OK == result) { /* OK, now send the connect request to the proxy */ @@ -1039,18 +1068,18 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, letter = line_start[perline]; line_start[perline]=0; /* zero terminate the buffer */ if((checkprefix("WWW-Authenticate:", line_start) && - (401 == httpcode)) || + (401 == k->httpcode)) || (checkprefix("Proxy-authenticate:", line_start) && - (407 == httpcode))) { - result = Curl_http_auth(conn, httpcode, line_start); + (407 == k->httpcode))) { + result = Curl_http_input_auth(conn, k->httpcode, line_start); if(result) return result; } else if(2 == sscanf(line_start, "HTTP/1.%d %d", &subversion, - &httpcode)) { + &k->httpcode)) { /* store the HTTP code */ - data->info.httpproxycode = httpcode; + data->info.httpproxycode = k->httpcode; } /* put back the letter we blanked out before */ line_start[perline]= letter; @@ -1073,8 +1102,9 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, } while(conn->newurl); - if(200 != httpcode) { - failf(data, "Received HTTP code %d from proxy after CONNECT", httpcode); + if(200 != k->httpcode) { + failf(data, "Received HTTP code %d from proxy after CONNECT", + k->httpcode); return CURLE_RECV_ERROR; } @@ -1084,7 +1114,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, Curl_safefree(conn->allocptr.proxyuserpwd); conn->allocptr.proxyuserpwd = NULL; - Curl_http_auth_stage(data, 401); /* move on to the host auth */ + data->state.authproxy.done = TRUE; infof (data, "Proxy replied OK to CONNECT request\n"); return CURLE_OK; @@ -1189,24 +1219,6 @@ CURLcode Curl_http_done(struct connectdata *conn) return CURLE_OK; } -/* - * Curl_http_auth_stage() sets the "authentication stage" - which is 407 for - * proxy authentication or 401 for host authentication. - */ -void Curl_http_auth_stage(struct SessionHandle *data, - int stage) -{ - curlassert((stage == 401) || (stage == 407)); - - /* We set none, one or more bits for which authentication types we accept - for this stage. */ - data->state.authwant = (stage == 401)? - data->set.httpauth:data->set.proxyauth; - - data->state.authstage = stage; - data->state.authavail = CURLAUTH_NONE; /* no type available yet */ -} - /* * Curl_http() gets called from the generic Curl_do() function when a HTTP * request is to be performed. This creates and sends a propperly constructed @@ -1284,11 +1296,12 @@ CURLcode Curl_http(struct connectdata *conn) } /* setup the authentication headers */ - result = http_auth_headers(conn, request, ppath); + result = Curl_http_output_auth(conn, request, ppath, FALSE); if(result) return result; - if(!data->state.authdone && (httpreq != HTTPREQ_GET)) { + if((!data->state.authhost.done || !data->state.authproxy.done ) && + (httpreq != HTTPREQ_GET)) { /* Until we are authenticated, we switch over to HEAD. Unless its a GET we want to do. The explanation for this is rather long and boring, but the point is that it can't be done otherwise without risking having to @@ -1583,7 +1596,7 @@ CURLcode Curl_http(struct connectdata *conn) request, ppath, httpstring, - (conn->bits.httpproxy && conn->allocptr.proxyuserpwd)? + conn->allocptr.proxyuserpwd? conn->allocptr.proxyuserpwd:"", conn->allocptr.userpwd?conn->allocptr.userpwd:"", (conn->bits.use_range && conn->allocptr.rangeline)? @@ -1755,8 +1768,8 @@ CURLcode Curl_http(struct connectdata *conn) /* setup variables for the upcoming transfer */ result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount, - data->state.authdone?FIRSTSOCKET:-1, - data->state.authdone?&http->writebytecount:NULL); + FIRSTSOCKET, + &http->writebytecount); if(result) { Curl_formclean(http->sendit); /* free that whole lot */ return result; @@ -1794,8 +1807,8 @@ CURLcode Curl_http(struct connectdata *conn) /* prepare for transfer */ result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount, - data->state.authdone?FIRSTSOCKET:-1, - data->state.authdone?&http->writebytecount:NULL); + FIRSTSOCKET, + &http->writebytecount); if(result) return result; break; @@ -1826,7 +1839,8 @@ CURLcode Curl_http(struct connectdata *conn) if(data->set.postfields) { - if(data->state.authdone && (postsize < (100*1024))) { + if((data->state.authhost.done || data->state.authproxy.done ) + && (postsize < (100*1024))) { /* If we're not done with the authentication phase, we don't expect to actually send off any data yet. Hence, we delay the sending of the body until we receive that friendly 100-continue response */ @@ -1862,7 +1876,7 @@ CURLcode Curl_http(struct connectdata *conn) /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, http->postsize); - if(!data->state.authdone && !checkheaders(data, "Expect:")) { + if(!checkheaders(data, "Expect:")) { /* if not disabled explicitly we add a Expect: 100-continue to the headers which actually speeds up post operations (as there is one packet coming back from the web server) */ diff --git a/lib/http.h b/lib/http.h index 5dff8cb71..944314a55 100644 --- a/lib/http.h +++ b/lib/http.h @@ -45,9 +45,9 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap, /* These functions are in http.c */ void Curl_http_auth_stage(struct SessionHandle *data, int stage); -CURLcode Curl_http_auth(struct connectdata *conn, - int httpcode, char *header); -void Curl_http_auth_act(struct connectdata *conn); +CURLcode Curl_http_input_auth(struct connectdata *conn, + int httpcode, char *header); +CURLcode Curl_http_auth_act(struct connectdata *conn); int Curl_http_should_fail(struct connectdata *conn); #endif diff --git a/lib/http_digest.c b/lib/http_digest.c index 9d5864496..35ba17180 100644 --- a/lib/http_digest.c +++ b/lib/http_digest.c @@ -47,14 +47,16 @@ #include "memdebug.h" #endif -/* Test example header: +/* Test example headers: WWW-Authenticate: Digest realm="testrealm", nonce="1053604598" +Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598" */ CURLdigest Curl_input_digest(struct connectdata *conn, - char *header) /* rest of the www-authenticate: + bool proxy, + char *header) /* rest of the *-authenticate: header */ { bool more = TRUE; @@ -64,7 +66,14 @@ CURLdigest Curl_input_digest(struct connectdata *conn, bool foundAuthInt = FALSE; struct SessionHandle *data=conn->data; bool before = FALSE; /* got a nonce before */ - struct digestdata *d = &data->state.digest; + struct digestdata *d; + + if(proxy) { + d = &data->state.proxydigest; + } + else { + d = &data->state.digest; + } /* skip initial whitespaces */ while(*header && isspace((int)*header)) @@ -78,7 +87,7 @@ CURLdigest Curl_input_digest(struct connectdata *conn, before = TRUE; /* clear off any former leftovers and init to defaults */ - Curl_digest_cleanup(data); + Curl_digest_cleanup_one(d); while(more) { char value[32]; @@ -183,6 +192,7 @@ static void md5_to_ascii(unsigned char *source, /* 16 bytes */ } CURLcode Curl_output_digest(struct connectdata *conn, + bool proxy, unsigned char *request, unsigned char *uripath) { @@ -198,9 +208,28 @@ CURLcode Curl_output_digest(struct connectdata *conn, char *cnonce; char *tmp = NULL; struct timeval now; + struct auth *authp; + char **userp; struct SessionHandle *data = conn->data; - struct digestdata *d = &data->state.digest; + struct digestdata *d; + + if(proxy) { + d = &data->state.proxydigest; + authp = &data->state.authproxy; + userp = &conn->allocptr.proxyuserpwd; + } + else { + d = &data->state.digest; + authp = &data->state.authhost; + userp = &conn->allocptr.userpwd; + } + + if(!d->nonce) { + authp->done = FALSE; + return CURLE_OK; + } + authp->done = TRUE; ha1 = (unsigned char *)malloc(33); /* 32 digits and 1 zero byte */ @@ -293,8 +322,8 @@ CURLcode Curl_output_digest(struct connectdata *conn, Curl_safefree(conn->allocptr.userpwd); if (d->qop) { - conn->allocptr.userpwd = - aprintf( "Authorization: Digest " + *userp = + aprintf( "%sAuthorization: Digest " "username=\"%s\", " "realm=\"%s\", " "nonce=\"%s\", " @@ -303,6 +332,7 @@ CURLcode Curl_output_digest(struct connectdata *conn, "nc=\"%08x\", " "qop=\"%s\", " "response=\"%s\"", + proxy?"Proxy-":"", conn->user, d->realm, d->nonce, @@ -318,13 +348,14 @@ CURLcode Curl_output_digest(struct connectdata *conn, same nonce in the qop=auth mode. */ } else { - conn->allocptr.userpwd = - aprintf( "Authorization: Digest " + *userp = + aprintf( "%sAuthorization: Digest " "username=\"%s\", " "realm=\"%s\", " "nonce=\"%s\", " "uri=\"%s\", " "response=\"%s\"", + proxy?"Proxy-":"", conn->user, d->realm, d->nonce, @@ -336,36 +367,28 @@ CURLcode Curl_output_digest(struct connectdata *conn, if(d->opaque) { /* append opaque */ tmp = aprintf(", opaque=\"%s\"", d->opaque); - conn->allocptr.userpwd = (char*) - realloc(conn->allocptr.userpwd, - strlen(conn->allocptr.userpwd) + strlen(tmp) + 1); - strcat(conn->allocptr.userpwd, tmp); + *userp = (char*) realloc(*userp, strlen(*userp) + strlen(tmp) + 1); + strcat(*userp, tmp); free(tmp); } if(d->algorithm) { /* append algorithm */ tmp = aprintf(", algorithm=\"%s\"", d->algorithm); - conn->allocptr.userpwd = (char*) - realloc(conn->allocptr.userpwd, - strlen(conn->allocptr.userpwd) + strlen(tmp) + 1); + *userp = (char*) realloc(*userp, strlen(*userp) + strlen(tmp) + 1); strcat(conn->allocptr.userpwd, tmp); free(tmp); } /* append CRLF to the userpwd header */ - conn->allocptr.userpwd = (char*) - realloc(conn->allocptr.userpwd, - strlen(conn->allocptr.userpwd) + 3 + 1); - strcat(conn->allocptr.userpwd, "\r\n"); + *userp = (char*) realloc(*userp, strlen(*userp) + 3 + 1); + strcat(*userp, "\r\n"); return CURLE_OK; } -void Curl_digest_cleanup(struct SessionHandle *data) +void Curl_digest_cleanup_one(struct digestdata *d) { - struct digestdata *d = &data->state.digest; - if(d->nonce) free(d->nonce); d->nonce = NULL; @@ -395,4 +418,11 @@ void Curl_digest_cleanup(struct SessionHandle *data) d->stale = FALSE; /* default means normal, not stale */ } + +void Curl_digest_cleanup(struct SessionHandle *data) +{ + Curl_digest_cleanup_one(&data->state.digest); + Curl_digest_cleanup_one(&data->state.proxydigest); +} + #endif diff --git a/lib/http_digest.h b/lib/http_digest.h index a8b33add8..c7a41f1b4 100644 --- a/lib/http_digest.h +++ b/lib/http_digest.h @@ -38,12 +38,15 @@ enum { }; /* this is for digest header input */ -CURLdigest Curl_input_digest(struct connectdata *conn, char *header); +CURLdigest Curl_input_digest(struct connectdata *conn, + bool proxy, char *header); /* this is for creating digest header output */ CURLcode Curl_output_digest(struct connectdata *conn, + bool proxy, unsigned char *request, unsigned char *uripath); void Curl_digest_cleanup(struct SessionHandle *data); +void Curl_digest_cleanup_one(struct digestdata *dig); #endif diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c index d1f4e306c..9629b34d1 100644 --- a/lib/http_ntlm.c +++ b/lib/http_ntlm.c @@ -46,7 +46,6 @@ #include "base64.h" #include "http_ntlm.h" #include "url.h" -#include "http.h" /* for Curl_http_auth_stage() */ #define _MPRINTF_REPLACE /* use our functions only */ #include @@ -298,23 +297,26 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, char *passwdp; /* point to the correct struct with this */ struct ntlmdata *ntlm; + struct auth *authp; curlassert(conn); curlassert(conn->data); - conn->data->state.authdone = FALSE; if(proxy) { allocuserpwd = &conn->allocptr.proxyuserpwd; userp = conn->proxyuser; passwdp = conn->proxypasswd; ntlm = &conn->proxyntlm; + authp = &conn->data->state.authproxy; } else { allocuserpwd = &conn->allocptr.userpwd; userp = conn->user; passwdp = conn->passwd; ntlm = &conn->ntlm; + authp = &conn->data->state.authhost; } + authp->done = FALSE; /* not set means empty */ if(!userp) @@ -563,11 +565,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; /* FIX TODO */ ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */ - conn->data->state.authdone = TRUE; - - /* Switch to web authentication after proxy authentication is done */ - if (proxy) - Curl_http_auth_stage(conn->data, 401); + authp->done = TRUE; } break; @@ -578,7 +576,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, free(*allocuserpwd); *allocuserpwd=NULL; } - conn->data->state.authdone = TRUE; + authp->done = TRUE; break; } diff --git a/lib/transfer.c b/lib/transfer.c index 3df1f1fd0..ed1245fe9 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -445,9 +445,9 @@ CURLcode Curl_readwrite(struct connectdata *conn, } /* - ** Now that all of the headers have been parsed, see - ** if we should give up and return an error. - */ + * When all the headers have been parsed, see if we should give + * up and return an error. + */ if (Curl_http_should_fail(conn)) { failf (data, "The requested URL returned error: %d", k->httpcode); @@ -483,19 +483,23 @@ CURLcode Curl_readwrite(struct connectdata *conn, } else { /* we wanted to resume a download, although the server - doesn't seem to support this and we did this with a GET - (if it wasn't a GET we did a POST or PUT resume) */ + * doesn't seem to support this and we did this with a GET + * (if it wasn't a GET we did a POST or PUT resume) */ failf (data, "HTTP server doesn't seem to support " "byte ranges. Cannot resume."); return CURLE_HTTP_RANGE_ERROR; } } - if(!stop_reading) - /* *auth_act() checks what authentication methods that are - available and decides which one (if any) to use. It will - set 'newurl' if an auth metod was picked. */ - Curl_http_auth_act(conn); + if(!stop_reading) { + /* Curl_http_auth_act() checks what authentication methods + * that are available and decides which one (if any) to + * use. It will set 'newurl' if an auth metod was picked. */ + result = Curl_http_auth_act(conn); + + if(result) + return result; + } if(!k->header) { /* @@ -593,22 +597,17 @@ CURLcode Curl_readwrite(struct connectdata *conn, data->info.httpversion = k->httpversion; /* - ** This code executes as part of processing - ** the header. As a result, it's not - ** totally clear how to interpret the - ** response code yet as that depends on what - ** other headers may be present. 401 and - ** 407 may be errors, but may be OK - ** depending on how authentication is - ** working. Other codes are definitely - ** errors, so give up here. - */ + * This code executes as part of processing the header. As a + * result, it's not totally clear how to interpret the + * response code yet as that depends on what other headers may + * be present. 401 and 407 may be errors, but may be OK + * depending on how authentication is working. Other codes + * are definitely errors, so give up here. + */ if (data->set.http_fail_on_error && (k->httpcode >= 400) && (k->httpcode != 401) && (k->httpcode != 407)) { - /* If we have been told to fail hard on HTTP-errors, - here is the check for that: */ /* serious error, go home! */ failf (data, "The requested URL returned error: %d", k->httpcode); @@ -821,7 +820,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, (401 == k->httpcode)) || (checkprefix("Proxy-authenticate:", k->p) && (407 == k->httpcode))) { - result = Curl_http_auth(conn, k->httpcode, k->p); + result = Curl_http_input_auth(conn, k->httpcode, k->p); if(result) return result; } @@ -1514,10 +1513,9 @@ CURLcode Curl_pretransfer(struct SessionHandle *data) data->state.this_is_a_follow = FALSE; /* reset this */ data->state.errorbuf = FALSE; /* no error has occurred */ - /* set preferred authentication, default to basic */ - - data->state.authstage = 0; /* initialize authentication later */ data->state.authproblem = FALSE; + data->state.authhost.want = data->set.httpauth; + data->state.authproxy.want = data->set.proxyauth; /* If there was a list of cookie files to read and we haven't done it before, do it now! */ diff --git a/lib/url.c b/lib/url.c index 7962d264e..df07f538a 100644 --- a/lib/url.c +++ b/lib/url.c @@ -1332,9 +1332,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) CURLcode Curl_disconnect(struct connectdata *conn) { + struct SessionHandle *data; if(!conn) return CURLE_OK; /* this is closed and fine already */ + data = conn->data; + /* * The range string is usually freed in curl_done(), but we might * get here *instead* if we fail prematurely. Thus we need to be able @@ -1346,11 +1349,20 @@ CURLcode Curl_disconnect(struct connectdata *conn) } if((conn->ntlm.state != NTLMSTATE_NONE) || - (conn->proxyntlm.state != NTLMSTATE_NONE)) + (conn->proxyntlm.state != NTLMSTATE_NONE)) { /* Authentication data is a mix of connection-related and sessionhandle- related stuff. NTLM is connection-related so when we close the shop we shall forget. */ - conn->data->state.authstage = 0; + data->state.authhost.done = FALSE; + data->state.authhost.picked = + data->state.authhost.want; + + data->state.authproxy.done = FALSE; + data->state.authproxy.picked = + data->state.authhost.want; + + data->state.authproblem = FALSE; + } if(conn->curl_disconnect) /* This is set if protocol-specific cleanups should be made */ @@ -1358,8 +1370,8 @@ CURLcode Curl_disconnect(struct connectdata *conn) if(-1 != conn->connectindex) { /* unlink ourselves! */ - infof(conn->data, "Closing connection #%d\n", conn->connectindex); - conn->data->state.connects[conn->connectindex] = NULL; + infof(data, "Closing connection #%d\n", conn->connectindex); + data->state.connects[conn->connectindex] = NULL; } Curl_safefree(conn->proto.generic); @@ -1488,7 +1500,7 @@ ConnectionExists(struct SessionHandle *data, } if((needle->protocol & PROT_FTP) || ((needle->protocol & PROT_HTTP) && - (needle->data->state.authwant==CURLAUTH_NTLM))) { + (needle->data->state.authhost.want==CURLAUTH_NTLM))) { /* This is FTP or HTTP+NTLM, verify that we're using the same name and password as well */ if(!strequal(needle->user, check->user) || diff --git a/lib/urldata.h b/lib/urldata.h index 9cda637b9..8d29cf66e 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -678,6 +678,16 @@ typedef enum { #define MAX_CURL_USER_LENGTH_TXT "255" #define MAX_CURL_PASSWORD_LENGTH_TXT "255" +struct auth { + long want; /* Bitmask set to the authentication methods wanted by the app + (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */ + long picked; + long avail; /* bitmask for what the server reports to support for this + resource */ + bool done; /* TRUE when the auth phase is done and ready to do the *actual* + request */ +}; + struct UrlState { enum { Curl_if_none, @@ -724,22 +734,16 @@ struct UrlState { is always set TRUE when curl_easy_perform() is called. */ struct digestdata digest; + struct digestdata proxydigest; #ifdef HAVE_GSSAPI struct negotiatedata negotiate; #endif - long authstage; /* 0 - authwant and authavail are still not initialized - 401 - web authentication is performed - 407 - proxy authentication is performed */ - long authwant; /* initially set to authentication methods requested by - client (either with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH - depending on authstage) */ - long authavail; /* what the server reports */ + struct auth authhost; + struct auth authproxy; bool authproblem; /* TRUE if there's some problem authenticating */ - bool authdone; /* TRUE when the auth phase is done and ready - to do the *actual* request */ #ifdef USE_ARES ares_channel areschannel; /* for name resolves */ #endif diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 3e3749aad..69d71d388 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -3,26 +3,27 @@ install: test: EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \ -test10 test109 test118 test13 test200 test28 test36 test47 test100 \ -test11 test119 test14 test201 test29 test37 test5 test101 test110 \ -test12 test15 test202 test3 test4 test6 test102 test111 test120 test16 \ -test21 test30 test7 test103 test112 test121 test17 test22 test300 \ -test8 test104 test113 test122 test18 test23 test301 test9 test105 \ -test114 test123 test19 test24 test302 test43 test31 test106 test115 \ -test124 test190 test25 test303 test44 test38 test107 test116 test125 \ -test2 test26 test33 test45 test126 test304 test39 test32 test128 \ -test48 test306 test130 test131 test132 test133 test134 test135 test305 \ -test49 test50 test51 test52 test53 test54 test55 test56 test500 \ -test501 test502 test503 test504 test136 test57 test137 test138 test58 \ -test139 test140 test141 test59 test60 test61 test142 test143 test62 \ -test63 test64 test65 test66 test144 test145 test67 test68 test41 \ -test40 test42 test69 test70 test71 test72 test73 test146 test505 \ -test74 test75 test76 test77 test78 test147 test148 test506 test79 \ -test80 test81 test82 test83 test84 test85 test86 test87 test507 \ -test149 test88 test89 test90 test508 test91 test92 test203 test93 \ -test94 test95 test509 test510 test97 test98 test99 test150 test151 \ -test152 test153 test154 test155 test156 test157 test158 test159 test511 \ -test160 test161 test162 test163 test164 test512 test165 test166 + test10 test109 test118 test13 test200 test28 test36 test47 test100 \ + test11 test119 test14 test201 test29 test37 test5 test101 test110 \ + test12 test15 test202 test3 test4 test6 test102 test111 test120 \ + test16 test21 test30 test7 test103 test112 test121 test17 test22 \ + test300 test8 test104 test113 test122 test18 test23 test301 test9 \ + test105 test114 test123 test19 test24 test302 test43 test31 test106 \ + test115 test124 test190 test25 test303 test44 test38 test107 test116 \ + test125 test2 test26 test33 test45 test126 test304 test39 test32 \ + test128 test48 test306 test130 test131 test132 test133 test134 \ + test135 test305 test49 test50 test51 test52 test53 test54 test55 \ + test56 test500 test501 test502 test503 test504 test136 test57 test137 \ + test138 test58 test139 test140 test141 test59 test60 test61 test142 \ + test143 test62 test63 test64 test65 test66 test144 test145 test67 \ + test68 test41 test40 test42 test69 test70 test71 test72 test73 \ + test146 test505 test74 test75 test76 test77 test78 test147 test148 \ + test506 test79 test80 test81 test82 test83 test84 test85 test86 \ + test87 test507 test149 test88 test89 test90 test508 test91 test92 \ + test203 test93 test94 test95 test509 test510 test97 test98 test99 \ + test150 test151 test152 test153 test154 test155 test156 test157 \ + test158 test159 test511 test160 test161 test162 test163 test164 \ + test512 test165 test166 test167 test168 test169 # The following tests have been removed from the dist since they no longer # work. We need to fix the test suite's FTPS server first, then bring them diff --git a/tests/data/test16 b/tests/data/test16 index 9e30ce8bf..4adea4a8d 100644 --- a/tests/data/test16 +++ b/tests/data/test16 @@ -32,7 +32,7 @@ HTTP with proxy athorization GET http://we.want.that.site.com/16 HTTP/1.1 -Proxy-authorization: Basic ZmFrZUB1c2VyOqenp2xvb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29uZw== +Proxy-Authorization: Basic ZmFrZUB1c2VyOqenp2xvb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29uZw== Host: we.want.that.site.com Pragma: no-cache Accept: */* diff --git a/tests/data/test167 b/tests/data/test167 new file mode 100644 index 000000000..5dda8770a --- /dev/null +++ b/tests/data/test167 @@ -0,0 +1,62 @@ +# Server-side + + +HTTP/1.1 401 Authorization Required swsclose +WWW-Authenticate: Digest realm="weirdorealm", nonce="12345" + + + + +HTTP/1.1 200 OK swsclose +Server: no + +Nice auth sir! + + + +HTTP/1.1 401 Authorization Required swsclose +WWW-Authenticate: Digest realm="weirdorealm", nonce="12345" + +HTTP/1.1 200 OK swsclose +Server: no + +Nice auth sir! + + + +# Client-side + + +http + + +HTTP with proxy-requiring-Basic to site-requiring-Digest + + +http://data.from.server.requiring.digest.hohoho.com/167 --proxy http://%HOSTIP:%HOSTPORT --proxy-user foo:bar --digest --user digest:alot + + + +# Verify data after the test has been "shot" + + +^User-Agent: curl/.* + + +GET http://data.from.server.requiring.digest.hohoho.com/167 HTTP/1.1 +Proxy-Authorization: Basic Zm9vOmJhcg== +User-Agent: curl/7.12.0-CVS (i686-pc-linux-gnu) libcurl/7.12.0-CVS OpenSSL/0.9.6b zlib/1.1.4 c-ares/1.2.0 libidn/0.4.3 +Host: data.from.server.requiring.digest.hohoho.com +Pragma: no-cache +Accept: */* + +GET http://data.from.server.requiring.digest.hohoho.com/167 HTTP/1.1 +Proxy-Authorization: Basic Zm9vOmJhcg== +Authorization: Digest username="digest", realm="weirdorealm", nonce="12345", uri="/167", response="13c7c02a252cbe1c46d8669898a3be26" +User-Agent: curl/7.12.0-CVS (i686-pc-linux-gnu) libcurl/7.12.0-CVS OpenSSL/0.9.6b zlib/1.1.4 c-ares/1.2.0 libidn/0.4.3 +Host: data.from.server.requiring.digest.hohoho.com +Pragma: no-cache +Accept: */* + + + diff --git a/tests/data/test168 b/tests/data/test168 new file mode 100644 index 000000000..e726b5101 --- /dev/null +++ b/tests/data/test168 @@ -0,0 +1,82 @@ +# Server-side + + +# this is returned first since we get no proxy-auth + +HTTP/1.1 407 Authorization Required to proxy me my dear swsclose +Proxy-Authenticate: Digest realm="weirdorealm", nonce="12345" + +And you should ignore this data. + + +# then this is returned since we get no server-auth + +HTTP/1.1 401 Authorization to the remote host as well swsbounce swsclose +WWW-Authenticate: Digest realm="realmweirdo", nonce="123456" + +you should ignore this data too + + + +HTTP/1.1 200 OK swsclose +Server: no + +Nice auth sir! + + + +HTTP/1.1 407 Authorization Required to proxy me my dear swsclose +Proxy-Authenticate: Digest realm="weirdorealm", nonce="12345" + +HTTP/1.1 401 Authorization to the remote host as well swsbounce swsclose +WWW-Authenticate: Digest realm="realmweirdo", nonce="123456" + +HTTP/1.1 200 OK swsclose +Server: no + +Nice auth sir! + + + +# Client-side + + +http + + +HTTP with proxy-requiring-Digest to site-requiring-Digest + + +http://data.from.server.requiring.digest.hohoho.com/168 --proxy http://%HOSTIP:%HOSTPORT --proxy-user foo:bar --proxy-digest --digest --user digest:alot + + + +# Verify data after the test has been "shot" + + +^User-Agent: curl/.* + + +GET http://data.from.server.requiring.digest.hohoho.com/168 HTTP/1.1 +User-Agent: curl/7.12.0-CVS (i686-pc-linux-gnu) libcurl/7.12.0-CVS OpenSSL/0.9.6b zlib/1.1.4 c-ares/1.2.0 libidn/0.4.3 +Host: data.from.server.requiring.digest.hohoho.com +Pragma: no-cache +Accept: */* + +GET http://data.from.server.requiring.digest.hohoho.com/168 HTTP/1.1 +Proxy-Authorization: Digest username="digest", realm="weirdorealm", nonce="12345", uri="/168", response="4e79e4fc104ef1f16ab4567e1ad4dede" +User-Agent: curl/7.12.0-CVS (i686-pc-linux-gnu) libcurl/7.12.0-CVS OpenSSL/0.9.6b zlib/1.1.4 c-ares/1.2.0 libidn/0.4.3 +Host: data.from.server.requiring.digest.hohoho.com +Pragma: no-cache +Accept: */* + +GET http://data.from.server.requiring.digest.hohoho.com/168 HTTP/1.1 +Proxy-Authorization: Digest username="digest", realm="weirdorealm", nonce="12345", uri="/168", response="4e79e4fc104ef1f16ab4567e1ad4dede" +Authorization: Digest username="digest", realm="realmweirdo", nonce="123456", uri="/168", response="ca87f2d768a231e2d637a55698d5c416" +User-Agent: curl/7.12.0-CVS (i686-pc-linux-gnu) libcurl/7.12.0-CVS OpenSSL/0.9.6b ipv6 zlib/1.1.4 GSS libidn/0.4.3 +Host: data.from.server.requiring.digest.hohoho.com +Pragma: no-cache +Accept: */* + + + diff --git a/tests/data/test169 b/tests/data/test169 new file mode 100644 index 000000000..ddd8e4ce3 --- /dev/null +++ b/tests/data/test169 @@ -0,0 +1,107 @@ +# Server-side + + +# this is returned first since we get no proxy-auth + +HTTP/1.1 407 Authorization Required to proxy me my dear swsclose +Proxy-Authenticate: NTLM + +And you should ignore this data. + + +# then this is returned since we get no server-auth + +HTTP/1.1 200 Authorizated fine +Content-Length: 27 + +Welcome to the end station + + + +HTTP/1.1 407 NTLM type-1 received sending back type-2 +Server: Microsoft-IIS/5.0 +Content-Length: 34 +Content-Type: text/html; charset=iso-8859-1 +Proxy-Authenticate: NTLM TlRMTVNTUAACAAAAAgACADAAAAAGgoEAc51AYVDgyNcAAAAAAAAAAG4AbgAyAAAAQ0MCAAQAQwBDAAEAEgBFAEwASQBTAEEAQgBFAFQASAAEABgAYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAwAsAGUAbABpAHMAYQBiAGUAdABoAC4AYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAAAAAA== + +This is not the real page either! + + +# This is supposed to be returned when the server gets the second +# Authorization: NTLM line passed-in from the client + +HTTP/1.1 401 You now need to authenticate with the host +Server: Microsoft-IIS/5.0 +WWW-Authenticate: Digest realm="r e a l m", nonce="abcdef" +Content-Length: 40 +Content-Type: text/html; charset=iso-8859-1 + +We have not authenticated with the server yet + + + +HTTP/1.1 407 NTLM type-1 received sending back type-2 +Server: Microsoft-IIS/5.0 +Content-Length: 34 +Content-Type: text/html; charset=iso-8859-1 +Proxy-Authenticate: NTLM TlRMTVNTUAACAAAAAgACADAAAAAGgoEAc51AYVDgyNcAAAAAAAAAAG4AbgAyAAAAQ0MCAAQAQwBDAAEAEgBFAEwASQBTAEEAQgBFAFQASAAEABgAYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAwAsAGUAbABpAHMAYQBiAGUAdABoAC4AYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAAAAAA== + +HTTP/1.1 401 You now need to authenticate with the host +Server: Microsoft-IIS/5.0 +WWW-Authenticate: Digest realm="r e a l m", nonce="abcdef" +Content-Length: 40 +Content-Type: text/html; charset=iso-8859-1 + +HTTP/1.1 200 Authorizated fine +Content-Length: 27 + +Welcome to the end station + + + +# Client-side + + +http + +# NTLM only works if we are built with SSL + +SSL + + +HTTP with proxy-requiring-NTLM to site-requiring-Digest + + +http://data.from.server.requiring.digest.hohoho.com/169 --proxy http://%HOSTIP:%HOSTPORT --proxy-user foo:bar --proxy-ntlm --digest --user digest:alot + + + +# Verify data after the test has been "shot" + + +^User-Agent: curl/.* + + +GET http://data.from.server.requiring.digest.hohoho.com/169 HTTP/1.1 +Proxy-Authorization: NTLM TlRMTVNTUAABAAAAAgIAAAAAAAAgAAAAAAAAACAAAAA= +User-Agent: curl/7.12.0-CVS (i686-pc-linux-gnu) libcurl/7.12.0-CVS OpenSSL/0.9.6b ipv6 zlib/1.1.4 GSS libidn/0.4.3 +Host: data.from.server.requiring.digest.hohoho.com +Pragma: no-cache +Accept: */* + +GET http://data.from.server.requiring.digest.hohoho.com/169 HTTP/1.1 +Proxy-Authorization: NTLM TlRMTVNTUAADAAAAGAAYAEMAAAAYABgAWwAAAAAAAABAAAAAAwADAEAAAAAAAAAAQwAAAAAAAABzAAAAAYIAAGZvb4P6B+XVQ6vQsx3DfDXUVhd9436GAxPu0IYcl2Z7LxHmNeOAWQ+vxUmhuCFJBUgXCQ== +User-Agent: curl/7.12.0-CVS (i686-pc-linux-gnu) libcurl/7.12.0-CVS OpenSSL/0.9.6b ipv6 zlib/1.1.4 GSS libidn/0.4.3 +Host: data.from.server.requiring.digest.hohoho.com +Pragma: no-cache +Accept: */* + +GET http://data.from.server.requiring.digest.hohoho.com/169 HTTP/1.1 +Authorization: Digest username="digest", realm="r e a l m", nonce="abcdef", uri="/169", response="95d48591985a03c4b49cb962aa7bd3e6" +User-Agent: curl/7.12.0-CVS (i686-pc-linux-gnu) libcurl/7.12.0-CVS OpenSSL/0.9.6b ipv6 zlib/1.1.4 GSS libidn/0.4.3 +Host: data.from.server.requiring.digest.hohoho.com +Pragma: no-cache +Accept: */* + + + diff --git a/tests/data/test503 b/tests/data/test503 index 24d55dc55..9f26e2927 100644 --- a/tests/data/test503 +++ b/tests/data/test503 @@ -49,7 +49,7 @@ moo CONNECT 127.0.0.1:8433 HTTP/1.0 -Proxy-authorization: Basic dGVzdDppbmc= +Proxy-Authorization: Basic dGVzdDppbmc= GET /503 HTTP/1.1 Authorization: Basic dGVzdDppbmc= diff --git a/tests/data/test63 b/tests/data/test63 index 3806237e9..ecca6b256 100644 --- a/tests/data/test63 +++ b/tests/data/test63 @@ -32,7 +32,7 @@ http://we.want.that.site.com/63 GET http://we.want.that.site.com/63 HTTP/1.1 -Proxy-authorization: Basic ZmFrZTp1c2Vy +Proxy-Authorization: Basic ZmFrZTp1c2Vy Host: we.want.that.site.com Pragma: no-cache Accept: */* diff --git a/tests/data/test80 b/tests/data/test80 index 21e9bbdac..dd4f0605c 100644 --- a/tests/data/test80 +++ b/tests/data/test80 @@ -45,7 +45,7 @@ http://%HOSTIP:%HOSTPORT/we/want/that/page/80 -p -x %HOSTIP:%HOSTPORT --user iam CONNECT 127.0.0.1:8999 HTTP/1.0 -Proxy-authorization: Basic eW91YXJlOnlvdXJzZWxm +Proxy-Authorization: Basic eW91YXJlOnlvdXJzZWxm User-Agent: curl/7.10.7-pre2 (i686-pc-linux-gnu) libcurl/7.10.7-pre2 OpenSSL/0.9.7a zlib/1.1.3 GET /we/want/that/page/80 HTTP/1.1 diff --git a/tests/data/test82 b/tests/data/test82 index fc4e490bd..7b49f89f2 100644 --- a/tests/data/test82 +++ b/tests/data/test82 @@ -35,7 +35,7 @@ http://%HOSTIP:%HOSTPORT/82 --proxy-user testuser:testpass -x http://%HOSTIP:%HO GET http://127.0.0.1:8999/82 HTTP/1.1 -Proxy-authorization: Basic dGVzdHVzZXI6dGVzdHBhc3M= +Proxy-Authorization: Basic dGVzdHVzZXI6dGVzdHBhc3M= User-Agent: curl/7.10.6-pre1 (i686-pc-linux-gnu) libcurl/7.10.6-pre1 OpenSSL/0.9.7a ipv6 zlib/1.1.3 Host: 127.0.0.1:8999 Pragma: no-cache diff --git a/tests/data/test85 b/tests/data/test85 index a1fe04365..b5c6e96de 100644 --- a/tests/data/test85 +++ b/tests/data/test85 @@ -34,7 +34,7 @@ http://%HOSTIP:%HOSTPORT/we/want/that/page/85 -x %HOSTIP:%HOSTPORT --user iam:my GET http://127.0.0.1:8999/we/want/that/page/85 HTTP/1.1 -Proxy-authorization: Basic dGVzdGluZzp0aGlz +Proxy-Authorization: Basic dGVzdGluZzp0aGlz Authorization: Basic aWFtOm15c2VsZg== User-Agent: curl/7.10.7-pre2 (i686-pc-linux-gnu) libcurl/7.10.7-pre2 OpenSSL/0.9.7a zlib/1.1.3 Host: 127.0.0.1:8999