From: Henrik Nordstrom Date: Wed, 26 Aug 2009 11:43:52 +0000 (+0200) Subject: Rework the auth forwarding special cases X-Git-Tag: SQUID_3_2_0_1~759^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ee0b94f4b7d2c3281a98eff2706f8e32d812bee3;p=thirdparty%2Fsquid.git Rework the auth forwarding special cases The auth forwarding special cases had grown a bit hairy with a lot of duplicated code between WWW-Auth and Proxy-Auth and far from trivial to follow code logics. This change breaks this logic out to a separate function shared in both modes, selecing mode based on type of peer. Also moves PROXYPASS back into the land of undocumented features. This is a feature which most would only get confused by and which can cause significant security issues if used wrongly. --- diff --git a/src/cf.data.pre b/src/cf.data.pre index 382208cc43..a5291db557 100644 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@ -1797,30 +1797,14 @@ DOC_START Note: This will pass any form of authentication but only Basic auth will work through a proxy unless the connection-auth options are also used. - - login=PROXYPASS - Send login details received from client to this peer. - Only WWW-Authorization headers are passed to the peer. - If the 'originserver' option is also used this will - convert Proxy-Authorization: to WWW-Authorization: before - relaying. The header content is not altered. - - Authentication is not required by Squid for this to work - however it should be noted that without it somewhere down - the proxy chain there may be no Proxy-Authorization: - header to convert. - - Note: This will pass any form of authentication but - only Basic auth will work through a proxy unless the - connection-auth options are also used. - + login=PASS Send login details received from client to this peer. Authentication is not required by this option. If there are no client-provided authentication headers to pass on, but username and password are available - from either proxy login or an external ACL user= and - password= result tags they may be sent instead. + from an external ACL user= and password= result tags + they may be sent instead. Note: To combine this with proxy_auth both proxies must share the same user database as HTTP only allows for diff --git a/src/http.cc b/src/http.cc index 9f51b1ea9b..198c3fabcc 100644 --- a/src/http.cc +++ b/src/http.cc @@ -1446,6 +1446,75 @@ HttpStateData::doneWithServer() const return fd < 0; } + +/* + * Fixup authentication request headers for special cases + */ +static void +httpFixupAuthentication(HttpRequest * request, HttpRequest * orig_request, const HttpHeader * hdr_in, HttpHeader * hdr_out, http_state_flags flags) +{ + http_hdr_type header = flags.originpeer ? HDR_AUTHORIZATION : HDR_PROXY_AUTHORIZATION; + + /* Nothing to do unless we are forwarding to a peer */ + if (!request->flags.proxying) + return; + + /* Needs to be explicitly enabled */ + return; + + /* Maybe already dealt with? */ + if (hdr_out->has(header)) + return; + + /* Nothing to do here for PASSTHRU */ + if (strcmp(orig_request->peer_login, "PASSTHRU") == 0) + return; + + /* PROXYPASS is a special case, single-signon to servers with the proxy password (basic only) */ + if (flags.originpeer && strcmp(orig_request->peer_login, "PROXYPASS") == 0 && hdr_in->has(HDR_PROXY_AUTHORIZATION)) { + const char *auth = hdr_in->getStr(HDR_PROXY_AUTHORIZATION); + + if (auth && strncasecmp(auth, "basic ", 6) == 0) { + hdr_out->putStr(header, auth); + return; + } + } + + /* Special mode to pass the username to the upstream cache */ + if (*orig_request->peer_login == '*') { + char loginbuf[256]; + const char *username = "-"; + + if (orig_request->extacl_user.size()) + username = orig_request->extacl_user.termedBuf(); + else if (orig_request->auth_user_request) + username = orig_request->auth_user_request->username(); + + snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1); + + httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s", + base64_encode(loginbuf)); + return; + } + + /* external_acl provided credentials */ + if (orig_request->extacl_user.size() && orig_request->extacl_passwd.size() && + (strcmp(orig_request->peer_login, "PASS") == 0 || + strcmp(orig_request->peer_login, "PROXYPASS"))) { + char loginbuf[256]; + snprintf(loginbuf, sizeof(loginbuf), SQUIDSTRINGPH ":" SQUIDSTRINGPH, + SQUIDSTRINGPRINT(orig_request->extacl_user), + SQUIDSTRINGPRINT(orig_request->extacl_passwd)); + httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s", + base64_encode(loginbuf)); + return; + } + + httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s", + base64_encode(orig_request->peer_login)); + return; +} + /* * build request headers and append them to a given MemBuf * used by buildRequestPrefix() @@ -1576,87 +1645,11 @@ HttpStateData::httpBuildRequestHeader(HttpRequest * request, } } - /* append Proxy-Authorization if configured for peer, and proxying */ - if (request->flags.proxying && orig_request->peer_login && - !hdr_out->has(HDR_PROXY_AUTHORIZATION)) { - if (*orig_request->peer_login == '*') { - /* Special mode, to pass the username to the upstream cache */ - char loginbuf[256]; - const char *username = "-"; - - if (orig_request->extacl_user.size()) - username = orig_request->extacl_user.termedBuf(); - else if (orig_request->auth_user_request) - username = orig_request->auth_user_request->username(); - - snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1); - - httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s", - base64_encode(loginbuf)); - } else if (strcmp(orig_request->peer_login, "PASS") == 0) { - if (orig_request->extacl_user.size() && orig_request->extacl_passwd.size()) { - char loginbuf[256]; - snprintf(loginbuf, sizeof(loginbuf), SQUIDSTRINGPH ":" SQUIDSTRINGPH, - SQUIDSTRINGPRINT(orig_request->extacl_user), - SQUIDSTRINGPRINT(orig_request->extacl_passwd)); - httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s", - base64_encode(loginbuf)); - } - } else if (strcmp(orig_request->peer_login, "PROXYPASS") == 0) { - /* Nothing to do */ - } else if (strcmp(orig_request->peer_login, "PASSTHRU") == 0) { - /* Nothing to do (yet) */ - } else { - httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s", - base64_encode(orig_request->peer_login)); - } - } - - /* append WWW-Authorization if configured for peer */ - if (flags.originpeer && orig_request->peer_login && - !hdr_out->has(HDR_AUTHORIZATION)) { - if (strcmp(orig_request->peer_login, "PASS") == 0) { - /* No credentials to forward.. (should have been done above if available) */ - } else if (strcmp(orig_request->peer_login, "PASSTHRU") == 0) { - /* Nothing to do (yet) */ - } else if (strcmp(orig_request->peer_login, "PROXYPASS") == 0) { - /* Special mode, convert proxy authentication to WWW authentication - * (also applies to authentication provided by external acl) - */ - const char *auth = hdr_in->getStr(HDR_PROXY_AUTHORIZATION); - - if (auth && strncasecmp(auth, "basic ", 6) == 0) { - hdr_out->putStr(HDR_AUTHORIZATION, auth); - } else if (orig_request->extacl_user.size() && orig_request->extacl_passwd.size()) { - char loginbuf[256]; - snprintf(loginbuf, sizeof(loginbuf), SQUIDSTRINGPH ":" SQUIDSTRINGPH, - SQUIDSTRINGPRINT(orig_request->extacl_user), - SQUIDSTRINGPRINT(orig_request->extacl_passwd)); - httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s", - base64_encode(loginbuf)); - } - } else if (*orig_request->peer_login == '*') { - /* Special mode, to pass the username to the upstream cache */ - char loginbuf[256]; - const char *username = "-"; + /* Fixup (Proxy-)Authorization special cases. Plain relaying dealt with above */ + httpFixupAuthentication(request, orig_request, hdr_in, hdr_out, flags); - if (orig_request->auth_user_request) - username = orig_request->auth_user_request->username(); - else if (orig_request->extacl_user.size()) - username = orig_request->extacl_user.termedBuf(); - - snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1); - - httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s", - base64_encode(loginbuf)); - } else { - /* Fixed login string */ - httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s", - base64_encode(orig_request->peer_login)); - } - } - - /* append Cache-Control, add max-age if not there already */ { + /* append Cache-Control, add max-age if not there already */ + { HttpHdrCc *cc = hdr_in->getCc(); if (!cc) @@ -1727,9 +1720,9 @@ copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, co * Only pass on proxy authentication to peers for which * authentication forwarding is explicitly enabled */ - if (flags.proxying && orig_request->peer_login && - (strcmp(orig_request->peer_login, "PASS") == 0 || - strcmp(orig_request->peer_login, "PASSTHRU") == 0)) { + if (!flags.originpeer && flags.proxying && orig_request->peer_login && + (strcmp(orig_request->peer_login, "PASS") == 0 || + strcmp(orig_request->peer_login, "PASSTHRU") == 0)) { hdr_out->addEntry(e->clone()); } break; @@ -1756,8 +1749,7 @@ copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, co hdr_out->addEntry(e->clone()); } else { /** \note In accelerators, only forward authentication if enabled - * by login=PASS or login=PROXYPASS or login=PASSTHRU - * (see also below for proxy->server authentication) + * (see also httpFixupAuthentication for special cases) */ if (orig_request->peer_login && (strcmp(orig_request->peer_login, "PASS") == 0 ||