General HTTP authentication cleanup and fixes

This commit is contained in:
Daniel Stenberg 2004-05-04 07:52:53 +00:00
parent e7ee1ccf45
commit fc6eff13b5
20 changed files with 636 additions and 309 deletions

13
CHANGES
View File

@ -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.

View File

@ -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

View File

@ -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) */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 <curl/mprintf.h>
@ -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;
}

View File

@ -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! */

View File

@ -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) ||

View File

@ -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

View File

@ -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

View File

@ -32,7 +32,7 @@ HTTP with proxy athorization
</strip>
<protocol>
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: */*

62
tests/data/test167 Normal file
View File

@ -0,0 +1,62 @@
# Server-side
<reply>
<data>
HTTP/1.1 401 Authorization Required swsclose
WWW-Authenticate: Digest realm="weirdorealm", nonce="12345"
</data>
<data1000>
HTTP/1.1 200 OK swsclose
Server: no
Nice auth sir!
</data1000>
<datacheck>
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!
</datacheck>
</reply>
# Client-side
<client>
<server>
http
</server>
<name>
HTTP with proxy-requiring-Basic to site-requiring-Digest
</name>
<command>
http://data.from.server.requiring.digest.hohoho.com/167 --proxy http://%HOSTIP:%HOSTPORT --proxy-user foo:bar --digest --user digest:alot
</command>
</test>
# Verify data after the test has been "shot"
<verify>
<strip>
^User-Agent: curl/.*
</strip>
<protocol>
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: */*
</protocol>
</verify>

82
tests/data/test168 Normal file
View File

@ -0,0 +1,82 @@
# Server-side
<reply>
# this is returned first since we get no proxy-auth
<data>
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.
</data>
# then this is returned since we get no server-auth
<data1000>
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
</data1000>
<data1001>
HTTP/1.1 200 OK swsclose
Server: no
Nice auth sir!
</data1001>
<datacheck>
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!
</datacheck>
</reply>
# Client-side
<client>
<server>
http
</server>
<name>
HTTP with proxy-requiring-Digest to site-requiring-Digest
</name>
<command>
http://data.from.server.requiring.digest.hohoho.com/168 --proxy http://%HOSTIP:%HOSTPORT --proxy-user foo:bar --proxy-digest --digest --user digest:alot
</command>
</test>
# Verify data after the test has been "shot"
<verify>
<strip>
^User-Agent: curl/.*
</strip>
<protocol>
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: */*
</protocol>
</verify>

107
tests/data/test169 Normal file
View File

@ -0,0 +1,107 @@
# Server-side
<reply>
# this is returned first since we get no proxy-auth
<data>
HTTP/1.1 407 Authorization Required to proxy me my dear swsclose
Proxy-Authenticate: NTLM
And you should ignore this data.
</data>
# then this is returned since we get no server-auth
<data1000>
HTTP/1.1 200 Authorizated fine
Content-Length: 27
Welcome to the end station
</data1000>
<data1001>
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!
</data1001>
# This is supposed to be returned when the server gets the second
# Authorization: NTLM line passed-in from the client
<data1002>
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
</data1002>
<datacheck>
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
</datacheck>
</reply>
# Client-side
<client>
<server>
http
</server>
# NTLM only works if we are built with SSL
<features>
SSL
</features>
<name>
HTTP with proxy-requiring-NTLM to site-requiring-Digest
</name>
<command>
http://data.from.server.requiring.digest.hohoho.com/169 --proxy http://%HOSTIP:%HOSTPORT --proxy-user foo:bar --proxy-ntlm --digest --user digest:alot
</command>
</test>
# Verify data after the test has been "shot"
<verify>
<strip>
^User-Agent: curl/.*
</strip>
<protocol>
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: */*
</protocol>
</verify>

View File

@ -49,7 +49,7 @@ moo
<verify>
<protocol>
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=

View File

@ -32,7 +32,7 @@ http://we.want.that.site.com/63
</strip>
<protocol>
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: */*

View File

@ -45,7 +45,7 @@ http://%HOSTIP:%HOSTPORT/we/want/that/page/80 -p -x %HOSTIP:%HOSTPORT --user iam
</strip>
<protocol>
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

View File

@ -35,7 +35,7 @@ http://%HOSTIP:%HOSTPORT/82 --proxy-user testuser:testpass -x http://%HOSTIP:%HO
</strip>
<protocol>
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

View File

@ -34,7 +34,7 @@ http://%HOSTIP:%HOSTPORT/we/want/that/page/85 -x %HOSTIP:%HOSTPORT --user iam:my
</strip>
<protocol>
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