------------------------------------------------------------ revno: 13172 revision-id: chtsanti@users.sourceforge.net-20131206145947-k5xc0wo3d63n9bff parent: chtsanti@users.sourceforge.net-20131206110950-sg7fx6ci5goead0u committer: Christos Tsantilas branch nick: trunk timestamp: Fri 2013-12-06 16:59:47 +0200 message: Add key_extras to proxy authentication schemes. The key_extras value is a "quoted string" with logformat %macro support. It is appended to request line for the authentication helper. Example usage: auth_param basic key_extras "thePort:%>lp" auth_param digest key_extras "LocalIP=%>la:%lp" This is a Measurement Factory project. ------------------------------------------------------------ # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: chtsanti@users.sourceforge.net-20131206145947-\ # k5xc0wo3d63n9bff # target_branch: http://bzr.squid-cache.org/bzr/squid3/trunk/ # testament_sha1: 271cb458792bd260bd2875906c9b5d026255e564 # timestamp: 2013-12-06 15:53:44 +0000 # source_branch: http://bzr.squid-cache.org/bzr/squid3/trunk/ # base_revision_id: chtsanti@users.sourceforge.net-20131206110950-\ # sg7fx6ci5goead0u # # Begin patch === modified file 'src/AccessLogEntry.h' --- src/AccessLogEntry.h 2013-12-05 11:04:45 +0000 +++ src/AccessLogEntry.h 2013-12-06 14:59:47 +0000 @@ -169,7 +169,7 @@ ssluser(NULL), #endif port(NULL) { - ; + caddr.setNoAddr(); } Ip::Address caddr; === modified file 'src/FwdState.cc' --- src/FwdState.cc 2013-12-02 18:33:26 +0000 +++ src/FwdState.cc 2013-12-06 14:59:47 +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-12-06 14:59:47 +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/acl/FilledChecklist.h' --- src/acl/FilledChecklist.h 2013-06-06 13:53:16 +0000 +++ src/acl/FilledChecklist.h 2013-12-06 14:59:47 +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-12-05 11:04:45 +0000 +++ src/adaptation/AccessCheck.cc 2013-12-06 14:59:47 +0000 @@ -126,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/auth/Acl.cc' --- src/auth/Acl.cc 2013-10-25 00:13:46 +0000 +++ src/auth/Acl.cc 2013-12-06 14:59:47 +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-12-06 14:59:47 +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-12-06 14:59:47 +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,17 @@ "Unsupported or unconfigured/inactive proxy-auth scheme, '" << proxy_auth << "'"); return NULL; } + static MemBuf rmb; + rmb.reset(); + if (config->keyExtras) { + // %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->keyExtras->assemble(rmb, al, 0); + } - return config->decode(proxy_auth); + return config->decode(proxy_auth, rmb.hasContent() ? rmb.content() : NULL); } Auth::Config * @@ -76,3 +89,43 @@ void Auth::Config::registerWithCacheManager(void) {} + +void +Auth::Config::parse(Auth::Config * scheme, int n_configured, char *param_str) +{ + if (strcmp(param_str, "key_extras") == 0) { + keyExtrasLine = ConfigParser::NextQuotedToken(); + Format::Format *nlf = new ::Format::Format(scheme->type()); + if (!nlf->parse(keyExtrasLine.termedBuf())) { + debugs(29, DBG_CRITICAL, "FATAL: Failed parsing key_extras formatting value"); + self_destruct(); + return; + } + if (keyExtras) + delete keyExtras; + + keyExtras = nlf; + + if (char *t = strtok(NULL, w_space)) { + debugs(29, DBG_CRITICAL, "FATAL: Unexpected argument '" << t << "' after request_format specification"); + self_destruct(); + } + } else { + debugs(29, DBG_CRITICAL, "Unrecognised " << scheme->type() << " auth scheme parameter '" << param_str << "'"); + } +} + +void +Auth::Config::dump(StoreEntry *entry, const char *name, Auth::Config *scheme) +{ + if (keyExtrasLine.size() > 0) + storeAppendPrintf(entry, "%s %s key_extras \"%s\"\n", name, scheme->type(), keyExtrasLine.termedBuf()); +} + +void +Auth::Config::done() +{ + delete keyExtras; + keyExtras = NULL; + keyExtrasLine.clean(); +} === modified file 'src/auth/Config.h' --- src/auth/Config.h 2012-09-01 14:38:36 +0000 +++ src/auth/Config.h 2013-12-06 14:59:47 +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), keyExtras(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,8 @@ public: HelperChildConfig authenticateChildren; wordlist *authenticateProgram; ///< Helper program to run, includes all parameters + String keyExtrasLine; ///< The format of the request to the auth helper + Format::Format *keyExtras; ///< The compiled request format }; 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-12-06 14:59:47 +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-31 06:28:58 +0000 +++ src/auth/User.cc 2013-12-06 14:59:47 +0000 @@ -49,14 +49,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; @@ -338,6 +339,14 @@ debugs(29, 2, HERE << "user '" << username() << "' has been seen at a new IP address (" << ipaddr << ")"); } +SBuf +Auth::User::BuildUserKey(const char *username, const char *realm) +{ + SBuf key; + key.Printf("%s:%s", username, realm); + return key; +} + /** * Add the Auth::User structure to the username cache. */ @@ -390,6 +399,8 @@ if (aString) { assert(!username_); username_ = xstrdup(aString); + if (!requestRealm_.isEmpty()) + userKey_ = BuildUserKey(username_, requestRealm_.c_str()); } else { safe_free(username_); } === modified file 'src/auth/User.h' --- src/auth/User.h 2013-10-31 06:28:58 +0000 +++ src/auth/User.h 2013-12-06 14:59:47 +0000 @@ -40,6 +40,7 @@ #include "dlink.h" #include "ip/Address.h" #include "Notes.h" +#include "SBuf.h" class AuthUserHashPointer; class StoreEntry; @@ -82,12 +83,15 @@ public: static void cacheInit(); static void CachedACLsReset(); + static SBuf BuildUserKey(const char *username, const char *realm); void absorb(Auth::User::Pointer from); virtual ~User(); char const *username() const { return username_; } void username(char const *); + const char *userKey() {return !userKey_.isEmpty() ? userKey_.c_str() : 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. + */ + SBuf requestRealm_; + + /** + * A Unique key for the user, consist by username and requestRealm_ + */ + SBuf 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-11-11 11:24:23 +0000 +++ src/auth/UserRequest.cc 2013-12-06 14:59:47 +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,20 @@ { return Auth::Scheme::Find(user()->config->type()); } + +const char * +Auth::UserRequest::helperRequestKeyExtras(HttpRequest *request, AccessLogEntry::Pointer &al) +{ + if (Format::Format *reqFmt = user()->config->keyExtras) { + static MemBuf mb; + mb.reset(); + // 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; + debugs(29, 5, "Assembled line to send :" << mb.content()); + return mb.content(); + } + return NULL; +} === modified file 'src/auth/UserRequest.h' --- src/auth/UserRequest.h 2013-10-25 00:13:46 +0000 +++ src/auth/UserRequest.h 2013-12-06 14:59:47 +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; + + const char *helperRequestKeyExtras(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-12-06 14:59:47 +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-12-06 14:59:47 +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-12-06 14:59:47 +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()); @@ -120,7 +133,12 @@ xstrncpy(usern, rfc1738_escape(user()->username()), sizeof(usern)); xstrncpy(pass, rfc1738_escape(basic_auth->passwd), sizeof(pass)); } - int sz = snprintf(buf, sizeof(buf), "%s %s\n", usern, pass); + int sz = 0; + if (const char *keyExtras = helperRequestKeyExtras(request, al)) + sz = snprintf(buf, sizeof(buf), "%s %s %s\n", usern, pass, keyExtras); + else + 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-12-06 14:59:47 +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-12-06 14:59:47 +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, "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-12-06 14:59:47 +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-12-06 14:59:47 +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-12-06 14:59:47 +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-11-21 23:58:59 +0000 +++ src/auth/digest/UserRequest.cc 2013-12-06 14:59:47 +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,19 @@ return; } + const char *keyExtras = helperRequestKeyExtras(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); + if (keyExtras) + snprintf(buf, 8192, "\"%s\":\"%s\" %s\n", userstr, realm, keyExtras); + else + snprintf(buf, 8192, "\"%s\":\"%s\"\n", userstr, realm); } else { - snprintf(buf, 8192, "\"%s\":\"%s\"\n", user()->username(), realm); + if (keyExtras) + snprintf(buf, 8192, "\"%s\":\"%s\" %s\n", user()->username(), realm, keyExtras); + 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-12-06 14:59:47 +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-11-26 09:43:29 +0000 +++ src/auth/digest/auth_digest.cc 2013-12-06 14:59:47 +0000 @@ -477,12 +477,12 @@ /* USER related functions */ static Auth::User::Pointer -authDigestUserFindUsername(const char *username) +authDigestUserFindUsername(const char *userkey) { AuthUserHashPointer *usernamehash; - debugs(29, 9, HERE << "Looking for user '" << username << "'"); + debugs(29, 9, "Looking for user '" << userkey << "'"); - if (username && (usernamehash = static_cast < AuthUserHashPointer * >(hash_lookup(proxy_auth_username_cache, username)))) { + if ((usernamehash = static_cast < AuthUserHashPointer * >(hash_lookup(proxy_auth_username_cache, userkey)))) { 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; @@ -944,7 +946,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; } @@ -955,7 +957,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; } @@ -963,7 +965,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; } @@ -971,7 +973,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; } @@ -980,7 +982,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; } @@ -988,7 +990,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; } @@ -999,7 +1001,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; } @@ -1011,7 +1013,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; } @@ -1019,7 +1021,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; } @@ -1027,7 +1029,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; } @@ -1035,7 +1037,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; } @@ -1050,7 +1052,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; } @@ -1061,7 +1063,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; } @@ -1075,10 +1077,11 @@ Auth::User::Pointer auth_user; - if ((auth_user = authDigestUserFindUsername(username)) == NULL) { + SBuf key = Auth::User::BuildUserKey(username, aRequestRealm); + if (key.isEmpty() || (auth_user = authDigestUserFindUsername(key.c_str())) == 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-12-06 14:59:47 +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-12-06 14:59:47 +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-12-06 14:59:47 +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-12-06 14:59:47 +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,17 @@ debugs(29, 8, HERE << "credentials state is '" << user()->credentials() << "'"); + const char *keyExtras = helperRequestKeyExtras(request, al); if (user()->credentials() == Auth::Pending) { - snprintf(buf, sizeof(buf), "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here? + if (keyExtras) + snprintf(buf, sizeof(buf), "YR %s %s\n", client_blob, keyExtras); + else + 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 (keyExtras) + snprintf(buf, sizeof(buf), "KK %s %s\n", client_blob, keyExtras); + else + snprintf(buf, sizeof(buf), "KK %s\n", client_blob); } waiting = 1; @@ -283,10 +305,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-12-06 14:59:47 +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-12-06 14:59:47 +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-12-06 14:59:47 +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-12-06 14:59:47 +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-12-06 14:59:47 +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-12-06 14:59:47 +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,18 @@ debugs(29, 8, HERE << "credentials state is '" << user()->credentials() << "'"); + const char *keyExtras = helperRequestKeyExtras(request, al); if (user()->credentials() == Auth::Pending) { - snprintf(buf, sizeof(buf), "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here? + if (keyExtras) + snprintf(buf, sizeof(buf), "YR %s %s\n", client_blob, keyExtras); + else + 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 (keyExtras) + snprintf(buf, sizeof(buf), "KK %s %s\n", client_blob, keyExtras); + else + snprintf(buf, sizeof(buf), "KK %s\n", client_blob); } - waiting = 1; safe_free(client_blob); @@ -276,10 +298,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-12-06 14:59:47 +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-12-06 14:59:47 +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-12-06 14:59:47 +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-12-05 11:04:45 +0000 +++ src/cf.data.pre 2013-12-06 14:59:47 +0000 @@ -319,12 +319,30 @@ 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 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. + + "key_extras" format + Specifies a string to be append to 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). + === 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. @@ -407,8 +425,8 @@ === 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="..." @@ -576,7 +594,6 @@ supported by the proxy. auth_param negotiate keep_alive on - Examples: @@ -3726,6 +3743,11 @@ 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 ". HTTP related format codes: === modified file 'src/client_side.cc' --- src/client_side.cc 2013-12-05 11:04:45 +0000 +++ src/client_side.cc 2013-12-06 14:59:47 +0000 @@ -633,13 +633,6 @@ if (loggingEntry() && loggingEntry()->mem_obj) al->cache.objectSize = loggingEntry()->contentLen(); // payload duplicate ?? with or without TE ? - al->cache.caddr.setNoAddr(); - - if (getConn() != NULL) { - al->cache.caddr = getConn()->log_addr; - al->cache.port = cbdataReference(getConn()->port); - } - al->http.clientRequestSz.header = req_sz; al->http.clientReplySz.header = out.headers_sz; // XXX: calculate without payload encoding or headers !! @@ -4323,7 +4316,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-12-05 11:04:45 +0000 +++ src/client_side_request.cc 2013-12-06 14:59:47 +0000 @@ -164,6 +164,9 @@ al = new AccessLogEntry; al->cache.start_time = current_time; 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) @@ -507,6 +510,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; === modified file 'src/format/ByteCode.h' --- src/format/ByteCode.h 2013-12-05 11:04:45 +0000 +++ src/format/ByteCode.h 2013-12-06 14:59:47 +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-12-05 11:04:45 +0000 +++ src/format/Format.cc 2013-12-06 14:59:47 +0000 @@ -1115,6 +1115,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-12-05 11:04:45 +0000 +++ src/format/Token.cc 2013-12-06 14:59:47 +0000 @@ -129,6 +129,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-12-06 14:59:47 +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/tests/stub_libauth.cc' --- src/tests/stub_libauth.cc 2013-11-05 06:26:39 +0000 +++ src/tests/stub_libauth.cc 2013-12-06 14:59:47 +0000 @@ -5,7 +5,7 @@ #if USE_AUTH #include "auth/Config.h" -Auth::UserRequest::Pointer Auth::Config::CreateAuthUser(const char *) STUB_RETVAL(NULL) +Auth::UserRequest::Pointer Auth::Config::CreateAuthUser(const char *, AccessLogEntry::Pointer &al) STUB_RETVAL(NULL) Auth::Config * Auth::Config::Find(const char *) STUB_RETVAL(NULL) void Auth::Config::registerWithCacheManager(void) STUB_NOP Auth::ConfigVector Auth::TheConfig; @@ -28,7 +28,7 @@ void Auth::Scheme::FreeAll() STUB #include "auth/User.h" -Auth::User::User(Auth::Config *) STUB +Auth::User::User(Auth::Config *, const char *) STUB Auth::CredentialState Auth::User::credentials() const STUB_RETVAL(credentials_state) void Auth::User::credentials(CredentialState) STUB void Auth::User::absorb(Auth::User::Pointer) STUB @@ -44,7 +44,7 @@ #include "auth/UserRequest.h" char const * Auth::UserRequest::username() const STUB_RETVAL("stub_username") -void Auth::UserRequest::start(AUTHCB *, void *) STUB +void Auth::UserRequest::start(HttpRequest *, AccessLogEntry::Pointer &, AUTHCB *, void *) STUB bool Auth::UserRequest::valid() const STUB_RETVAL(false) void * Auth::UserRequest::operator new (size_t) STUB_RETVAL((void *)1) void Auth::UserRequest::operator delete (void *) STUB @@ -62,8 +62,8 @@ void Auth::UserRequest::addAuthenticationInfoTrailer(HttpReply *, int) STUB void Auth::UserRequest::releaseAuthServer() STUB const char * Auth::UserRequest::connLastHeader() STUB_RETVAL("stub") -AuthAclState Auth::UserRequest::authenticate(Auth::UserRequest::Pointer *, http_hdr_type, HttpRequest *, ConnStateData *, Ip::Address &) STUB_RETVAL(AUTH_AUTHENTICATED) -AuthAclState Auth::UserRequest::tryToAuthenticateAndSetAuthUser(Auth::UserRequest::Pointer *, http_hdr_type, HttpRequest *, ConnStateData *, Ip::Address &) STUB_RETVAL(AUTH_AUTHENTICATED) +AuthAclState Auth::UserRequest::authenticate(Auth::UserRequest::Pointer *, http_hdr_type, HttpRequest *, ConnStateData *, Ip::Address &, AccessLogEntry::Pointer &) STUB_RETVAL(AUTH_AUTHENTICATED) +AuthAclState Auth::UserRequest::tryToAuthenticateAndSetAuthUser(Auth::UserRequest::Pointer *, http_hdr_type, HttpRequest *, ConnStateData *, Ip::Address &, AccessLogEntry::Pointer &) STUB_RETVAL(AUTH_AUTHENTICATED) void Auth::UserRequest::addReplyAuthHeader(HttpReply *, Auth::UserRequest::Pointer, HttpRequest *, int, int) STUB void authenticateFixHeader(HttpReply *, Auth::UserRequest::Pointer, HttpRequest *, int, int) STUB void authenticateAddTrailer(HttpReply *, Auth::UserRequest::Pointer, HttpRequest *, int) STUB === modified file 'src/tunnel.cc' --- src/tunnel.cc 2013-10-25 00:13:46 +0000 +++ src/tunnel.cc 2013-12-06 14:59:47 +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);