From ad21f8e2b774367156fbe71f4318b5646059b724 Mon Sep 17 00:00:00 2001 From: Micah Cowan Date: Sat, 26 Apr 2008 21:28:35 -0700 Subject: [PATCH] Add fix from eleven, for doing HTTPS auth over a proxy (in eleven, changeset 883844a4ac33). --- src/ChangeLog | 6 ++ src/http.c | 70 ++++++++++----------- tests/ChangeLog | 8 ++- tests/Makefile.am | 1 + tests/Test-proxied-https-auth.px | 101 +++++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+), 36 deletions(-) create mode 100755 tests/Test-proxied-https-auth.px diff --git a/src/ChangeLog b/src/ChangeLog index 5e3e6312..2f8464bd 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2008-04-26 Micah Cowan + + * http.c (gethttp): Move proxy CONNECT handling to below the + retry_with_auth label, to deal with properly reconnecting to + proxies when we need to authenticate. + 2008-04-25 Micah Cowan * Makefile.am: -I foo -> -Ifoo. diff --git a/src/http.c b/src/http.c index a795bc5e..b304af76 100644 --- a/src/http.c +++ b/src/http.c @@ -1497,41 +1497,6 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy) basic_auth_finished = maybe_send_basic_creds(u->host, user, passwd, req); } - proxyauth = NULL; - if (proxy) - { - char *proxy_user, *proxy_passwd; - /* For normal username and password, URL components override - command-line/wgetrc parameters. With proxy - authentication, it's the reverse, because proxy URLs are - normally the "permanent" ones, so command-line args - should take precedence. */ - if (opt.proxy_user && opt.proxy_passwd) - { - proxy_user = opt.proxy_user; - proxy_passwd = opt.proxy_passwd; - } - else - { - proxy_user = proxy->user; - proxy_passwd = proxy->passwd; - } - /* #### This does not appear right. Can't the proxy request, - say, `Digest' authentication? */ - if (proxy_user && proxy_passwd) - proxyauth = basic_authentication_encode (proxy_user, proxy_passwd); - - /* If we're using a proxy, we will be connecting to the proxy - server. */ - conn = proxy; - - /* Proxy authorization over SSL is handled below. */ -#ifdef HAVE_SSL - if (u->scheme != SCHEME_HTTPS) -#endif - request_set_header (req, "Proxy-Authorization", proxyauth, rel_value); - } - /* Generate the Host header, HOST:PORT. Take into account that: - Broken server-side software often doesn't recognize the PORT @@ -1602,6 +1567,41 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy) without authorization header fails. (Expected to happen at least for the Digest authorization scheme.) */ + proxyauth = NULL; + if (proxy) + { + char *proxy_user, *proxy_passwd; + /* For normal username and password, URL components override + command-line/wgetrc parameters. With proxy + authentication, it's the reverse, because proxy URLs are + normally the "permanent" ones, so command-line args + should take precedence. */ + if (opt.proxy_user && opt.proxy_passwd) + { + proxy_user = opt.proxy_user; + proxy_passwd = opt.proxy_passwd; + } + else + { + proxy_user = proxy->user; + proxy_passwd = proxy->passwd; + } + /* #### This does not appear right. Can't the proxy request, + say, `Digest' authentication? */ + if (proxy_user && proxy_passwd) + proxyauth = basic_authentication_encode (proxy_user, proxy_passwd); + + /* If we're using a proxy, we will be connecting to the proxy + server. */ + conn = proxy; + + /* Proxy authorization over SSL is handled below. */ +#ifdef HAVE_SSL + if (u->scheme != SCHEME_HTTPS) +#endif + request_set_header (req, "Proxy-Authorization", proxyauth, rel_value); + } + keep_alive = false; /* Establish the connection. */ diff --git a/tests/ChangeLog b/tests/ChangeLog index e6972b50..f485f93c 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,6 +1,12 @@ +2008-04-26 Micah Cowan + + * Makefile.am, Test-proxied-https-auth.px: Added a test for + accessing password-protected HTTPS URLs through a proxy (via + CONNECT). + 2008-04-10 Micah Cowan - * Makefile.in, Test-proxy-auth-basic.px: Added a test for + * Makefile.am, Test-proxy-auth-basic.px: Added a test for accessing password-protected URLs through a proxy. 2008-01-25 Micah Cowan diff --git a/tests/Makefile.am b/tests/Makefile.am index 224cb9cc..fefdbf1d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -46,6 +46,7 @@ run-unit-tests: unit-tests$(EXEEXT) ./unit-tests$(EXEEXT) run-px-tests: WgetTest.pm + $(PERLRUN) $(srcdir)/Test-proxied-https-auth.px && echo && echo $(PERLRUN) $(srcdir)/Test-proxy-auth-basic.px && echo && echo $(PERLRUN) $(srcdir)/Test-auth-basic.px && echo && echo $(PERLRUN) $(srcdir)/Test-c-full.px && echo && echo diff --git a/tests/Test-proxied-https-auth.px b/tests/Test-proxied-https-auth.px new file mode 100755 index 00000000..22606589 --- /dev/null +++ b/tests/Test-proxied-https-auth.px @@ -0,0 +1,101 @@ +#!/usr/bin/perl +use warnings; +use strict; + +use WgetTest; # For $WGETPATH. +use HTTP::Daemon; +use HTTP::Request; +use IO::Socket::SSL 'debug4'; + +sub get_request { + my $conn = shift; + my $content = ''; + my $line; + + while (defined ($line = <$conn>)) { + $content .= $line; + last if $line eq "\r\n"; + } + + my $rqst = HTTP::Request->parse($content) + or die "Couldn't parse request:\n$content\n"; + + return $rqst; +} + +sub do_server { + my $alrm = alarm 10; + + my $s = HTTP::Daemon->new (LocalAddr => 'localhost', + LocalPort => '8080', + ReuseAddr => 1) or die "Cannot create server!!!"; + my $conn; + my $rqst; + my $rspn; + for my $expect_inner_auth (0, 1) { + $conn = $s->accept; + $rqst = $conn->get_request; + + # TODO: expect no auth the first time, request it, expect it the second + # time. + + die "Method not CONNECT\n" if ($rqst->method ne 'CONNECT'); + $rspn = HTTP::Response->new(200, 'OK'); + $conn->send_response($rspn); + + $conn = IO::Socket::SSL->new_from_fd($conn->fileno, SSL_server => 1, + SSL_passwd_cb => sub { return "Hello"; }) + or die "Couldn't initiate SSL"; + + $rqst = &get_request($conn) + or die "Didn't get proxied request\n"; + + unless ($expect_inner_auth) { + die "Early proxied auth\n" if $rqst->header('Authorization'); + + # TODO: handle non-persistent connection here. + $rspn = HTTP::Response->new(401, 'Unauthorized', [ + 'WWW-Authenticate' => 'Basic realm="gondor"', + Connection => 'close' + ]); + $rspn->protocol('HTTP/1.0'); + print $rspn->as_string; + print $conn $rspn->as_string; + } else { + die "No proxied auth\n" unless $rqst->header('Authorization'); + + $rspn = HTTP::Response->new(200, 'OK', [ + 'Content-Type' => 'text/plain', + 'Connection' => 'close', + ], "foobarbaz\n"); + print $conn $rspn->as_string; + } + $conn->close; + } + undef $conn; + undef $s; + alarm $alrm; +} + +sub fork_server { + my $pid = fork; + die "Couldn't fork" if ($pid < 0); + return $pid if $pid; + + &do_server; + exit; +} + +system ('rm -f needs-auth.txt'); +&fork_server; + +sleep 1; +my $cmdline = $WgetTest::WGETPATH . " --user=fiddle-dee-dee" + . " --password=Dodgson -e https_proxy=localhost:8080" + . " --no-check-certificate" + . " https://no.such.domain/needs-auth.txt"; + +my $code = system($cmdline); + +warn "Got code: $code\n" if $code; +exit $code; -- 2.39.2