Author: Dan Searle <dan.searle@censornet.com>

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<const HttpRequest*>(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<const HttpRequest*>(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<const HttpRequest*>(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<const HttpReply*>(head)) {
         HttpReply::Pointer new_reply(new HttpReply);


