Add auth_param request_format, request_realm to proxy authentication schemes. The request_format value is a "quoted string" with logformat %macro support. A new %credentials macro can be used to supply user password and other scheme-dependent information to the helper. The request_realm is an authenticated users cache key format, needed when request_format feature is used to authenticate different users with identical user names (e.g., when user authentication depends on http_port). Example usage: auth_param basic request_format "%>lp %un %credentials" auth_param digest request_format "\"%un\":\"%credentials\"" This is a Measurement Factory project. === modified file 'src/AccessLogEntry.h' --- src/AccessLogEntry.h 2013-10-25 00:13:46 +0000 +++ src/AccessLogEntry.h 2013-10-29 08:25:36 +0000 @@ -158,7 +158,7 @@ ssluser(NULL), #endif port(NULL) { - ; + caddr.setNoAddr(); } Ip::Address caddr; === modified file 'src/FwdState.cc' --- src/FwdState.cc 2013-10-25 00:13:46 +0000 +++ src/FwdState.cc 2013-10-28 19:17:59 +0000 @@ -163,7 +163,7 @@ #endif // do full route options selection - peerSelect(&serverDestinations, request, entry, fwdPeerSelectionCompleteWrapper, this); + peerSelect(&serverDestinations, request, al, entry, fwdPeerSelectionCompleteWrapper, this); } #if STRICT_ORIGINAL_DST === modified file 'src/PeerSelectState.h' --- src/PeerSelectState.h 2013-10-25 00:13:46 +0000 +++ src/PeerSelectState.h 2013-10-28 19:17:51 +0000 @@ -33,6 +33,7 @@ #ifndef SQUID_PEERSELECTSTATE_H #define SQUID_PEERSELECTSTATE_H +#include "AccessLogEntry.h" #include "acl/Checklist.h" #include "base/Vector.h" #include "cbdata.h" @@ -47,7 +48,7 @@ typedef void PSC(Comm::ConnectionList *, ErrorState *, void *); -void peerSelect(Comm::ConnectionList *, HttpRequest *, StoreEntry *, PSC *, void *data); +void peerSelect(Comm::ConnectionList *, HttpRequest *, AccessLogEntry::Pointer const&, StoreEntry *, PSC *, void *data); void peerSelectInit(void); /** @@ -79,6 +80,7 @@ const char * url() const; HttpRequest *request; + AccessLogEntry::Pointer al; ///< info for the future access.log entry StoreEntry *entry; allow_t always_direct; allow_t never_direct; === modified file 'src/Server.cc' --- src/Server.cc 2013-10-25 00:13:46 +0000 +++ src/Server.cc 2013-10-28 19:17:51 +0000 @@ -555,7 +555,7 @@ } adaptedHeadSource = initiateAdaptation( - new Adaptation::Iterator(vrep, cause, group)); + new Adaptation::Iterator(vrep, cause, fwd->al, group)); startedAdaptation = initiated(adaptedHeadSource); Must(startedAdaptation); } @@ -918,7 +918,7 @@ // The callback can be called with a NULL service if adaptation is off. adaptationAccessCheckPending = Adaptation::AccessCheck::Start( Adaptation::methodRespmod, Adaptation::pointPreCache, - originalRequest(), virginReply(), this); + originalRequest(), virginReply(), fwd->al, this); debugs(11,5, HERE << "adaptationAccessCheckPending=" << adaptationAccessCheckPending); if (adaptationAccessCheckPending) return; === modified file 'src/acl/FilledChecklist.h' --- src/acl/FilledChecklist.h 2013-06-06 13:53:16 +0000 +++ src/acl/FilledChecklist.h 2013-10-28 19:17:51 +0000 @@ -1,6 +1,7 @@ #ifndef SQUID_ACLFILLED_CHECKLIST_H #define SQUID_ACLFILLED_CHECKLIST_H +#include "AccessLogEntry.h" #include "acl/Checklist.h" #include "acl/forward.h" #include "ip/Address.h" @@ -75,6 +76,8 @@ Ssl::X509_Pointer serverCert; #endif + AccessLogEntry::Pointer al; ///< info for the future access.log entry + ExternalACLEntry *extacl_entry; private: === modified file 'src/adaptation/AccessCheck.cc' --- src/adaptation/AccessCheck.cc 2013-02-16 17:05:36 +0000 +++ src/adaptation/AccessCheck.cc 2013-10-29 08:18:48 +0000 @@ -1,4 +1,5 @@ #include "squid.h" +#include "AccessLogEntry.h" #include "acl/FilledChecklist.h" #include "adaptation/AccessCheck.h" #include "adaptation/AccessRule.h" @@ -19,13 +20,14 @@ bool Adaptation::AccessCheck::Start(Method method, VectPoint vp, - HttpRequest *req, HttpReply *rep, Adaptation::Initiator *initiator) + HttpRequest *req, HttpReply *rep, + AccessLogEntry::Pointer &al, Adaptation::Initiator *initiator) { if (Config::Enabled) { // the new check will call the callback and delete self, eventually AsyncJob::Start(new AccessCheck( // we do not store so not a CbcPointer - ServiceFilter(method, vp, req, rep), initiator)); + ServiceFilter(method, vp, req, rep, al), initiator)); return true; } @@ -124,6 +126,7 @@ acl_checklist = new ACLFilledChecklist(r->acl, filter.request, dash_str); if ((acl_checklist->reply = filter.reply)) HTTPMSGLOCK(acl_checklist->reply); + acl_checklist->al = filter.al; acl_checklist->nonBlockingCheck(AccessCheckCallbackWrapper, this); return; } === modified file 'src/adaptation/AccessCheck.h' --- src/adaptation/AccessCheck.h 2013-10-25 00:13:46 +0000 +++ src/adaptation/AccessCheck.h 2013-10-29 08:17:25 +0000 @@ -2,6 +2,7 @@ #define SQUID_ADAPTATION__ACCESS_CHECK_H #include "acl/Acl.h" +#include "AccessLogEntry.h" #include "adaptation/Elements.h" #include "adaptation/forward.h" #include "adaptation/Initiator.h" @@ -25,7 +26,7 @@ // use this to start async ACL checks; returns true if started static bool Start(Method method, VectPoint vp, HttpRequest *req, - HttpReply *rep, Adaptation::Initiator *initiator); + HttpReply *rep, AccessLogEntry::Pointer &al, Adaptation::Initiator *initiator); protected: // use Start to start adaptation checks === modified file 'src/adaptation/Iterator.cc' --- src/adaptation/Iterator.cc 2013-10-25 00:13:46 +0000 +++ src/adaptation/Iterator.cc 2013-10-29 08:22:54 +0000 @@ -16,12 +16,14 @@ Adaptation::Iterator::Iterator( HttpMsg *aMsg, HttpRequest *aCause, + AccessLogEntry::Pointer &alp, const ServiceGroupPointer &aGroup): AsyncJob("Iterator"), Adaptation::Initiate("Iterator"), theGroup(aGroup), theMsg(aMsg), theCause(aCause), + al(alp), theLauncher(0), iterations(0), adapted(false) @@ -257,7 +259,7 @@ Must(false); // should not happen } - return ServiceFilter(method, theGroup->point, req, rep); + return ServiceFilter(method, theGroup->point, req, rep, al); } CBDATA_NAMESPACED_CLASS_INIT(Adaptation, Iterator); === modified file 'src/adaptation/Iterator.h' --- src/adaptation/Iterator.h 2013-10-25 00:13:46 +0000 +++ src/adaptation/Iterator.h 2013-10-29 08:22:00 +0000 @@ -1,6 +1,7 @@ #ifndef SQUID_ADAPTATION__ITERATOR_H #define SQUID_ADAPTATION__ITERATOR_H +#include "AccessLogEntry.h" #include "adaptation/Initiate.h" #include "adaptation/Initiator.h" #include "adaptation/ServiceGroups.h" @@ -25,6 +26,7 @@ { public: Iterator(HttpMsg *virginHeader, HttpRequest *virginCause, + AccessLogEntry::Pointer &alp, const Adaptation::ServiceGroupPointer &aGroup); virtual ~Iterator(); @@ -57,6 +59,7 @@ ServicePlan thePlan; ///< which services to use and in what order HttpMsg *theMsg; ///< the message being adapted (virgin for each step) HttpRequest *theCause; ///< the cause of the original virgin message + AccessLogEntry::Pointer al; ///< info for the future access.log entry CbcPointer theLauncher; ///< current transaction launcher int iterations; ///< number of steps initiated bool adapted; ///< whether the virgin message has been replaced === modified file 'src/adaptation/ServiceFilter.cc' --- src/adaptation/ServiceFilter.cc 2013-10-25 00:13:46 +0000 +++ src/adaptation/ServiceFilter.cc 2013-10-29 09:26:02 +0000 @@ -1,13 +1,15 @@ #include "squid.h" +#include "AccessLogEntry.h" #include "adaptation/ServiceFilter.h" #include "HttpReply.h" #include "HttpRequest.h" -Adaptation::ServiceFilter::ServiceFilter(Method aMethod, VectPoint aPoint, HttpRequest *aReq, HttpReply *aRep): +Adaptation::ServiceFilter::ServiceFilter(Method aMethod, VectPoint aPoint, HttpRequest *aReq, HttpReply *aRep, AccessLogEntry::Pointer const &alp): method(aMethod), point(aPoint), request(aReq), - reply(aRep) + reply(aRep), + al(alp) { if (reply) HTTPMSGLOCK(reply); @@ -21,7 +23,8 @@ method(f.method), point(f.point), request(f.request), - reply(f.reply) + reply(f.reply), + al(f.al) { if (request) HTTPMSGLOCK(request); === modified file 'src/adaptation/ServiceFilter.h' --- src/adaptation/ServiceFilter.h 2009-07-13 01:20:26 +0000 +++ src/adaptation/ServiceFilter.h 2013-10-28 19:17:51 +0000 @@ -1,6 +1,7 @@ #ifndef SQUID_ADAPTATION__SERVICE_FILTER_H #define SQUID_ADAPTATION__SERVICE_FILTER_H +#include "AccessLogEntry.h" #include "adaptation/Elements.h" class HttpRequest; @@ -13,7 +14,7 @@ class ServiceFilter { public: - ServiceFilter(Method, VectPoint, HttpRequest *, HttpReply *); // locks + ServiceFilter(Method, VectPoint, HttpRequest *, HttpReply *, AccessLogEntry::Pointer const &al); // locks ServiceFilter(const ServiceFilter &f); ~ServiceFilter(); // unlocks @@ -24,6 +25,7 @@ VectPoint point; ///< adaptation location HttpRequest *request; ///< HTTP request being adapted or cause; may be nil HttpReply *reply; ///< HTTP response being adapted; may be nil + AccessLogEntry::Pointer al; ///< info for the future access.log entry }; } // namespace Adaptation === modified file 'src/auth/Acl.cc' --- src/auth/Acl.cc 2013-10-25 00:13:46 +0000 +++ src/auth/Acl.cc 2013-10-29 09:28:36 +0000 @@ -46,7 +46,7 @@ /* Note: this fills in auth_user_request when applicable */ const AuthAclState result = Auth::UserRequest::tryToAuthenticateAndSetAuthUser( &checklist->auth_user_request, headertype, request, - checklist->conn(), checklist->src_addr); + checklist->conn(), checklist->src_addr, checklist->al); switch (result) { case AUTH_ACL_CANNOT_AUTHENTICATE: === modified file 'src/auth/AclProxyAuth.cc' --- src/auth/AclProxyAuth.cc 2013-10-25 00:13:46 +0000 +++ src/auth/AclProxyAuth.cc 2013-10-28 19:17:51 +0000 @@ -145,7 +145,7 @@ /* make sure someone created auth_user_request for us */ assert(checklist->auth_user_request != NULL); assert(checklist->auth_user_request->valid()); - checklist->auth_user_request->start(LookupDone, checklist); + checklist->auth_user_request->start(checklist->request, checklist->al, LookupDone, checklist); } void === modified file 'src/auth/Config.cc' --- src/auth/Config.cc 2012-09-01 14:38:36 +0000 +++ src/auth/Config.cc 2013-10-29 12:30:00 +0000 @@ -33,8 +33,12 @@ #include "squid.h" #include "auth/Config.h" #include "auth/UserRequest.h" +#include "cache_cf.h" +#include "ConfigParser.h" #include "Debug.h" +#include "format/Format.h" #include "globals.h" +#include "Store.h" Auth::ConfigVector Auth::TheConfig; @@ -46,7 +50,7 @@ * It may also be NULL reflecting that no user could be created. */ Auth::UserRequest::Pointer -Auth::Config::CreateAuthUser(const char *proxy_auth) +Auth::Config::CreateAuthUser(const char *proxy_auth, AccessLogEntry::Pointer &al) { assert(proxy_auth != NULL); debugs(29, 9, HERE << "header = '" << proxy_auth << "'"); @@ -58,8 +62,19 @@ "Unsupported or unconfigured/inactive proxy-auth scheme, '" << proxy_auth << "'"); return NULL; } + static MemBuf rmb; + rmb.reset(); + if (config->requestRealm) { + config->requestRealm->assemble(rmb, al, 0); + } else if (config->requestFormat) { + // %credentials and %username, which normally included in + // request_format, are - at this time, but that is OK + // because user name is added to key explicitly, and we do + // not want to store authenticated credentials at all. + config->requestFormat->assemble(rmb, al, 0); + } - return config->decode(proxy_auth); + return config->decode(proxy_auth, rmb.hasContent() ? rmb.content() : NULL); } Auth::Config * @@ -76,3 +91,66 @@ void Auth::Config::registerWithCacheManager(void) {} + +void +Auth::Config::parse(Auth::Config * scheme, int n_configured, char *param_str) +{ + if (strcasecmp(param_str, "request_format") == 0) { + requestFormatLine = ConfigParser::NextQuotedToken(); + Format::Format *nlf = new ::Format::Format(scheme->type()); + if (!nlf->parse(requestFormatLine.termedBuf())) { + self_destruct(); + return; + } + if (requestFormat) + delete requestFormat; + + requestFormat = nlf; + + if (char *t = strtok(NULL, w_space)) { + debugs(29, DBG_CRITICAL, HERE << "unexpected argument '" << t << "' after request_format specification"); + self_destruct(); + } + } else if (strcasecmp(param_str, "request_realm") == 0) { + requestRealmFormat = ConfigParser::NextQuotedToken(); + Format::Format *nlf = new ::Format::Format(scheme->type()); + if (!nlf->parse(requestRealmFormat.termedBuf())) { + self_destruct(); + return; + } + if (requestRealm) + delete requestRealm; + + requestRealm = nlf; + + if (char *t = strtok(NULL, w_space)) { + debugs(29, DBG_CRITICAL, HERE << "unexpected argument '" << t << "' after request_realm specification"); + self_destruct(); + } + } else { + debugs(29, DBG_CRITICAL, HERE << "unrecognised " << scheme->type() << " auth scheme parameter '" << param_str << "'"); + } +} + +void +Auth::Config::dump(StoreEntry *entry, const char *name, Auth::Config *scheme) +{ + if (requestFormatLine.defined()) + storeAppendPrintf(entry, "%s %s request_format \"%s\"\n", name, scheme->type(), requestFormatLine.termedBuf()); + if (requestRealmFormat.defined()) + storeAppendPrintf(entry, "%s %s request_realm \"%s\"\n", name, scheme->type(), requestRealmFormat.termedBuf()); +} + +void +Auth::Config::done() +{ + if (requestFormat) + delete requestFormat; + requestFormat = NULL; + requestFormatLine.clean(); + + if (requestRealm) + delete requestRealm; + requestRealm = NULL; + requestRealmFormat.clean(); +} === modified file 'src/auth/Config.h' --- src/auth/Config.h 2012-09-01 14:38:36 +0000 +++ src/auth/Config.h 2013-10-29 09:28:36 +0000 @@ -32,6 +32,7 @@ #if USE_AUTH +#include "AccessLogEntry.h" #include "auth/UserRequest.h" #include "HelperChildConfig.h" @@ -43,6 +44,11 @@ /* for http_hdr_type parameters-by-value */ #include "HttpHeader.h" +namespace Format +{ + class Format; +} + namespace Auth { @@ -61,10 +67,10 @@ { public: - static UserRequest::Pointer CreateAuthUser(const char *proxy_auth); + static UserRequest::Pointer CreateAuthUser(const char *proxy_auth, AccessLogEntry::Pointer &al); static Config *Find(const char *proxy_auth); - Config() : authenticateChildren(20), authenticateProgram(NULL) {} + Config() : authenticateChildren(20), authenticateProgram(NULL), requestFormat(NULL), requestRealm(NULL) {} virtual ~Config() {} @@ -86,7 +92,7 @@ \param proxy_auth Login Pattern to parse. \retval * Details needed to authenticate. */ - virtual UserRequest::Pointer decode(char const *proxy_auth) = 0; + virtual UserRequest::Pointer decode(char const *proxy_auth, const char *requestRealm) = 0; /** * squid is finished with this config, release any unneeded resources. @@ -95,7 +101,7 @@ * \todo we need a 'done for reconfigure' and a 'done permanently' concept. */ - virtual void done() = 0; + virtual void done(); /** * The configured function is used to see if the auth module has been given valid @@ -117,7 +123,7 @@ * Responsible for writing to the StoreEntry the configuration parameters that a user * would put in a config file to recreate the running configuration. */ - virtual void dump(StoreEntry *, const char *, Config *) = 0; + virtual void dump(StoreEntry *, const char *, Config *); /** add headers as needed when challenging for auth */ virtual void fixHeader(UserRequest::Pointer, HttpReply *, http_hdr_type, HttpRequest *) = 0; @@ -129,7 +135,7 @@ virtual void registerWithCacheManager(void); /** parse config options */ - virtual void parse(Config *, int, char *) = 0; + virtual void parse(Config *, int, char *); /** the http string id */ virtual const char * type() const = 0; @@ -137,6 +143,10 @@ public: HelperChildConfig authenticateChildren; wordlist *authenticateProgram; ///< Helper program to run, includes all parameters + String requestFormatLine; ///< The format of the request to the auth helper + Format::Format *requestFormat; ///< The compiled request format + String requestRealmFormat; ///< The realm of the request to use for caching helper results + Format::Format *requestRealm; ///< The compiled requestRealm }; typedef Vector ConfigVector; === modified file 'src/auth/Gadgets.cc' --- src/auth/Gadgets.cc 2013-10-25 00:13:46 +0000 +++ src/auth/Gadgets.cc 2013-10-29 09:28:36 +0000 @@ -139,7 +139,7 @@ AuthUserHashPointer::AuthUserHashPointer(Auth::User::Pointer anAuth_user): auth_user(anAuth_user) { - key = (void *)anAuth_user->username(); + key = (void *)anAuth_user->userKey(); next = NULL; hash_join(proxy_auth_username_cache, (hash_link *) this); } === modified file 'src/auth/User.cc' --- src/auth/User.cc 2013-10-27 05:08:49 +0000 +++ src/auth/User.cc 2013-10-29 11:40:13 +0000 @@ -53,14 +53,15 @@ time_t Auth::User::last_discard = 0; -Auth::User::User(Auth::Config *aConfig) : +Auth::User::User(Auth::Config *aConfig, const char *aRequestRealm) : auth_type(Auth::AUTH_UNKNOWN), config(aConfig), ipcount(0), expiretime(0), notes(), credentials_state(Auth::Unchecked), - username_(NULL) + username_(NULL), + requestRealm_(aRequestRealm) { proxy_auth_list.head = proxy_auth_list.tail = NULL; proxy_match_cache.head = proxy_match_cache.tail = NULL; @@ -342,6 +343,16 @@ debugs(29, 2, HERE << "user '" << username() << "' has been seen at a new IP address (" << ipaddr << ")"); } +String +Auth::User::BuildUserKey(const char *username, const char *realm) +{ + static String key; + key.reset(username); + key.append(':'); + key.append(realm); + return key; +} + /** * Add the Auth::User structure to the username cache. */ === modified file 'src/auth/User.cci' --- src/auth/User.cci 2012-09-01 14:38:36 +0000 +++ src/auth/User.cci 2013-10-29 10:08:31 +0000 @@ -42,7 +42,9 @@ { if (aString) { assert(!username_); - username_ = xstrdup(aString); + username_ = xstrdup(aString); + if (requestRealm_.defined()) + userKey_ = BuildUserKey(username_, requestRealm_.termedBuf()); } else { safe_free(username_); } === modified file 'src/auth/User.h' --- src/auth/User.h 2013-10-27 05:08:49 +0000 +++ src/auth/User.h 2013-10-29 11:30:52 +0000 @@ -40,6 +40,7 @@ #include "dlink.h" #include "ip/Address.h" #include "Notes.h" +#include "SquidString.h" class AuthUserHashPointer; class StoreEntry; @@ -82,12 +83,15 @@ public: static void cacheInit(); static void CachedACLsReset(); + static String BuildUserKey(const char *username, const char *realm); void absorb(Auth::User::Pointer from); virtual ~User(); _SQUID_INLINE_ char const *username() const; _SQUID_INLINE_ void username(char const *); + const char *userKey() {return userKey_.defined() ? userKey_.termedBuf() : username_;} + /** * How long these credentials are still valid for. * Negative numbers means already expired. @@ -117,7 +121,7 @@ CredentialState credentials_state; protected: - User(Auth::Config *); + User(Auth::Config *, const char *requestRealm); private: /** @@ -133,6 +137,17 @@ */ const char *username_; + /** + * A realm for the user depending on request, designed to identify users, + * with the same username and different authentication domains. + */ + const String requestRealm_; + + /** + * A Unique key for the user, consist by username and requestRealm_ + */ + String userKey_; + /** what ip addresses has this user been seen at?, plus a list length cache */ dlink_list ip_list; }; === modified file 'src/auth/UserRequest.cc' --- src/auth/UserRequest.cc 2013-10-27 05:08:49 +0000 +++ src/auth/UserRequest.cc 2013-10-29 09:28:36 +0000 @@ -43,6 +43,8 @@ #include "comm/Connection.h" #include "HttpReply.h" #include "HttpRequest.h" +#include "format/Format.h" +#include "MemBuf.h" /* Generic Functions */ @@ -59,12 +61,12 @@ /* send the initial data to an authenticator module */ void -Auth::UserRequest::start(AUTHCB * handler, void *data) +Auth::UserRequest::start(HttpRequest *request, AccessLogEntry::Pointer &al, AUTHCB * handler, void *data) { assert(handler); assert(data); debugs(29, 9, HERE << "auth_user_request '" << this << "'"); - module_start(handler, data); + module_start(request, al, handler, data); } bool @@ -293,7 +295,7 @@ * Caller is responsible for locking and unlocking their *auth_user_request! */ AuthAclState -Auth::UserRequest::authenticate(Auth::UserRequest::Pointer * auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr) +Auth::UserRequest::authenticate(Auth::UserRequest::Pointer * auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr, AccessLogEntry::Pointer &al) { const char *proxy_auth; assert(headertype != 0); @@ -372,7 +374,7 @@ /* beginning of a new request check */ debugs(29, 4, HERE << "No connection authentication type"); - *auth_user_request = Auth::Config::CreateAuthUser(proxy_auth); + *auth_user_request = Auth::Config::CreateAuthUser(proxy_auth, al); if (*auth_user_request == NULL) return AUTH_ACL_CHALLENGE; else if (!(*auth_user_request)->valid()) { @@ -455,7 +457,7 @@ } AuthAclState -Auth::UserRequest::tryToAuthenticateAndSetAuthUser(Auth::UserRequest::Pointer * aUR, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr) +Auth::UserRequest::tryToAuthenticateAndSetAuthUser(Auth::UserRequest::Pointer * aUR, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr, AccessLogEntry::Pointer &al) { // If we have already been called, return the cached value Auth::UserRequest::Pointer t = authTryGetUser(*aUR, conn, request); @@ -471,7 +473,7 @@ } // ok, call the actual authenticator routine. - AuthAclState result = authenticate(aUR, headertype, request, conn, src_addr); + AuthAclState result = authenticate(aUR, headertype, request, conn, src_addr, al); // auth process may have changed the UserRequest we are dealing with t = authTryGetUser(*aUR, conn, request); @@ -564,3 +566,21 @@ { return Auth::Scheme::Find(user()->config->type()); } + +int +Auth::UserRequest::helperFormatedRequest(char *buf, size_t size, HttpRequest *request, AccessLogEntry::Pointer &al) +{ + if (Format::Format *reqFmt = user()->config->requestFormat) { + MemBuf mb; + mb.init(1024, 2048); + // We should pass AccessLogEntry as second argument .... + Auth::UserRequest::Pointer oldReq = request->auth_user_request; + request->auth_user_request = this; + reqFmt->assemble(mb, al, 0); + request->auth_user_request = oldReq; + int sz = snprintf(buf, size, "%s\n", mb.content()); + debugs(29, 5, "Assebled line to send :" << mb.content()); + return sz; + } + return 0; +} === modified file 'src/auth/UserRequest.h' --- src/auth/UserRequest.h 2013-10-25 00:13:46 +0000 +++ src/auth/UserRequest.h 2013-10-29 09:28:36 +0000 @@ -32,6 +32,7 @@ #if USE_AUTH +#include "AccessLogEntry.h" #include "auth/AuthAclState.h" #include "auth/Scheme.h" #include "auth/User.h" @@ -164,7 +165,7 @@ * \param handler Handler to process the callback when its run * \param data CBDATA for handler */ - virtual void module_start(AUTHCB *handler, void *data) = 0; + virtual void module_start(HttpRequest *request, AccessLogEntry::Pointer &al, AUTHCB *handler, void *data) = 0; // User credentials object this UserRequest is managing virtual User::Pointer user() {return _auth_user;} @@ -189,12 +190,12 @@ * * \return Some AUTH_ACL_* state */ - static AuthAclState tryToAuthenticateAndSetAuthUser(UserRequest::Pointer *aUR, http_hdr_type, HttpRequest *, ConnStateData *, Ip::Address &); + static AuthAclState tryToAuthenticateAndSetAuthUser(UserRequest::Pointer *aUR, http_hdr_type, HttpRequest *, ConnStateData *, Ip::Address &, AccessLogEntry::Pointer &); /// Add the appropriate [Proxy-]Authenticate header to the given reply static void addReplyAuthHeader(HttpReply * rep, UserRequest::Pointer auth_user_request, HttpRequest * request, int accelerated, int internal); - void start(AUTHCB *handler, void *data); + void start(HttpRequest *request, AccessLogEntry::Pointer &al, AUTHCB *handler, void *data); char const * denyMessage(char const * const default_message = NULL); /** Possibly overrideable in future */ @@ -217,9 +218,15 @@ virtual const char * connLastHeader(); + /** + * The string representation of the credentials send by client + */ + virtual const char *credentialsStr() = 0; + + int helperFormatedRequest(char *buf, size_t size, HttpRequest *, AccessLogEntry::Pointer &al); private: - static AuthAclState authenticate(UserRequest::Pointer * auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr); + static AuthAclState authenticate(UserRequest::Pointer * auth_user_request, http_hdr_type headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr, AccessLogEntry::Pointer &al); /** return a message on the 407 error pages */ char *message; === modified file 'src/auth/basic/User.cc' --- src/auth/basic/User.cc 2013-02-22 13:26:12 +0000 +++ src/auth/basic/User.cc 2013-10-29 09:39:16 +0000 @@ -5,8 +5,8 @@ #include "SquidConfig.h" #include "SquidTime.h" -Auth::Basic::User::User(Auth::Config *aConfig) : - Auth::User(aConfig), +Auth::Basic::User::User(Auth::Config *aConfig, const char *aRequestRealm) : + Auth::User(aConfig, aRequestRealm), passwd(NULL), queue(NULL), currentRequest(NULL) === modified file 'src/auth/basic/User.h' --- src/auth/basic/User.h 2013-02-22 13:26:12 +0000 +++ src/auth/basic/User.h 2013-10-29 09:28:36 +0000 @@ -19,7 +19,7 @@ public: MEMPROXY_CLASS(Auth::Basic::User); - User(Auth::Config *); + User(Auth::Config *, const char *requestRealm); ~User(); bool authenticated() const; bool valid() const; === modified file 'src/auth/basic/UserRequest.cc' --- src/auth/basic/UserRequest.cc 2013-10-27 05:08:49 +0000 +++ src/auth/basic/UserRequest.cc 2013-10-29 08:43:33 +0000 @@ -7,6 +7,10 @@ #include "charset.h" #include "Debug.h" #include "HelperReply.h" +#include "HttpMsg.h" +#include "HttpRequest.h" +#include "format/Format.h" +#include "MemBuf.h" #include "rfc1738.h" #include "SquidTime.h" @@ -25,6 +29,15 @@ return 0; } +const char * +Auth::Basic::UserRequest::credentialsStr() +{ + Auth::Basic::User const *basic_auth = dynamic_cast(user().getRaw()); + if (basic_auth) + return basic_auth->passwd; + return NULL; +} + /* log a basic user in */ void @@ -80,7 +93,7 @@ /* send the initial data to a basic authenticator module */ void -Auth::Basic::UserRequest::module_start(AUTHCB * handler, void *data) +Auth::Basic::UserRequest::module_start(HttpRequest *request, AccessLogEntry::Pointer &al, AUTHCB * handler, void *data) { assert(user()->auth_type == Auth::AUTH_BASIC); Auth::Basic::User *basic_auth = dynamic_cast(user().getRaw()); @@ -109,18 +122,21 @@ /* mark this user as having verification in progress */ user()->credentials(Auth::Pending); char buf[HELPER_INPUT_BUFFER]; - static char usern[HELPER_INPUT_BUFFER]; - static char pass[HELPER_INPUT_BUFFER]; - if (static_cast(user()->config)->utf8) { - latin1_to_utf8(usern, sizeof(usern), user()->username()); - latin1_to_utf8(pass, sizeof(pass), basic_auth->passwd); - xstrncpy(usern, rfc1738_escape(usern), sizeof(usern)); - xstrncpy(pass, rfc1738_escape(pass), sizeof(pass)); - } else { - xstrncpy(usern, rfc1738_escape(user()->username()), sizeof(usern)); - xstrncpy(pass, rfc1738_escape(basic_auth->passwd), sizeof(pass)); + int sz = 0; + if (!(sz = helperFormatedRequest(buf, sizeof(buf), request, al))) { + static char usern[HELPER_INPUT_BUFFER]; + static char pass[HELPER_INPUT_BUFFER]; + if (static_cast(user()->config)->utf8) { + latin1_to_utf8(usern, sizeof(usern), user()->username()); + latin1_to_utf8(pass, sizeof(pass), basic_auth->passwd); + xstrncpy(usern, rfc1738_escape(usern), sizeof(usern)); + xstrncpy(pass, rfc1738_escape(pass), sizeof(pass)); + } else { + xstrncpy(usern, rfc1738_escape(user()->username()), sizeof(usern)); + xstrncpy(pass, rfc1738_escape(basic_auth->passwd), sizeof(pass)); + } + sz = snprintf(buf, sizeof(buf), "%s %s\n", usern, pass); } - int sz = snprintf(buf, sizeof(buf), "%s %s\n", usern, pass); if (sz<=0) { debugs(9, DBG_CRITICAL, "ERROR: Basic Authentication Failure. Can not build helper validation request."); handler(data); === modified file 'src/auth/basic/UserRequest.h' --- src/auth/basic/UserRequest.h 2012-10-29 04:59:58 +0000 +++ src/auth/basic/UserRequest.h 2013-10-28 19:17:51 +0000 @@ -26,7 +26,8 @@ virtual int authenticated() const; virtual void authenticate(HttpRequest * request, ConnStateData *conn, http_hdr_type type); virtual Auth::Direction module_direction(); - virtual void module_start(AUTHCB *, void *); + virtual void module_start(HttpRequest * request, AccessLogEntry::Pointer &al, AUTHCB *, void *); + virtual const char *credentialsStr(); private: static HLPCB HandleReply; === modified file 'src/auth/basic/auth_basic.cc' --- src/auth/basic/auth_basic.cc 2013-10-25 00:13:46 +0000 +++ src/auth/basic/auth_basic.cc 2013-10-29 09:38:32 +0000 @@ -116,6 +116,8 @@ void Auth::Basic::Config::done() { + Auth::Config::done(); + authbasic_initialised = 0; if (basicauthenticators) { @@ -149,6 +151,7 @@ storeAppendPrintf(entry, "%s basic children %d startup=%d idle=%d concurrency=%d\n", name, authenticateChildren.n_max, authenticateChildren.n_startup, authenticateChildren.n_idle, authenticateChildren.concurrency); storeAppendPrintf(entry, "%s basic credentialsttl %d seconds\n", name, (int) credentialsTTL); storeAppendPrintf(entry, "%s basic casesensitive %s\n", name, casesensitive ? "on" : "off"); + Auth::Config::dump(entry, name, scheme); } Auth::Basic::Config::Config() : @@ -184,9 +187,8 @@ parse_onoff(&casesensitive); } else if (strcmp(param_str, "utf8") == 0) { parse_onoff(&utf8); - } else { - debugs(29, DBG_CRITICAL, HERE << "unrecognised basic auth scheme parameter '" << param_str << "'"); - } + } else + Auth::Config::parse(scheme, n_configured, param_str); } static void @@ -196,15 +198,15 @@ } static Auth::User::Pointer -authBasicAuthUserFindUsername(const char *username) +authBasicAuthUserFindUsername(const char *userkey) { AuthUserHashPointer *usernamehash; - debugs(29, 9, HERE << "Looking for user '" << username << "'"); + debugs(29, 9, HERE << "Looking for user '" << userkey << "'"); - if (username && (usernamehash = static_cast(hash_lookup(proxy_auth_username_cache, username)))) { + if (userkey && (usernamehash = static_cast(hash_lookup(proxy_auth_username_cache, userkey)))) { while (usernamehash) { if ((usernamehash->user()->auth_type == Auth::AUTH_BASIC) && - !strcmp(username, (char const *)usernamehash->key)) + !strcmp(userkey, (char const *)usernamehash->key)) return usernamehash->user(); usernamehash = static_cast(usernamehash->next); @@ -257,7 +259,7 @@ * descriptive message to the user. */ Auth::UserRequest::Pointer -Auth::Basic::Config::decode(char const *proxy_auth) +Auth::Basic::Config::decode(char const *proxy_auth, const char *aRequestRealm) { Auth::UserRequest::Pointer auth_user_request = dynamic_cast(new Auth::Basic::UserRequest); /* decode the username */ @@ -275,18 +277,18 @@ char *seperator = strchr(cleartext, ':'); - lb = local_basic = new Auth::Basic::User(this); - if (seperator == NULL) { - local_basic->username(cleartext); - } else { + lb = local_basic = new Auth::Basic::User(this, aRequestRealm); + + if (seperator) { /* terminate the username */ *seperator = '\0'; - local_basic->username(cleartext); local_basic->passwd = xstrdup(seperator+1); } if (!casesensitive) - Tolower((char *)local_basic->username()); + Tolower(cleartext); + local_basic->username(cleartext); + if (local_basic->passwd == NULL) { debugs(29, 4, HERE << "no password in proxy authorization header '" << proxy_auth << "'"); @@ -310,7 +312,7 @@ /* now lookup and see if we have a matching auth_user structure in memory. */ Auth::User::Pointer auth_user; - if ((auth_user = authBasicAuthUserFindUsername(lb->username())) == NULL) { + if ((auth_user = authBasicAuthUserFindUsername(lb->userKey())) == NULL) { /* the user doesn't exist in the username cache yet */ /* save the credentials */ debugs(29, 9, HERE << "Creating new user '" << lb->username() << "'"); === modified file 'src/auth/basic/auth_basic.h' --- src/auth/basic/auth_basic.h 2013-10-25 00:13:46 +0000 +++ src/auth/basic/auth_basic.h 2013-10-29 09:28:36 +0000 @@ -26,7 +26,7 @@ ~Config(); virtual bool active() const; virtual bool configured() const; - virtual Auth::UserRequest::Pointer decode(char const *proxy_auth); + virtual Auth::UserRequest::Pointer decode(char const *proxy_auth, const char *requestRealm); virtual void done(); virtual void rotateHelpers(); virtual void dump(StoreEntry *, const char *, Auth::Config *); === modified file 'src/auth/digest/User.cc' --- src/auth/digest/User.cc 2013-01-25 09:09:52 +0000 +++ src/auth/digest/User.cc 2013-10-29 09:42:30 +0000 @@ -6,8 +6,8 @@ #include "SquidConfig.h" #include "SquidTime.h" -Auth::Digest::User::User(Auth::Config *aConfig) : - Auth::User(aConfig), +Auth::Digest::User::User(Auth::Config *aConfig, const char *aRequestRealm) : + Auth::User(aConfig, aRequestRealm), HA1created(0) { memset(HA1, 0, sizeof(HA1)); === modified file 'src/auth/digest/User.h' --- src/auth/digest/User.h 2011-04-15 00:12:31 +0000 +++ src/auth/digest/User.h 2013-10-29 09:28:36 +0000 @@ -14,7 +14,7 @@ public: MEMPROXY_CLASS(Auth::Digest::User); - User(Auth::Config *); + User(Auth::Config *, const char *requestRealm); ~User(); int authenticated() const; === modified file 'src/auth/digest/UserRequest.cc' --- src/auth/digest/UserRequest.cc 2013-10-27 05:08:49 +0000 +++ src/auth/digest/UserRequest.cc 2013-10-28 19:17:51 +0000 @@ -1,4 +1,5 @@ #include "squid.h" +#include "AccessLogEntry.h" #include "auth/digest/auth_digest.h" #include "auth/digest/User.h" #include "auth/digest/UserRequest.h" @@ -7,6 +8,8 @@ #include "HttpHeaderTools.h" #include "HttpReply.h" #include "HttpRequest.h" +#include "format/Format.h" +#include "MemBuf.h" #include "SquidTime.h" Auth::Digest::UserRequest::UserRequest() : @@ -56,6 +59,12 @@ return 0; } +const char * +Auth::Digest::UserRequest::credentialsStr() +{ + return realm; +} + /** log a digest user in */ void @@ -248,7 +257,7 @@ /* send the initial data to a digest authenticator module */ void -Auth::Digest::UserRequest::module_start(AUTHCB * handler, void *data) +Auth::Digest::UserRequest::module_start(HttpRequest *request, AccessLogEntry::Pointer &al, AUTHCB * handler, void *data) { char buf[8192]; @@ -261,12 +270,14 @@ return; } - if (static_cast(Auth::Config::Find("digest"))->utf8) { - char userstr[1024]; - latin1_to_utf8(userstr, sizeof(userstr), user()->username()); - snprintf(buf, 8192, "\"%s\":\"%s\"\n", userstr, realm); - } else { - snprintf(buf, 8192, "\"%s\":\"%s\"\n", user()->username(), realm); + if (!helperFormatedRequest(buf, sizeof(buf), request, al)) { + if (static_cast(Auth::Config::Find("digest"))->utf8) { + char userstr[1024]; + latin1_to_utf8(userstr, sizeof(userstr), user()->username()); + snprintf(buf, 8192, "\"%s\":\"%s\"\n", userstr, realm); + } else { + snprintf(buf, 8192, "\"%s\":\"%s\"\n", user()->username(), realm); + } } helperSubmit(digestauthenticators, buf, Auth::Digest::UserRequest::HandleReply, === modified file 'src/auth/digest/UserRequest.h' --- src/auth/digest/UserRequest.h 2013-10-25 00:13:46 +0000 +++ src/auth/digest/UserRequest.h 2013-10-28 19:17:51 +0000 @@ -34,7 +34,8 @@ virtual void addAuthenticationInfoTrailer(HttpReply * rep, int accel); #endif - virtual void module_start(AUTHCB *, void *); + virtual void module_start(HttpRequest *request, AccessLogEntry::Pointer &al, AUTHCB *, void *); + virtual const char *credentialsStr(); char *nonceb64; /* "dcd98b7102dd2f0e8b11d0f600bfb0c093" */ char *cnonce; /* "0a4f113b" */ === modified file 'src/auth/digest/auth_digest.cc' --- src/auth/digest/auth_digest.cc 2013-10-25 00:13:46 +0000 +++ src/auth/digest/auth_digest.cc 2013-10-29 11:48:09 +0000 @@ -477,12 +477,12 @@ /* USER related functions */ static Auth::User::Pointer -authDigestUserFindUsername(const char *username) +authDigestUserFindUsername(const String &userkey) { AuthUserHashPointer *usernamehash; - debugs(29, 9, HERE << "Looking for user '" << username << "'"); + debugs(29, 9, HERE << "Looking for user '" << userkey << "'"); - if (username && (usernamehash = static_cast < AuthUserHashPointer * >(hash_lookup(proxy_auth_username_cache, username)))) { + if (userkey.defined() && (usernamehash = static_cast < AuthUserHashPointer * >(hash_lookup(proxy_auth_username_cache, userkey.termedBuf())))) { while ((usernamehash->user()->auth_type != Auth::AUTH_DIGEST) && (usernamehash->next)) usernamehash = static_cast(usernamehash->next); @@ -523,6 +523,7 @@ name, "digest", noncemaxuses, name, "digest", (int) noncemaxduration, name, "digest", (int) nonceGCInterval); + Auth::Config::dump(entry, name, scheme); } bool @@ -605,6 +606,8 @@ void Auth::Digest::Config::done() { + Auth::Config::done(); + authdigest_initialised = 0; if (digestauthenticators) @@ -666,9 +669,8 @@ parse_onoff(&PostWorkaround); } else if (strcmp(param_str, "utf8") == 0) { parse_onoff(&utf8); - } else { - debugs(29, DBG_CRITICAL, "unrecognised digest auth scheme parameter '" << param_str << "'"); - } + } else + Auth::Config::parse(scheme, n_configured, param_str); } const char * @@ -758,13 +760,13 @@ /* setup the necessary info to log the username */ static Auth::UserRequest::Pointer -authDigestLogUsername(char *username, Auth::UserRequest::Pointer auth_user_request) +authDigestLogUsername(char *username, Auth::UserRequest::Pointer auth_user_request, const char *requestRealm) { assert(auth_user_request != NULL); /* log the username */ debugs(29, 9, "Creating new user for logging '" << (username?username:"[no username]") << "'"); - Auth::User::Pointer digest_user = new Auth::Digest::User(static_cast(Auth::Config::Find("digest"))); + Auth::User::Pointer digest_user = new Auth::Digest::User(static_cast(Auth::Config::Find("digest")), requestRealm); /* save the credentials */ digest_user->username(username); /* set the auth_user type */ @@ -779,7 +781,7 @@ * Auth_user structure. */ Auth::UserRequest::Pointer -Auth::Digest::Config::decode(char const *proxy_auth) +Auth::Digest::Config::decode(char const *proxy_auth, const char *aRequestRealm) { const char *item; const char *p; @@ -936,7 +938,7 @@ /* do we have a username ? */ if (!username || username[0] == '\0') { debugs(29, 2, "Empty or not present username"); - rv = authDigestLogUsername(username, digest_request); + rv = authDigestLogUsername(username, digest_request, aRequestRealm); safe_free(username); return rv; } @@ -947,7 +949,7 @@ */ if (strchr(username, '"')) { debugs(29, 2, "Unacceptable username '" << username << "'"); - rv = authDigestLogUsername(username, digest_request); + rv = authDigestLogUsername(username, digest_request, aRequestRealm); safe_free(username); return rv; } @@ -955,7 +957,7 @@ /* do we have a realm ? */ if (!digest_request->realm || digest_request->realm[0] == '\0') { debugs(29, 2, "Empty or not present realm"); - rv = authDigestLogUsername(username, digest_request); + rv = authDigestLogUsername(username, digest_request, aRequestRealm); safe_free(username); return rv; } @@ -963,7 +965,7 @@ /* and a nonce? */ if (!digest_request->nonceb64 || digest_request->nonceb64[0] == '\0') { debugs(29, 2, "Empty or not present nonce"); - rv = authDigestLogUsername(username, digest_request); + rv = authDigestLogUsername(username, digest_request, aRequestRealm); safe_free(username); return rv; } @@ -972,7 +974,7 @@ * authenticate phase, but needs to be given */ if (!digest_request->uri || digest_request->uri[0] == '\0') { debugs(29, 2, "Missing URI field"); - rv = authDigestLogUsername(username, digest_request); + rv = authDigestLogUsername(username, digest_request, aRequestRealm); safe_free(username); return rv; } @@ -980,7 +982,7 @@ /* is the response the correct length? */ if (!digest_request->response || strlen(digest_request->response) != 32) { debugs(29, 2, "Response length invalid"); - rv = authDigestLogUsername(username, digest_request); + rv = authDigestLogUsername(username, digest_request, aRequestRealm); safe_free(username); return rv; } @@ -991,7 +993,7 @@ else if (strcmp(digest_request->algorithm, "MD5") && strcmp(digest_request->algorithm, "MD5-sess")) { debugs(29, 2, "invalid algorithm specified!"); - rv = authDigestLogUsername(username, digest_request); + rv = authDigestLogUsername(username, digest_request, aRequestRealm); safe_free(username); return rv; } @@ -1003,7 +1005,7 @@ if (strcmp(digest_request->qop, QOP_AUTH) != 0) { /* we received a qop option we didn't send */ debugs(29, 2, "Invalid qop option received"); - rv = authDigestLogUsername(username, digest_request); + rv = authDigestLogUsername(username, digest_request, aRequestRealm); safe_free(username); return rv; } @@ -1011,7 +1013,7 @@ /* check cnonce */ if (!digest_request->cnonce || digest_request->cnonce[0] == '\0') { debugs(29, 2, "Missing cnonce field"); - rv = authDigestLogUsername(username, digest_request); + rv = authDigestLogUsername(username, digest_request, aRequestRealm); safe_free(username); return rv; } @@ -1019,7 +1021,7 @@ /* check nc */ if (strlen(digest_request->nc) != 8 || strspn(digest_request->nc, "0123456789abcdefABCDEF") != 8) { debugs(29, 2, "invalid nonce count"); - rv = authDigestLogUsername(username, digest_request); + rv = authDigestLogUsername(username, digest_request, aRequestRealm); safe_free(username); return rv; } @@ -1027,7 +1029,7 @@ /* cnonce and nc both require qop */ if (digest_request->cnonce || digest_request->nc[0] != '\0') { debugs(29, 2, "missing qop!"); - rv = authDigestLogUsername(username, digest_request); + rv = authDigestLogUsername(username, digest_request, aRequestRealm); safe_free(username); return rv; } @@ -1042,7 +1044,7 @@ debugs(29, 2, "Unexpected or invalid nonce received"); if (digest_request->user() != NULL) digest_request->user()->credentials(Auth::Failed); - rv = authDigestLogUsername(username, digest_request); + rv = authDigestLogUsername(username, digest_request, aRequestRealm); safe_free(username); return rv; } @@ -1053,7 +1055,7 @@ /* check that we're not being hacked / the username hasn't changed */ if (nonce->user && strcmp(username, nonce->user->username())) { debugs(29, 2, "Username for the nonce does not equal the username for the request"); - rv = authDigestLogUsername(username, digest_request); + rv = authDigestLogUsername(username, digest_request, aRequestRealm); safe_free(username); return rv; } @@ -1067,10 +1069,10 @@ Auth::User::Pointer auth_user; - if ((auth_user = authDigestUserFindUsername(username)) == NULL) { + if ((auth_user = authDigestUserFindUsername(Auth::User::BuildUserKey(username, aRequestRealm))) == NULL) { /* the user doesn't exist in the username cache yet */ debugs(29, 9, HERE << "Creating new digest user '" << username << "'"); - digest_user = new Auth::Digest::User(this); + digest_user = new Auth::Digest::User(this, aRequestRealm); /* auth_user is a parent */ auth_user = digest_user; /* save the username */ === modified file 'src/auth/digest/auth_digest.h' --- src/auth/digest/auth_digest.h 2013-01-25 16:53:16 +0000 +++ src/auth/digest/auth_digest.h 2013-10-29 09:28:36 +0000 @@ -69,7 +69,7 @@ Config(); virtual bool active() const; virtual bool configured() const; - virtual Auth::UserRequest::Pointer decode(char const *proxy_auth); + virtual Auth::UserRequest::Pointer decode(char const *proxy_auth, const char *requestRealm); virtual void done(); virtual void rotateHelpers(); virtual void dump(StoreEntry *, const char *, Auth::Config *); === modified file 'src/auth/negotiate/User.cc' --- src/auth/negotiate/User.cc 2012-01-20 18:55:04 +0000 +++ src/auth/negotiate/User.cc 2013-10-29 09:42:10 +0000 @@ -3,8 +3,8 @@ #include "auth/negotiate/User.h" #include "Debug.h" -Auth::Negotiate::User::User(Auth::Config *aConfig) : - Auth::User(aConfig) +Auth::Negotiate::User::User(Auth::Config *aConfig, const char *aRequestRealm) : + Auth::User(aConfig, aRequestRealm) { proxy_auth_list.head = proxy_auth_list.tail = NULL; } === modified file 'src/auth/negotiate/User.h' --- src/auth/negotiate/User.h 2011-04-14 02:40:59 +0000 +++ src/auth/negotiate/User.h 2013-10-29 09:28:36 +0000 @@ -16,7 +16,7 @@ { public: MEMPROXY_CLASS(Auth::Negotiate::User); - User(Auth::Config *); + User(Auth::Config *, const char *requestRealm); ~User(); virtual int32_t ttl() const; === modified file 'src/auth/negotiate/UserRequest.cc' --- src/auth/negotiate/UserRequest.cc 2013-10-27 05:08:49 +0000 +++ src/auth/negotiate/UserRequest.cc 2013-10-29 09:28:36 +0000 @@ -1,4 +1,5 @@ #include "squid.h" +#include "AccessLogEntry.h" #include "auth/negotiate/auth_negotiate.h" #include "auth/negotiate/UserRequest.h" #include "auth/State.h" @@ -9,6 +10,8 @@ #include "HttpHeaderTools.h" #include "HttpReply.h" #include "HttpRequest.h" +#include "format/Format.h" +#include "MemBuf.h" #include "SquidTime.h" Auth::Negotiate::UserRequest::UserRequest() @@ -52,6 +55,18 @@ return 0; } +const char * +Auth::Negotiate::UserRequest::credentialsStr() +{ + static char buf[MAX_AUTHTOKEN_LEN]; + if (user()->credentials() == Auth::Pending) { + snprintf(buf, sizeof(buf), "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here? + } else { + snprintf(buf, sizeof(buf), "KK %s\n", client_blob); + } + return buf; +} + Auth::Direction Auth::Negotiate::UserRequest::module_direction() { @@ -82,7 +97,7 @@ } void -Auth::Negotiate::UserRequest::module_start(AUTHCB * handler, void *data) +Auth::Negotiate::UserRequest::module_start(HttpRequest *req, AccessLogEntry::Pointer &al, AUTHCB * handler, void *data) { static char buf[MAX_AUTHTOKEN_LEN]; @@ -100,10 +115,12 @@ debugs(29, 8, HERE << "credentials state is '" << user()->credentials() << "'"); - if (user()->credentials() == Auth::Pending) { - snprintf(buf, sizeof(buf), "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here? - } else { - snprintf(buf, sizeof(buf), "KK %s\n", client_blob); + if (!helperFormatedRequest(buf, sizeof(buf), request, al)) { + if (user()->credentials() == Auth::Pending) { + snprintf(buf, sizeof(buf), "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here? + } else { + snprintf(buf, sizeof(buf), "KK %s\n", client_blob); + } } waiting = 1; @@ -283,10 +300,10 @@ debugs(29, 4, HERE << "authenticated user " << auth_user_request->user()->username()); /* see if this is an existing user with a different proxy_auth * string */ - AuthUserHashPointer *usernamehash = static_cast(hash_lookup(proxy_auth_username_cache, auth_user_request->user()->username())); + AuthUserHashPointer *usernamehash = static_cast(hash_lookup(proxy_auth_username_cache, auth_user_request->user()->userKey())); Auth::User::Pointer local_auth_user = lm_request->user(); while (usernamehash && (usernamehash->user()->auth_type != Auth::AUTH_NEGOTIATE || - strcmp(usernamehash->user()->username(), auth_user_request->user()->username()) != 0)) + strcmp(usernamehash->user()->userKey(), auth_user_request->user()->userKey()) != 0)) usernamehash = static_cast(usernamehash->next); if (usernamehash) { /* we can't seamlessly recheck the username due to the === modified file 'src/auth/negotiate/UserRequest.h' --- src/auth/negotiate/UserRequest.h 2013-04-04 06:15:00 +0000 +++ src/auth/negotiate/UserRequest.h 2013-10-29 08:04:25 +0000 @@ -26,7 +26,8 @@ virtual int authenticated() const; virtual void authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type); virtual Direction module_direction(); - virtual void module_start(AUTHCB *, void *); + virtual void module_start(HttpRequest *request, AccessLogEntry::Pointer &al, AUTHCB *, void *); + virtual const char *credentialsStr(); virtual void addAuthenticationInfoHeader(HttpReply * rep, int accel); === modified file 'src/auth/negotiate/auth_negotiate.cc' --- src/auth/negotiate/auth_negotiate.cc 2013-10-25 00:13:46 +0000 +++ src/auth/negotiate/auth_negotiate.cc 2013-10-29 09:41:51 +0000 @@ -88,6 +88,8 @@ void Auth::Negotiate::Config::done() { + Auth::Config::done(); + authnegotiate_initialised = 0; if (negotiateauthenticators) { @@ -120,7 +122,7 @@ storeAppendPrintf(entry, "\n%s negotiate children %d startup=%d idle=%d concurrency=%d\n", name, authenticateChildren.n_max, authenticateChildren.n_startup, authenticateChildren.n_idle, authenticateChildren.concurrency); storeAppendPrintf(entry, "%s %s keep_alive %s\n", name, "negotiate", keep_alive ? "on" : "off"); - + Auth::Config::dump(entry, name, scheme); } Auth::Negotiate::Config::Config() : keep_alive(1) @@ -140,9 +142,8 @@ authenticateChildren.parseConfig(); } else if (strcmp(param_str, "keep_alive") == 0) { parse_onoff(&keep_alive); - } else { - debugs(29, DBG_CRITICAL, "ERROR: unrecognised Negotiate auth scheme parameter '" << param_str << "'"); - } + } else + Auth::Config::parse(scheme, n_configured, param_str); } const char * @@ -287,9 +288,9 @@ * Auth_user structure. */ Auth::UserRequest::Pointer -Auth::Negotiate::Config::decode(char const *proxy_auth) +Auth::Negotiate::Config::decode(char const *proxy_auth, const char *aRequestRealm) { - Auth::Negotiate::User *newUser = new Auth::Negotiate::User(Auth::Config::Find("negotiate")); + Auth::Negotiate::User *newUser = new Auth::Negotiate::User(Auth::Config::Find("negotiate"), aRequestRealm); Auth::UserRequest *auth_user_request = new Auth::Negotiate::UserRequest(); assert(auth_user_request->user() == NULL); === modified file 'src/auth/negotiate/auth_negotiate.h' --- src/auth/negotiate/auth_negotiate.h 2011-12-30 01:24:57 +0000 +++ src/auth/negotiate/auth_negotiate.h 2013-10-29 09:28:36 +0000 @@ -31,7 +31,7 @@ Config(); virtual bool active() const; virtual bool configured() const; - virtual Auth::UserRequest::Pointer decode(char const *proxy_auth); + virtual Auth::UserRequest::Pointer decode(char const *proxy_auth, const char *requestRealm); virtual void done(); virtual void rotateHelpers(); virtual void dump(StoreEntry *, const char *, Auth::Config *); === modified file 'src/auth/ntlm/User.cc' --- src/auth/ntlm/User.cc 2012-01-20 18:55:04 +0000 +++ src/auth/ntlm/User.cc 2013-10-29 09:41:16 +0000 @@ -3,8 +3,8 @@ #include "auth/ntlm/User.h" #include "Debug.h" -Auth::Ntlm::User::User(Auth::Config *aConfig) : - Auth::User(aConfig) +Auth::Ntlm::User::User(Auth::Config *aConfig, const char *aRequestRealm) : + Auth::User(aConfig, aRequestRealm) { proxy_auth_list.head = proxy_auth_list.tail = NULL; } === modified file 'src/auth/ntlm/User.h' --- src/auth/ntlm/User.h 2011-04-14 02:40:59 +0000 +++ src/auth/ntlm/User.h 2013-10-29 09:28:36 +0000 @@ -16,7 +16,7 @@ { public: MEMPROXY_CLASS(Auth::Ntlm::User); - User(Auth::Config *); + User(Auth::Config *, const char *requestRealm); ~User(); virtual int32_t ttl() const; === modified file 'src/auth/ntlm/UserRequest.cc' --- src/auth/ntlm/UserRequest.cc 2013-10-27 05:08:49 +0000 +++ src/auth/ntlm/UserRequest.cc 2013-10-29 09:28:36 +0000 @@ -1,11 +1,15 @@ #include "squid.h" +#include "AccessLogEntry.h" #include "auth/ntlm/auth_ntlm.h" #include "auth/ntlm/UserRequest.h" #include "auth/State.h" #include "cbdata.h" #include "client_side.h" #include "globals.h" +#include "HttpMsg.h" #include "HttpRequest.h" +#include "format/Format.h" +#include "MemBuf.h" #include "SquidTime.h" Auth::Ntlm::UserRequest::UserRequest() @@ -49,6 +53,18 @@ return 0; } +const char * +Auth::Ntlm::UserRequest::credentialsStr() +{ + static char buf[MAX_AUTHTOKEN_LEN]; + if (user()->credentials() == Auth::Pending) { + snprintf(buf, sizeof(buf), "YR %s\n", client_blob); + } else { + snprintf(buf, sizeof(buf), "KK %s\n", client_blob); + } + return buf; +} + Auth::Direction Auth::Ntlm::UserRequest::module_direction() { @@ -79,7 +95,7 @@ } void -Auth::Ntlm::UserRequest::module_start(AUTHCB * handler, void *data) +Auth::Ntlm::UserRequest::module_start(HttpRequest *req, AccessLogEntry::Pointer &al, AUTHCB * handler, void *data) { static char buf[MAX_AUTHTOKEN_LEN]; @@ -94,12 +110,13 @@ debugs(29, 8, HERE << "credentials state is '" << user()->credentials() << "'"); - if (user()->credentials() == Auth::Pending) { - snprintf(buf, sizeof(buf), "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here? - } else { - snprintf(buf, sizeof(buf), "KK %s\n", client_blob); + if (!helperFormatedRequest(buf, sizeof(buf), request, al)) { + if (user()->credentials() == Auth::Pending) { + snprintf(buf, sizeof(buf), "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here? + } else { + snprintf(buf, sizeof(buf), "KK %s\n", client_blob); + } } - waiting = 1; safe_free(client_blob); @@ -276,10 +293,10 @@ debugs(29, 4, HERE << "authenticated user " << auth_user_request->user()->username()); /* see if this is an existing user with a different proxy_auth * string */ - AuthUserHashPointer *usernamehash = static_cast(hash_lookup(proxy_auth_username_cache, auth_user_request->user()->username())); + AuthUserHashPointer *usernamehash = static_cast(hash_lookup(proxy_auth_username_cache, auth_user_request->user()->userKey())); Auth::User::Pointer local_auth_user = lm_request->user(); while (usernamehash && (usernamehash->user()->auth_type != Auth::AUTH_NTLM || - strcmp(usernamehash->user()->username(), auth_user_request->user()->username()) != 0)) + strcmp(usernamehash->user()->userKey(), auth_user_request->user()->userKey()) != 0)) usernamehash = static_cast(usernamehash->next); if (usernamehash) { /* we can't seamlessly recheck the username due to the === modified file 'src/auth/ntlm/UserRequest.h' --- src/auth/ntlm/UserRequest.h 2013-10-25 00:13:46 +0000 +++ src/auth/ntlm/UserRequest.h 2013-10-29 08:06:01 +0000 @@ -26,7 +26,8 @@ virtual int authenticated() const; virtual void authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type); virtual Auth::Direction module_direction(); - virtual void module_start(AUTHCB *, void *); + virtual void module_start(HttpRequest *req, AccessLogEntry::Pointer &al, AUTHCB *, void *); + virtual const char *credentialsStr(); virtual const char * connLastHeader(); === modified file 'src/auth/ntlm/auth_ntlm.cc' --- src/auth/ntlm/auth_ntlm.cc 2013-10-25 00:13:46 +0000 +++ src/auth/ntlm/auth_ntlm.cc 2013-10-29 09:40:42 +0000 @@ -80,6 +80,8 @@ void Auth::Ntlm::Config::done() { + Auth::Config::done(); + authntlm_initialised = 0; if (ntlmauthenticators) { @@ -112,7 +114,7 @@ storeAppendPrintf(entry, "\n%s ntlm children %d startup=%d idle=%d concurrency=%d\n", name, authenticateChildren.n_max, authenticateChildren.n_startup, authenticateChildren.n_idle, authenticateChildren.concurrency); storeAppendPrintf(entry, "%s %s keep_alive %s\n", name, "ntlm", keep_alive ? "on" : "off"); - + Auth::Config::dump(entry, name, scheme); } Auth::Ntlm::Config::Config() : keep_alive(1) @@ -132,9 +134,8 @@ authenticateChildren.parseConfig(); } else if (strcmp(param_str, "keep_alive") == 0) { parse_onoff(&keep_alive); - } else { - debugs(29, DBG_CRITICAL, "ERROR unrecognised NTLM auth scheme parameter '" << param_str << "'"); - } + } else + Auth::Config::parse(scheme, n_configured, param_str); } const char * @@ -267,9 +268,9 @@ * Auth_user structure. */ Auth::UserRequest::Pointer -Auth::Ntlm::Config::decode(char const *proxy_auth) +Auth::Ntlm::Config::decode(char const *proxy_auth, const char *aRequestRealm) { - Auth::Ntlm::User *newUser = new Auth::Ntlm::User(Auth::Config::Find("ntlm")); + Auth::Ntlm::User *newUser = new Auth::Ntlm::User(Auth::Config::Find("ntlm"), aRequestRealm); Auth::UserRequest::Pointer auth_user_request = new Auth::Ntlm::UserRequest(); assert(auth_user_request->user() == NULL); === modified file 'src/auth/ntlm/auth_ntlm.h' --- src/auth/ntlm/auth_ntlm.h 2013-10-25 00:13:46 +0000 +++ src/auth/ntlm/auth_ntlm.h 2013-10-29 09:28:36 +0000 @@ -27,7 +27,7 @@ Config(); virtual bool active() const; virtual bool configured() const; - virtual Auth::UserRequest::Pointer decode(char const *proxy_auth); + virtual Auth::UserRequest::Pointer decode(char const *proxy_auth, const char *requestRealm); virtual void done(); virtual void rotateHelpers(); virtual void dump(StoreEntry *, const char *, Auth::Config *); === modified file 'src/cf.data.pre' --- src/cf.data.pre 2013-10-13 17:55:11 +0000 +++ src/cf.data.pre 2013-10-29 11:39:28 +0000 @@ -319,12 +319,41 @@ Ports flagged 'transparent', 'intercept', or 'tproxy' have authentication disabled. + === Parameters common to all schemes. === + + "program" cmdline + Specifies the command for the external authenticator. Such a program + runs a loop that, on every iteration, reads a request_format line from + the standard and responds with a scheme-specific answer. The loop + stops when all input is exchausted (EOF). See scheme-specific + "program" descriptions below for details. + + "request_format" format + Specifies request line format for the authentication helper. "Quoted" + format values may contain spaces and logformat %macros. In theory, any + logformat %macro can be used. In practice, a %macro expands as a dash + (-) if the helper request is sent before the required macro + information is available to Squid. By default, Squid uses request + formats provided in scheme-specific examples below (search for + %credentials). + + "request_realm" format + Specifies a custom format for the authenticated user cache key. See + request_format for %macro support information, but note that %un and + %credentials macors are expanded to - in this context: Squid always + adds user name to the key internally, so you do not need to do that + manually, and Squid does not store %credentials information in the + cache at all. You may need this option if you want to authenticate two + clients with equal user names separately, usually based on custom + request_format information such as http_port number. By default, Squid + uses request_format as request_realm. + === Parameters for the basic scheme follow. === "program" cmdline Specify the command for the external authenticator. Such a program - reads a line containing "username password" and replies with one of - three results: + reads a request_format line ("username password" by default) and + replies with one of three results: OK the user exists. @@ -404,11 +433,17 @@ makes a big difference for user_max_ip ACL processing and similar. auth_param basic casesensitive off + request_format format + Specifies request line format for the authentication helper. + See "Parameters common to all schemes" above for details. + Example: + auth_param basic request_format "%un %credentials" + === Parameters for the digest scheme follow === "program" cmdline - Specify the command for the external authenticator. Such - a program reads a line containing "username":"realm" and + Specify the command for the external authenticator. Such a program + reads a request_format line ("username":"realm" by default) and replies with one of three results: OK ha1="..." @@ -499,6 +534,12 @@ an incorrect request digest in POST requests when reusing the same nonce as acquired earlier on a GET request. + "request_format" format + Specifies request line format for the authentication helper. + See "Parameters common to all schemes" above for details. + Example: + auth_param digest request_format "\"%un\":\"%credentials\"" + === NTLM scheme options follow === "program" cmdline @@ -536,6 +577,12 @@ auth_param ntlm keep_alive on + "request_format" format + Specifies request line format for the authentication helper. + See "Parameters common to all schemes" above for details. + Example: + auth_param ntlm request_format "%credentials" + === Options for configuring the NEGOTIATE auth-scheme follow === "program" cmdline @@ -577,6 +624,11 @@ auth_param negotiate keep_alive on + "request_format" format + Specifies request line format for the authentication helper. + See "Parameters common to all schemes" above for details. + Example: + auth_param negotiate request_format "%credentials" Examples: @@ -3707,6 +3759,12 @@ ue User name from external acl helper ui User name from ident us User name from SSL + credentials Client credentials. The exact meaning depends on + the authentication scheme: For Basic authentication, + it is the password; for Digest, the realm sent by the + client; for NTLM and Negotiate, the client challenge + or client credentials prefixed with "YR " or "KK ". + Meant for use with proxy_auth scheme request_format. HTTP related format codes: === modified file 'src/client_side.cc' --- src/client_side.cc 2013-10-27 05:08:49 +0000 +++ src/client_side.cc 2013-10-29 07:42:47 +0000 @@ -633,13 +633,6 @@ if (loggingEntry() && loggingEntry()->mem_obj) al->cache.objectSize = loggingEntry()->contentLen(); - al->cache.caddr.setNoAddr(); - - if (getConn() != NULL) { - al->cache.caddr = getConn()->log_addr; - al->cache.port = cbdataReference(getConn()->port); - } - al->cache.requestSize = req_sz; al->cache.requestHeadersSize = req_sz; @@ -4324,7 +4317,7 @@ ConnStateData * conn = http->getConn(); ACLFilledChecklist *ch = new ACLFilledChecklist(acl, http->request, cbdataReferenceValid(conn) && conn != NULL && conn->clientConnection != NULL ? conn->clientConnection->rfc931 : dash_str); - + ch->al = http->al; /* * hack for ident ACL. It needs to get full addresses, and a place to store * the ident result on persistent connections... === modified file 'src/client_side_request.cc' --- src/client_side_request.cc 2013-10-25 00:13:46 +0000 +++ src/client_side_request.cc 2013-10-28 19:17:56 +0000 @@ -164,6 +164,9 @@ setConn(aConn); al = new AccessLogEntry; al->tcpClient = clientConnection = aConn->clientConnection; + al->cache.port = cbdataReference(aConn->port); + al->cache.caddr = aConn->log_addr; + #if USE_SSL if (aConn->clientConnection != NULL && aConn->clientConnection->isOpen()) { if (SSL *ssl = fd_table[aConn->clientConnection->fd].ssl) @@ -506,6 +509,7 @@ */ ConnStateData *conn = http->getConn(); conn->log_addr = request->indirect_client_addr; + http->al->cache.caddr = conn->log_addr; } request->x_forwarded_for_iterator.clean(); request->flags.done_follow_x_forwarded_for = true; @@ -1706,7 +1710,7 @@ calloutContext->adaptation_acl_check_done = true; if (Adaptation::AccessCheck::Start( Adaptation::methodReqmod, Adaptation::pointPreCache, - request, NULL, this)) + request, NULL, calloutContext->http->al, this)) return; // will call callback } #endif @@ -1855,7 +1859,7 @@ assert(!virginHeadSource); assert(!adaptedBodySource); virginHeadSource = initiateAdaptation( - new Adaptation::Iterator(request, NULL, g)); + new Adaptation::Iterator(request, NULL, al, g)); // we could try to guess whether we can bypass this adaptation // initiation failure, but it should not really happen === modified file 'src/format/ByteCode.h' --- src/format/ByteCode.h 2013-07-15 15:47:00 +0000 +++ src/format/ByteCode.h 2013-10-28 19:17:56 +0000 @@ -193,6 +193,7 @@ LFT_ICAP_OUTCOME, LFT_ICAP_STATUS_CODE, #endif + LFT_CREDENTIALS, #if USE_SSL LFT_SSL_BUMP_MODE, === modified file 'src/format/Format.cc' --- src/format/Format.cc 2013-07-15 15:47:00 +0000 +++ src/format/Format.cc 2013-10-29 08:03:07 +0000 @@ -1107,6 +1107,14 @@ } break; + case LFT_CREDENTIALS: +#if USE_AUTH + if (al->request && al->request->auth_user_request != NULL) + out = strOrNull(al->request->auth_user_request->credentialsStr()); +#endif + + break; + case LFT_PERCENT: out = "%"; === modified file 'src/format/Token.cc' --- src/format/Token.cc 2013-07-15 15:47:00 +0000 +++ src/format/Token.cc 2013-10-29 08:01:11 +0000 @@ -128,6 +128,7 @@ {"err_code", LFT_SQUID_ERROR }, {"err_detail", LFT_SQUID_ERROR_DETAIL }, {"note", LFT_NOTE }, + {"credentials", LFT_CREDENTIALS}, {NULL, LFT_NONE} /* this must be last */ }; === modified file 'src/peer_select.cc' --- src/peer_select.cc 2013-10-25 00:13:46 +0000 +++ src/peer_select.cc 2013-10-29 08:11:33 +0000 @@ -141,6 +141,7 @@ void peerSelect(Comm::ConnectionList * paths, HttpRequest * request, + AccessLogEntry::Pointer const &al, StoreEntry * entry, PSC * callback, void *callback_data) @@ -156,6 +157,7 @@ psstate->request = request; HTTPMSGLOCK(psstate->request); + psstate->al = al; psstate->entry = entry; psstate->paths = paths; @@ -439,13 +441,17 @@ if (ps->always_direct == ACCESS_DUNNO) { debugs(44, 3, "peerSelectFoo: direct = " << DirectStr[ps->direct] << " (always_direct to be checked)"); /** check always_direct; */ - ps->acl_checklist = new ACLFilledChecklist(Config.accessList.AlwaysDirect, request, NULL); + ACLFilledChecklist *ch = new ACLFilledChecklist(Config.accessList.AlwaysDirect, request, NULL); + ch->al = ps->al; + ps->acl_checklist = ch; ps->acl_checklist->nonBlockingCheck(peerCheckAlwaysDirectDone, ps); return; } else if (ps->never_direct == ACCESS_DUNNO) { debugs(44, 3, "peerSelectFoo: direct = " << DirectStr[ps->direct] << " (never_direct to be checked)"); /** check never_direct; */ - ps->acl_checklist = new ACLFilledChecklist(Config.accessList.NeverDirect, request, NULL); + ACLFilledChecklist *ch = new ACLFilledChecklist(Config.accessList.NeverDirect, request, NULL); + ch->al = ps->al; + ps->acl_checklist = ch; ps->acl_checklist->nonBlockingCheck(peerCheckNeverDirectDone, ps); return; } else if (request->flags.noDirect) { === modified file 'src/tunnel.cc' --- src/tunnel.cc 2013-10-25 00:13:46 +0000 +++ src/tunnel.cc 2013-10-28 19:17:59 +0000 @@ -901,7 +901,7 @@ CommTimeoutCbPtrFun(tunnelTimeout, tunnelState)); commSetConnTimeout(tunnelState->client.conn, Config.Timeout.lifetime, timeoutCall); - peerSelect(&(tunnelState->serverDestinations), request, + peerSelect(&(tunnelState->serverDestinations), request, al, NULL, tunnelPeerSelectComplete, tunnelState);