Author: Dan Searle Pass user credentials obtained from external ACLs to the ICAP service using Proxy-Authorization and X-Client-Username ICAP headers. Also the credentials passed the eCAP services. === modified file 'src/adaptation/ecap/XactionRep.cc' --- src/adaptation/ecap/XactionRep.cc 2012-03-04 18:50:13 +0000 +++ src/adaptation/ecap/XactionRep.cc 2012-04-25 16:33:05 +0000 @@ -127,40 +127,43 @@ client_addr = request->client_addr; if (!client_addr.IsAnyAddr() && !client_addr.IsNoAddr()) { char ntoabuf[MAX_IPSTRLEN] = ""; client_addr.NtoA(ntoabuf,MAX_IPSTRLEN); return libecap::Area::FromTempBuffer(ntoabuf, strlen(ntoabuf)); } } return libecap::Area(); } const libecap::Area Adaptation::Ecap::XactionRep::usernameValue() const { #if USE_AUTH const HttpRequest *request = dynamic_cast(theCauseRep ? theCauseRep->raw().header : theVirginRep.raw().header); Must(request); if (request->auth_user_request != NULL) { if (char const *name = request->auth_user_request->username()) return libecap::Area::FromTempBuffer(name, strlen(name)); + else if (request->extacl_user.defined() && request->extacl_user.size()) + return libecap::Area::FromTempBuffer(request->extacl_user.rawBuf(), + request->extacl_user.size()); } #endif return libecap::Area(); } const libecap::Area Adaptation::Ecap::XactionRep::masterxSharedValue(const libecap::Name &name) const { const HttpRequest *request = dynamic_cast(theCauseRep ? theCauseRep->raw().header : theVirginRep.raw().header); Must(request); if (name.known()) { // must check to avoid empty names matching unset cfg Adaptation::History::Pointer ah = request->adaptHistory(false); if (ah != NULL) { String name, value; if (ah->getXxRecord(name, value)) return libecap::Area::FromTempBuffer(value.rawBuf(), value.size()); } } return libecap::Area(); === modified file 'src/adaptation/icap/ModXact.cc' --- src/adaptation/icap/ModXact.cc 2012-01-20 18:55:04 +0000 +++ src/adaptation/icap/ModXact.cc 2012-04-25 17:05:37 +0000 @@ -1315,54 +1315,60 @@ } prepareLogWithRequestDetails(request_, &al); Xaction::finalizeLogInfo(); } void Adaptation::Icap::ModXact::makeRequestHeaders(MemBuf &buf) { char ntoabuf[MAX_IPSTRLEN]; /* * XXX These should use HttpHdr interfaces instead of Printfs */ const Adaptation::ServiceConfig &s = service().cfg(); buf.Printf("%s " SQUIDSTRINGPH " ICAP/1.0\r\n", s.methodStr(), SQUIDSTRINGPRINT(s.uri)); buf.Printf("Host: " SQUIDSTRINGPH ":%d\r\n", SQUIDSTRINGPRINT(s.host), s.port); buf.Printf("Date: %s\r\n", mkrfc1123(squid_curtime)); if (!TheConfig.reuse_connections) buf.Printf("Connection: close\r\n"); + const HttpRequest *request = &virginRequest(); + // we must forward "Proxy-Authenticate" and "Proxy-Authorization" // as ICAP headers. if (virgin.header->header.has(HDR_PROXY_AUTHENTICATE)) { String vh=virgin.header->header.getByName("Proxy-Authenticate"); buf.Printf("Proxy-Authenticate: " SQUIDSTRINGPH "\r\n",SQUIDSTRINGPRINT(vh)); } if (virgin.header->header.has(HDR_PROXY_AUTHORIZATION)) { String vh=virgin.header->header.getByName("Proxy-Authorization"); buf.Printf("Proxy-Authorization: " SQUIDSTRINGPH "\r\n", SQUIDSTRINGPRINT(vh)); + } else if (request->extacl_user.defined() && request->extacl_user.size() && request->extacl_passwd.defined() && request->extacl_passwd.size()) { + char loginbuf[256]; + snprintf(loginbuf, sizeof(loginbuf), SQUIDSTRINGPH ":" SQUIDSTRINGPH, + SQUIDSTRINGPRINT(request->extacl_user), + SQUIDSTRINGPRINT(request->extacl_passwd)); + buf.Printf("Proxy-Authorization: Basic %s\r\n", old_base64_encode(loginbuf)); } - const HttpRequest *request = &virginRequest(); - // share the cross-transactional database records if needed if (Adaptation::Config::masterx_shared_name) { Adaptation::History::Pointer ah = request->adaptHistory(false); if (ah != NULL) { String name, value; if (ah->getXxRecord(name, value)) { buf.Printf(SQUIDSTRINGPH ": " SQUIDSTRINGPH "\r\n", SQUIDSTRINGPRINT(name), SQUIDSTRINGPRINT(value)); } } } buf.Printf("Encapsulated: "); MemBuf httpBuf; httpBuf.init(); // build HTTP request header, if any @@ -1471,40 +1477,43 @@ else if (allow204out) allowHeader = "Allow: 204\r\n"; else if (allow206) allowHeader = "Allow: 206\r\n"; if (allowHeader) { // may be nil if only allow204in is true buf.append(allowHeader, strlen(allowHeader)); debugs(93,5, HERE << "Will write " << allowHeader); } } void Adaptation::Icap::ModXact::makeUsernameHeader(const HttpRequest *request, MemBuf &buf) { #if USE_AUTH if (request->auth_user_request != NULL) { char const *name = request->auth_user_request->username(); if (name) { const char *value = TheConfig.client_username_encode ? old_base64_encode(name) : name; buf.Printf("%s: %s\r\n", TheConfig.client_username_header, value); } + } else if (request->extacl_user.defined() && request->extacl_user.size()) { + const char *value = TheConfig.client_username_encode ? old_base64_encode(request->extacl_user.termedBuf()) : request->extacl_user.termedBuf(); + buf.Printf("%s: %s\r\n", TheConfig.client_username_header, value); } #endif } void Adaptation::Icap::ModXact::encapsulateHead(MemBuf &icapBuf, const char *section, MemBuf &httpBuf, const HttpMsg *head) { // update ICAP header icapBuf.Printf("%s=%d, ", section, (int) httpBuf.contentSize()); // begin cloning HttpMsg::Pointer headClone; if (const HttpRequest* old_request = dynamic_cast(head)) { HttpRequest::Pointer new_request(new HttpRequest); Must(old_request->canonical); urlParse(old_request->method, old_request->canonical, new_request); new_request->http_ver = old_request->http_ver; headClone = new_request; } else if (const HttpReply *old_reply = dynamic_cast(head)) { HttpReply::Pointer new_reply(new HttpReply);