=== modified file 'configure.ac' --- configure.ac 2014-07-13 08:49:42 +0000 +++ configure.ac 2014-07-30 23:59:58 +0000 @@ -1765,40 +1765,53 @@ SQUID_YESNO([$enableval], [unrecognized argument to --enable-auth: $enableval]) ]) AC_MSG_NOTICE([Authentication support enabled: ${enable_auth:=yes}]) SQUID_DEFINE_BOOL(USE_AUTH,$enable_auth,[Enable support for authentication]) AM_CONDITIONAL(ENABLE_AUTH, test "x$enable_auth" != "xno") AUTH_MODULES="" AC_ARG_ENABLE(auth-basic, AS_HELP_STRING([--enable-auth-basic="list of helpers"], [Enable the basic authentication scheme, and build the specified helpers. Not providing an explicit list of helpers will attempt build of all possible helpers. Default is to do so. To disable the basic authentication scheme, use --disable-auth-basic. To enable but build no helpers, specify "none". To see available helpers, see the helpers/basic_auth directory. ]),[ #nothing to do really ]) m4_include([helpers/basic_auth/modules.m4]) +AC_ARG_ENABLE(auth-bearer, + AS_HELP_STRING([--enable-auth-bearer="list of helpers"], + [Enable the OAuth 2.0 Bearer authentication scheme, and build the + specified helpers. + Not providing an explicit list of helpers will attempt build of + all possible helpers. Default is to do so. + To disable the Bearer authentication scheme, use --disable-auth-bearer. + To enable but build no helpers, specify "none". + To see available helpers, see the helpers/bearer_auth directory. ]),[ +#nothing to do really +]) +m4_include([helpers/bearer_auth/modules.m4]) + AC_ARG_ENABLE(auth-ntlm, AS_HELP_STRING([--enable-auth-ntlm="list of helpers"], [Enable the NTLM authentication scheme, and build the specified helpers. Not providing an explicit list of helpers will attempt build of all possible helpers. Default is to do so. To disable the NTLM authentication scheme, use --disable-auth-ntlm. To enable but build no helpers, specify "none". To see available helpers, see the helpers/ntlm_auth directory. ]),[ ]) m4_include([helpers/ntlm_auth/modules.m4]) AC_ARG_ENABLE(auth-negotiate, AS_HELP_STRING([--enable-auth-negotiate="list of helpers"], [Enable the Negotiate authentication scheme, and build the specified helpers. Not providing an explicit list of helpers will attempt build of all possible helpers. Default is to do so. To disable the Negotiate authentication scheme, use --disable-auth-negotiate. To enable but build no helpers, specify "none". @@ -3446,40 +3459,41 @@ AC_CONFIG_FILES([ Makefile compat/Makefile lib/Makefile lib/ntlmauth/Makefile lib/libTrie/Makefile lib/libTrie/test/Makefile lib/profiler/Makefile lib/rfcnb/Makefile lib/smblib/Makefile lib/snmplib/Makefile scripts/Makefile src/Makefile src/anyp/Makefile src/base/Makefile src/acl/Makefile src/fs/Makefile src/repl/Makefile src/auth/Makefile src/auth/basic/Makefile + src/auth/bearer/Makefile src/auth/digest/Makefile src/auth/negotiate/Makefile src/auth/ntlm/Makefile src/adaptation/Makefile src/adaptation/icap/Makefile src/adaptation/ecap/Makefile src/comm/Makefile src/esi/Makefile src/eui/Makefile src/format/Makefile src/http/Makefile src/icmp/Makefile src/ident/Makefile src/ip/Makefile src/log/Makefile src/ipc/Makefile src/ssl/Makefile src/mgr/Makefile src/parser/Makefile src/snmp/Makefile @@ -3488,40 +3502,42 @@ errors/Makefile test-suite/Makefile doc/Makefile doc/manuals/Makefile helpers/Makefile helpers/basic_auth/Makefile helpers/basic_auth/DB/Makefile helpers/basic_auth/fake/Makefile helpers/basic_auth/getpwnam/Makefile helpers/basic_auth/LDAP/Makefile helpers/basic_auth/MSNT/Makefile helpers/basic_auth/MSNT-multi-domain/Makefile helpers/basic_auth/NCSA/Makefile helpers/basic_auth/NIS/Makefile helpers/basic_auth/PAM/Makefile helpers/basic_auth/POP3/Makefile helpers/basic_auth/RADIUS/Makefile helpers/basic_auth/SASL/Makefile helpers/basic_auth/SMB/Makefile helpers/basic_auth/SSPI/Makefile + helpers/bearer_auth/Makefile + helpers/bearer_auth/fake/Makefile helpers/digest_auth/Makefile helpers/digest_auth/eDirectory/Makefile helpers/digest_auth/file/Makefile helpers/digest_auth/LDAP/Makefile helpers/ntlm_auth/Makefile helpers/ntlm_auth/fake/Makefile helpers/ntlm_auth/smb_lm/Makefile helpers/ntlm_auth/SSPI/Makefile helpers/negotiate_auth/Makefile helpers/negotiate_auth/kerberos/Makefile helpers/negotiate_auth/SSPI/Makefile helpers/negotiate_auth/wrapper/Makefile helpers/external_acl/Makefile helpers/external_acl/AD_group/Makefile helpers/external_acl/delayer/Makefile helpers/external_acl/eDirectory_userip/Makefile helpers/external_acl/file_userip/Makefile helpers/external_acl/kerberos_ldap_group/Makefile helpers/external_acl/LDAP_group/Makefile helpers/external_acl/LM_group/Makefile === modified file 'helpers/Makefile.am' --- helpers/Makefile.am 2013-07-09 11:15:51 +0000 +++ helpers/Makefile.am 2014-05-22 09:19:25 +0000 @@ -1,30 +1,32 @@ EXTRA_DIST = defines.h DIST_SUBDIRS = \ basic_auth \ + bearer_auth \ digest_auth \ external_acl \ log_daemon \ negotiate_auth \ ntlm_auth \ url_rewrite \ ssl \ storeid_rewrite SUBDIRS = \ basic_auth \ + bearer_auth \ digest_auth \ external_acl \ log_daemon \ negotiate_auth \ url_rewrite \ storeid_rewrite if ENABLE_AUTH_NTLM SUBDIRS += ntlm_auth endif if ENABLE_SSL SUBDIRS += ssl endif === added directory 'helpers/bearer_auth' === added file 'helpers/bearer_auth/Makefile.am' --- helpers/bearer_auth/Makefile.am 1970-01-01 00:00:00 +0000 +++ helpers/bearer_auth/Makefile.am 2014-05-22 09:19:10 +0000 @@ -0,0 +1,7 @@ +## Alphabetical list of sub-directories to distribute with Squid: +DIST_SUBDIRS = \ + fake + +SUBDIRS = $(BEARER_AUTH_HELPERS) + +EXTRA_DIST = modules.m4 === added directory 'helpers/bearer_auth/fake' === added file 'helpers/bearer_auth/fake/Makefile.am' --- helpers/bearer_auth/fake/Makefile.am 1970-01-01 00:00:00 +0000 +++ helpers/bearer_auth/fake/Makefile.am 2014-05-22 09:19:10 +0000 @@ -0,0 +1,8 @@ +include $(top_srcdir)/src/Common.am + +libexec_PROGRAMS = bearer_fake_auth +bearer_fake_auth_SOURCES = fake.cc + +LDADD = $(COMPAT_LIB) + +EXTRA_DIST = required.m4 === added file 'helpers/bearer_auth/fake/fake.cc' --- helpers/bearer_auth/fake/fake.cc 1970-01-01 00:00:00 +0000 +++ helpers/bearer_auth/fake/fake.cc 2014-05-26 07:54:14 +0000 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2014, Treehouse Networks Ltd. New Zealand + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Fake Bearer Authentication program for Squid. + * + * This code gets the user details and returns OK. + * It is intended for testing use and as a base for further implementation. + */ + +#include "squid.h" +#include "helpers/defines.h" + +#include + +/** + * options: + * -d enable debugging. + * -h interface help. + */ +char *program_name = NULL; + +static void +usage(void) +{ + fprintf(stderr, + "Usage: %s [-d] [-v] [-h]\n" + " -d enable debugging.\n" + " -h this message\n\n", + program_name); +} + +static void +process_options(int argc, char *argv[]) +{ + int opt; + + opterr = 0; + while (-1 != (opt = getopt(argc, argv, "hd"))) { + switch (opt) { + case 'd': + debug_enabled = 1; + break; + case 'h': + usage(); + exit(0); + default: + fprintf(stderr, "%s: FATAL: unknown option: -%c. Exiting\n", program_name, opt); + usage(); + exit(1); + } + } +} + +int +main(int argc, char *argv[]) +{ + char buf[HELPER_INPUT_BUFFER]; + int buflen = 0; + + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + program_name = argv[0]; + + process_options(argc, argv); + + debug("%s build " __DATE__ ", " __TIME__ " starting up...\n", program_name); + + while (fgets(buf, HELPER_INPUT_BUFFER, stdin) != NULL) { + char *p; + + if ((p = strchr(buf, '\n')) != NULL) { + *p = '\0'; /* strip \n */ + buflen = p - buf; /* length is known already */ + } else + buflen = strlen(buf); /* keep this so we only scan the buffer for \0 once per loop */ + + debug("Got %d bytes '%s' from Squid\n", buflen, buf); + + /* send 'OK' result back to Squid */ + fprintf(stdout, "OK user=fake/%s ttl=60\n", buf); + } + debug("%s build " __DATE__ ", " __TIME__ " shutting down...\n", program_name); + return 0; +} === added file 'helpers/bearer_auth/fake/required.m4' --- helpers/bearer_auth/fake/required.m4 1970-01-01 00:00:00 +0000 +++ helpers/bearer_auth/fake/required.m4 2014-05-21 06:20:59 +0000 @@ -0,0 +1 @@ +BUILD_HELPER="fake" === added file 'helpers/bearer_auth/modules.m4' --- helpers/bearer_auth/modules.m4 1970-01-01 00:00:00 +0000 +++ helpers/bearer_auth/modules.m4 2014-05-21 06:24:16 +0000 @@ -0,0 +1,56 @@ +# This file is supposed to run all the tests required to identify which +# configured modules are able to be built in this environment + +# FIXME: de-duplicate $enable_auth_bearer list containing double entries. + +#not specified. Inherit global +if test "x$enable_auth_bearer" = "x"; then + enable_auth_bearer=$enable_auth +fi +#conflicts with global +if test "x$enable_auth_bearer" != "xno" -a "x$enable_auth" = "xno" ; then + AC_MSG_ERROR([Bearer auth requested but auth disabled]) +fi +#define list of modules to build +if test "x$enable_auth_bearer" = "xyes" ; then + SQUID_LOOK_FOR_MODULES([$srcdir/helpers/bearer_auth],[enable_auth_bearer]) +fi +#handle the "none" special case +if test "x$enable_auth_bearer" = "xnone" ; then + enable_auth_bearer="" +fi + +BEARER_AUTH_HELPERS="" +#enable_auth_bearer contains either "no" or the list of modules to be built +enable_auth_bearer="`echo $enable_auth_bearer| sed -e 's/,/ /g;s/ */ /g'`" +if test "x$enable_auth_bearer" != "xno" ; then + AUTH_MODULES="$AUTH_MODULES bearer" + AC_DEFINE([HAVE_AUTH_MODULE_BEARER],1,[Bearer auth module is built]) + for helper in $enable_auth_bearer; do + dir="$srcdir/helpers/bearer_auth/$helper" + + # modules converted to autoconf macros already + # NP: we only need this list because m4_include() does not accept variables + if test "x$helper" = "xfake" ; then + m4_include([helpers/bearer_auth/fake/required.m4]) + + # modules not yet converted to autoconf macros (or third party drop-in's) + elif test -f "$dir/config.test" && sh "$dir/config.test" "$squid_host_os"; then + BUILD_HELPER="$helper" + fi + + if test -d "$srcdir/helpers/bearer_auth/$helper"; then + if test "$BUILD_HELPER" != "$helper"; then + AC_MSG_NOTICE([Bearer auth helper $helper ... found but cannot be built]) + else + BEARER_AUTH_HELPERS="$BEARER_AUTH_HELPERS $BUILD_HELPER" + fi + else + AC_MSG_ERROR([Bearer auth helper $helper ... not found]) + fi + done +fi + +AC_MSG_NOTICE([Bearer auth helpers to be built: $BEARER_AUTH_HELPERS]) +AM_CONDITIONAL(ENABLE_AUTH_BEARER, test "x$enable_auth_bearer" != "xno") +AC_SUBST(BEARER_AUTH_HELPERS) === modified file 'src/AuthReg.cc' --- src/AuthReg.cc 2012-08-31 16:57:39 +0000 +++ src/AuthReg.cc 2014-05-22 09:21:50 +0000 @@ -1,48 +1,55 @@ #include "squid.h" #if USE_AUTH #include "AuthReg.h" #if HAVE_AUTH_MODULE_BASIC #include "auth/basic/Scheme.h" #endif +#if HAVE_AUTH_MODULE_BEARER +#include "auth/bearer/Scheme.h" +#endif #if HAVE_AUTH_MODULE_DIGEST #include "auth/digest/Scheme.h" #endif #if HAVE_AUTH_MODULE_NEGOTIATE #include "auth/negotiate/Scheme.h" #endif #if HAVE_AUTH_MODULE_NTLM #include "auth/ntlm/Scheme.h" #endif #include "Debug.h" /** * Initialize the authentication modules (if any) * This is required once, before any configuration actions are taken. */ void Auth::Init() { debugs(29,DBG_IMPORTANT,"Startup: Initializing Authentication Schemes ..."); #if HAVE_AUTH_MODULE_BASIC static const char *basic_type = Auth::Basic::Scheme::GetInstance()->type(); debugs(29,DBG_IMPORTANT,"Startup: Initialized Authentication Scheme '" << basic_type << "'"); #endif +#if HAVE_AUTH_MODULE_BEARER + static const char *bearer_type = Auth::Bearer::Scheme::GetInstance()->type(); + debugs(29,DBG_IMPORTANT,"Startup: Initialized Authentication Scheme '" << bearer_type << "'"); +#endif #if HAVE_AUTH_MODULE_DIGEST static const char *digest_type = Auth::Digest::Scheme::GetInstance()->type(); debugs(29,DBG_IMPORTANT,"Startup: Initialized Authentication Scheme '" << digest_type << "'"); #endif #if HAVE_AUTH_MODULE_NEGOTIATE static const char *negotiate_type = Auth::Negotiate::Scheme::GetInstance()->type(); debugs(29,DBG_IMPORTANT,"Startup: Initialized Authentication Scheme '" << negotiate_type << "'"); #endif #if HAVE_AUTH_MODULE_NTLM static const char *ntlm_type = Auth::Ntlm::Scheme::GetInstance()->type(); debugs(29,DBG_IMPORTANT,"Startup: Initialized Authentication Scheme '" << ntlm_type << "'"); #endif debugs(29,DBG_IMPORTANT,"Startup: Initialized Authentication."); } #endif /* USE_AUTH */ === modified file 'src/auth/Makefile.am' --- src/auth/Makefile.am 2013-10-31 04:39:36 +0000 +++ src/auth/Makefile.am 2014-05-22 09:21:41 +0000 @@ -1,25 +1,25 @@ include $(top_srcdir)/src/Common.am include $(top_srcdir)/src/TestHeaders.am SUBDIRS = $(AUTH_MODULES) -DIST_SUBDIRS = basic digest negotiate ntlm +DIST_SUBDIRS = basic bearer digest negotiate ntlm noinst_LTLIBRARIES = libauth.la libacls.la ## not needed? $(AUTH_LIBS_TO_BUILD) ## EXTRA_LTLIBRARIES = libdigest.la libntlm.la libnegotiate.la ## authentication framework; this library is always built libauth_la_SOURCES = \ Type.h \ Type.cc \ Config.cc \ Config.h \ CredentialState.cc \ CredentialState.h \ Gadgets.cc \ Gadgets.h \ QueueNode.h \ Scheme.cc \ Scheme.h \ State.h \ State.cc \ === modified file 'src/auth/QueueNode.h' --- src/auth/QueueNode.h 2013-03-25 05:41:24 +0000 +++ src/auth/QueueNode.h 2014-05-29 06:14:35 +0000 @@ -1,26 +1,31 @@ #ifndef SQUID_SRC_AUTH_QUEUENODE_H #define SQUID_SRC_AUTH_QUEUENODE_H +// NP: keep in sync with auth/UserRequest.h definition +typedef void AUTHCB(void*); + namespace Auth { +class UserRequest; + /** * A queue of auth requests waiting for verification to occur. * * Certain authentication schemes such a Basic and Bearer auth * permit credentials tokens to be repeated from multiple sources * simultaneously. This queue node allows multiple validation * queries to be collapsed into one backend helper lookup. * CBDATA and handlers stored in these queue nodes can be notified * all at once with a result when the lookup completes. */ class QueueNode { private: // we store CBDATA here, copy is not safe QueueNode(const QueueNode &); QueueNode &operator =(const QueueNode &); public: QueueNode(Auth::UserRequest *aRequest, AUTHCB *aHandler, void *aData) : === modified file 'src/auth/Type.h' --- src/auth/Type.h 2011-03-28 13:47:37 +0000 +++ src/auth/Type.h 2014-05-22 09:21:48 +0000 @@ -1,23 +1,24 @@ #ifndef _SQUID__SRC_AUTH_AUTHTYPE_H #define _SQUID__SRC_AUTH_AUTHTYPE_H #if USE_AUTH namespace Auth { typedef enum { AUTH_UNKNOWN, /* default */ AUTH_BASIC, + AUTH_BEARER, AUTH_NTLM, AUTH_DIGEST, AUTH_NEGOTIATE, AUTH_BROKEN /* known type, but broken data */ } Type; extern const char *Type_str[]; }; // namespace Auth #endif /* USE_AUTH */ #endif === added directory 'src/auth/bearer' === added file 'src/auth/bearer/Config.cc' --- src/auth/bearer/Config.cc 1970-01-01 00:00:00 +0000 +++ src/auth/bearer/Config.cc 2014-07-31 00:21:43 +0000 @@ -0,0 +1,253 @@ +/* + * DEBUG: section 29 Bearer Authentication + */ +#include "squid.h" +#include "auth/bearer/Config.h" +#include "auth/bearer/Scheme.h" +#include "auth/bearer/Token.h" +#include "auth/bearer/User.h" +#include "auth/bearer/UserRequest.h" +#include "base/CharacterSet.h" +#include "cache_cf.h" +#include "HttpHeaderTools.h" +#include "HttpReply.h" +#include "mgr/Registration.h" +#include "Store.h" +#include "wordlist.h" + +// Bearer Scheme statistics +static AUTHSSTATS authenticateBearerStats; + +helper *bearerauthenticators = NULL; + +static int authbearer_initialised = 0; + +bool +Auth::Bearer::Config::active() const +{ + return authbearer_initialised == 1; +} + +bool +Auth::Bearer::Config::configured() const +{ + if ((authenticateProgram != NULL) && (authenticateChildren.n_max != 0) && + !realm.isEmpty() && (bearerAuthScope != NULL)) { + debugs(29, 9, "returning configured"); + return true; + } + + debugs(29, 9, "returning unconfigured"); + return false; +} + +const char * +Auth::Bearer::Config::type() const +{ + return Auth::Bearer::Scheme::GetInstance()->type(); +} + +void +Auth::Bearer::Config::fixHeader(Auth::UserRequest::Pointer, HttpReply *rep, http_hdr_type hdrType, HttpRequest *) +{ + if (authenticateProgram) { + debugs(29, 9, "Sending type:" << hdrType << " header: 'Bearer realm=\"" << realm << "\", scope=\"" << bearerAuthScope << "\"'"); + httpHeaderPutStrf(&rep->header, hdrType, "Bearer realm=\"" SQUIDSBUFPH "\", scope=\"%s\"", SQUIDSBUFPRINT(realm), bearerAuthScope); + } +} + +void +Auth::Bearer::Config::rotateHelpers() +{ + /* schedule closure of existing helpers */ + if (bearerauthenticators) { + helperShutdown(bearerauthenticators); + } + + /* NP: dynamic helper restart will ensure they start up again as needed. */ +} + +/** shutdown the auth helpers and free any allocated configuration details */ +void +Auth::Bearer::Config::done() +{ + Auth::Config::done(); + + authbearer_initialised = 0; + + if (bearerauthenticators) { + helperShutdown(bearerauthenticators); + } + + delete bearerauthenticators; + bearerauthenticators = NULL; + + if (authenticateProgram) + wordlistDestroy(&authenticateProgram); + + safe_free(bearerAuthScope); +} + +void +Auth::Bearer::Config::dump(StoreEntry * entry, const char *name, Auth::Config * scheme) +{ + if (!Auth::Config::dump(entry, name, scheme)) + return false; // not configured + + storeAppendPrintf(entry, "%s bearer scope %s\n", name, bearerAuthScope); + storeAppendPrintf(entry, "%s bearer cleanup_interval %" PRId64 " seconds\n", name, static_cast(tokenGCInterval)); +} + +Auth::Bearer::Config::Config() +{ + static const SBuf defaultRealm("Squid proxy-caching web server"); + realm = defaultRealm; + bearerAuthScope = xstrdup("proxy:HTTP"); +} + +Auth::Bearer::Config::~Config() +{ + safe_free(bearerAuthScope); +} + +void +Auth::Bearer::Config::parse(Auth::Config * scheme, int n_configured, char *param_str) +{ + if (strcmp(param_str, "scope") == 0) { + parse_eol(&bearerAuthScope); + } else if (strcmp(param_str, "cleanup_interval") == 0) { + parse_time_t(&tokenGCInterval); + } else + Auth::Config::parse(scheme, n_configured, param_str); +} + +static void +authenticateBearerStats(StoreEntry * sentry) +{ + helperStats(sentry, bearerauthenticators, "Bearer Authenticator Statistics"); +} + +/** + * Decode a Bearer [Proxy-]Auth string. Looking for an existing + * Auth::UserRequest structure with matching token, or create a + * new one if needed. + * + * Note that just returning will be treated as + * "cannot decode credentials". Use the message field to return + * a descriptive message to the user. + */ +Auth::UserRequest::Pointer +Auth::Bearer::Config::decode(char const *proxy_auth, const char *aRequestRealm) +{ + Auth::UserRequest::Pointer auth_user_request = dynamic_cast(new Auth::Bearer::UserRequest); + + // retrieve the b68token + SBuf blob(proxy_auth); + if (!blob.isEmpty()) { + // trim prefix: WSP "Bearer" WSP + SBuf::size_type p = blob.findFirstNotOf(CharacterSet::WSP); + blob.consume(p); + p = blob.findFirstOf(CharacterSet::WSP); + blob.consume(p); + p = blob.findFirstNotOf(CharacterSet::WSP); + blob.consume(p); + } + + // empty header? no auth details produced... + if (blob.isEmpty()) + return auth_user_request; + + // XXX: if the token contains non-b68token characters it is invalid. + + Auth::User::Pointer auth_user; + + // if there is a cached entry for this token use it + TokenCache::iterator itr = Auth::Bearer::Token::Cache.find(SBuf(blob)); + if (!itr->second) { + // generate a User object for this token and cache it + Auth::Bearer::User *usr = new Auth::Bearer::User(this, aRequestRealm); + usr->token = new Token(blob); + usr->token->user = usr; + usr->auth_type = Auth::AUTH_BEARER; + + Auth::Bearer::Token::Cache.insert(std::pair(SBuf(blob), usr->token)); + auth_user = usr; + + } else + auth_user = itr->second->user; + + debugs(29, 3, "Found Bearer token " << blob <<" , user=" << auth_user->username() << ", " << auth_user); + + assert(auth_user != NULL); + auth_user_request->user(auth_user); + return auth_user_request; +} + +/** + * Initialize helpers and the like for this auth scheme. + * Called AFTER parsing the config file + */ +void +Auth::Bearer::Config::init(Auth::Config * schemeCfg) +{ + if (authenticateProgram && !authbearer_initialised) { + authbearer_initialised = 1; + + if (bearerauthenticators == NULL) + bearerauthenticators = new helper("bearerauthenticator"); + + bearerauthenticators->cmdline = authenticateProgram; + + bearerauthenticators->childs.updateLimits(authenticateChildren); + + bearerauthenticators->ipc_type = IPC_STREAM; + + helperOpenServers(bearerauthenticators); + + TokenCacheCleanup(NULL); // kick-start garbage collection events + } +} + +void +Auth::Bearer::Config::registerWithCacheManager(void) +{ + Mgr::RegisterAction("bearerauthenticator", + "Bearer User Authenticator Stats", + authenticateBearerStats, 0, 1); +} + +void +Auth::Bearer::Config::TokenCacheCleanup(void *) +{ + debugs(29, 3, "Cleaning the token cache at time=" << current_time.tv_sec); + + // only clear tokens out of cache after 1 hour stale + // could make this configurable + time_t stalenessLimit = current_time.tv_sec - 60*60; + + /* + * For big caches we could consider stepping through + * 100/200 entries at a time. Lets see how it flies + * first. + */ + Auth::Bearer::TokenCache *cache = &Auth::Bearer::Token::Cache; + for (Auth::Bearer::TokenCache::iterator itr = cache->begin(); itr != cache->end();) { + debugs(29, 3, "token " << itr->second->b68encoded + << ", user=" << itr->second->user->username() + << ", expires=" << itr->second->expires); + + // remove if it is too old + if (itr->second->expires < stalenessLimit) { + debugs(29, 3, "token " << itr->second->b68encoded << " removed"); + Auth::Bearer::TokenCache::iterator remove = itr++; + cache->erase(remove); + } else + ++itr; + } + + debugs(29, 3, "Finished cleaning the token cache."); + + const Auth::Bearer::Config *cfg = static_cast(Auth::Config::Find("bearer")); + if (cfg && cfg->active()) + eventAdd("Bearer token cache maintenance", Auth::Bearer::Config::TokenCacheCleanup, NULL, cfg->tokenGCInterval, 1); +} === added file 'src/auth/bearer/Config.h' --- src/auth/bearer/Config.h 1970-01-01 00:00:00 +0000 +++ src/auth/bearer/Config.h 2014-07-31 00:17:41 +0000 @@ -0,0 +1,48 @@ +#ifndef _SQUID_SRC_AUTH_BEARER_CONFIG_H +#define _SQUID_SRC_AUTH_BEARER_CONFIG_H + +#include "auth/bearer/forward.h" +#include "auth/Config.h" +#include "auth/Gadgets.h" +#include "auth/UserRequest.h" +#include "helper.h" + +namespace Auth +{ +namespace Bearer +{ + +/// Bearer authentication configuration data +class Config : public Auth::Config +{ +public: + Config(); + ~Config(); + virtual bool active() const; + virtual bool configured() const; + 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 *); + virtual void fixHeader(Auth::UserRequest::Pointer, HttpReply *, http_hdr_type, HttpRequest *); + virtual void init(Auth::Config *); + virtual void parse(Auth::Config *, int, char *); + void decode(char const *httpAuthHeader, Auth::UserRequest::Pointer); + virtual void registerWithCacheManager(void); + virtual const char * type() const; + +public: + char *bearerAuthScope; + time_t tokenGCInterval; + +private: + void tokenCacheSetup(); + static void TokenCacheCleanup(void *); +}; + +} // namespace Bearer +} // namespace Auth + +extern helper *bearerauthenticators; + +#endif /* _SQUID_SRC_AUTH_BEARER_CONFIG_H */ === added file 'src/auth/bearer/Makefile.am' --- src/auth/bearer/Makefile.am 1970-01-01 00:00:00 +0000 +++ src/auth/bearer/Makefile.am 2014-07-30 12:25:52 +0000 @@ -0,0 +1,17 @@ +include $(top_srcdir)/src/Common.am +include $(top_srcdir)/src/TestHeaders.am + +noinst_LTLIBRARIES = libbearer.la + +libbearer_la_SOURCES = \ + Config.cc \ + Config.h \ + forward.h \ + Scheme.cc \ + Scheme.h \ + Token.cc \ + Token.h \ + User.cc \ + User.h \ + UserRequest.cc \ + UserRequest.h === added file 'src/auth/bearer/Scheme.cc' --- src/auth/bearer/Scheme.cc 1970-01-01 00:00:00 +0000 +++ src/auth/bearer/Scheme.cc 2014-05-22 09:21:34 +0000 @@ -0,0 +1,40 @@ +#include "squid.h" +#include "auth/bearer/Config.h" +#include "auth/bearer/Scheme.h" +#include "Debug.h" +#include "helper.h" + +Auth::Scheme::Pointer Auth::Bearer::Scheme::_instance = NULL; + +Auth::Scheme::Pointer +Auth::Bearer::Scheme::GetInstance() +{ + if (_instance == NULL) { + _instance = new Auth::Bearer::Scheme(); + AddScheme(_instance); + } + return _instance; +} + +char const * +Auth::Bearer::Scheme::type() const +{ + return "bearer"; +} + +void +Auth::Bearer::Scheme::shutdownCleanup() +{ + if (_instance == NULL) + return; + + _instance = NULL; + debugs(29, DBG_CRITICAL, "Shutdown: " << type() << " authentication."); +} + +Auth::Config * +Auth::Bearer::Scheme::createConfig() +{ + Auth::Bearer::Config *newCfg = new Auth::Bearer::Config; + return dynamic_cast(newCfg); +} === added file 'src/auth/bearer/Scheme.h' --- src/auth/bearer/Scheme.h 1970-01-01 00:00:00 +0000 +++ src/auth/bearer/Scheme.h 2014-05-27 01:41:29 +0000 @@ -0,0 +1,36 @@ +#ifndef SQUID_AUTH_BEARER_SCHEME_H +#define SQUID_AUTH_BEARER_SCHEME_H + +#include "auth/Scheme.h" + +namespace Auth +{ +namespace Bearer +{ + +/// scheme instance for OAuth 2.0 Bearer +class Scheme : public Auth::Scheme +{ + +public: + static Auth::Scheme::Pointer GetInstance(); + Scheme() {}; + virtual ~Scheme() {} + + /* per scheme */ + virtual char const *type() const; + virtual void shutdownCleanup(); + virtual Auth::Config *createConfig(); + +private: + /* Not implemented */ + Scheme(Scheme const &); + Scheme &operator=(Scheme const &); + + static Auth::Scheme::Pointer _instance; +}; + +} // namespace Bearer +} // namespace Auth + +#endif /* SQUID_AUTH_BEARER_SCHEME_H */ === added file 'src/auth/bearer/Token.cc' --- src/auth/bearer/Token.cc 1970-01-01 00:00:00 +0000 +++ src/auth/bearer/Token.cc 2014-05-27 05:56:21 +0000 @@ -0,0 +1,9 @@ +#include "squid.h" +#include "auth/bearer/Token.h" + +Auth::Bearer::TokenCache Auth::Bearer::Token::Cache; + +Auth::Bearer::Token::~Token() +{ + // TODO detatch this token from the Auth:User ?? +} === added file 'src/auth/bearer/Token.h' --- src/auth/bearer/Token.h 1970-01-01 00:00:00 +0000 +++ src/auth/bearer/Token.h 2014-05-28 11:06:21 +0000 @@ -0,0 +1,43 @@ +#ifndef _SQUID_SRC_AUTH_BEARER_TOKEN_H +#define _SQUID_SRC_AUTH_BEARER_TOKEN_H + +#include "auth/bearer/forward.h" +#include "base/RefCount.h" +#include "SquidTime.h" + +namespace Auth { +namespace Bearer { + +/// a Bearer token we have seen and details we associate with it +class Token : public RefCountable +{ +public: + MEMPROXY_CLASS(Auth::Bearer::Token); + + Token() : user(NULL), expires(squid_curtime) {} + explicit Token(const SBuf &token) : b68encoded(token), user(NULL), expires(squid_curtime) {} + ~Token(); + + /// the B68 encoding form of this token + SBuf b68encoded; + + /// the Auth::User this token is tied to + Auth::Bearer::User *user; + + /// when this token will expire + time_t expires; + + /// a cache of known tokens + static TokenCache Cache; + +private: + Token(const Token &); // do not implement + Token &operator =(const Token&); // do not implement +}; + +MEMPROXY_CLASS_INLINE(Auth::Bearer::Token); + +} // namespace Bearer +} // namespace Auth + +#endif /* _SQUID_SRC_AUTH_BEARER_TOKEN_H */ === added file 'src/auth/bearer/User.cc' --- src/auth/bearer/User.cc 1970-01-01 00:00:00 +0000 +++ src/auth/bearer/User.cc 2014-05-28 11:49:31 +0000 @@ -0,0 +1,28 @@ +#include "squid.h" +#include "auth/bearer/User.h" +#include "auth/bearer/UserRequest.h" +#include "auth/Config.h" +#include "auth/QueueNode.h" +#include "Debug.h" + +Auth::Bearer::User::User(Auth::Config *aConfig, const char *aRequestRealm) : + Auth::User(aConfig, aRequestRealm), + queue(NULL) +{ +} + +Auth::Bearer::User::~User() +{ + debugs(29, 5, "doing nothing to clear Bearer scheme data for " << this); +} + +int32_t +Auth::Bearer::User::ttl() const +{ + // no token? should never happen, but treat as expired + if (token == NULL) + return -1; + + // credentials expiry depends on the Token age. + return static_cast(token->expires - squid_curtime); +} === added file 'src/auth/bearer/User.h' --- src/auth/bearer/User.h 1970-01-01 00:00:00 +0000 +++ src/auth/bearer/User.h 2014-05-27 01:45:19 +0000 @@ -0,0 +1,38 @@ +#ifndef _SQUID_AUTH_BEARER_USER_H +#define _SQUID_AUTH_BEARER_USER_H + +#include "auth/bearer/Token.h" +#include "auth/User.h" + +namespace Auth +{ + +class QueueNode; + +namespace Bearer +{ + +/// User credentials for the Bearer authentication protocol +class User : public Auth::User +{ +public: + MEMPROXY_CLASS(Auth::Bearer::User); + + User(Auth::Config *, const char *requestRealm); + ~User(); + + virtual int32_t ttl() const; + + /// authentication attempts waiting on helper feedback + QueueNode *queue; + + /// the token used to create this User object + TokenPointer token; +}; + +MEMPROXY_CLASS_INLINE(Auth::Bearer::User); + +} // namespace Bearer +} // namespace Auth + +#endif /* _SQUID_AUTH_BEARER_USER_H */ === added file 'src/auth/bearer/UserRequest.cc' --- src/auth/bearer/UserRequest.cc 1970-01-01 00:00:00 +0000 +++ src/auth/bearer/UserRequest.cc 2014-05-28 11:48:22 +0000 @@ -0,0 +1,251 @@ +#include "squid.h" +#include "auth/bearer/Config.h" +#include "auth/bearer/User.h" +#include "auth/bearer/UserRequest.h" +#include "auth/QueueNode.h" +#include "auth/State.h" +#include "cbdata.h" +#include "Debug.h" + +Auth::Bearer::UserRequest::UserRequest() +{ +} + +Auth::Bearer::UserRequest::~UserRequest() +{ +} + +int +Auth::Bearer::UserRequest::authenticated() const +{ + if (user() != NULL && user()->credentials() == Auth::Ok) { + debugs(29, 9, "user authenticated"); + return 1; + } + + debugs(29, 9, "user not fully authenticated"); + return 0; +} + +const char * +Auth::Bearer::UserRequest::credentialsStr() +{ + static char buf[MAX_AUTHTOKEN_LEN]; + buf[0] = '\0'; + + Auth::Bearer::User const *usr = dynamic_cast(user().getRaw()); + if (usr) + snprintf(buf, sizeof(buf), SQUIDSBUFPH "\n", SQUIDSBUFPRINT(usr->token->b68encoded)); + return buf; +} + +Auth::Direction +Auth::Bearer::UserRequest::module_direction() +{ + // null auth_user is checked for by Auth::UserRequest::direction() + + if (user()->auth_type != Auth::AUTH_BEARER) + return Auth::CRED_ERROR; + + switch (user()->credentials()) { + + case Auth::Unchecked: + case Auth::Pending: + return Auth::CRED_LOOKUP; + + case Auth::Ok: + if (user()->ttl() <= 0) + return Auth::CRED_LOOKUP; + return Auth::CRED_VALID; + + case Auth::Failed: + return Auth::CRED_VALID; + + default: + debugs(29, DBG_IMPORTANT, "WARNING: Bearer Authentication in unexpected state: " << user()->credentials()); + return Auth::CRED_ERROR; + } +} + +void +Auth::Bearer::UserRequest::startHelperLookup(HttpRequest *req, AccessLogEntry::Pointer &al, AUTHCB * handler, void *data) +{ + assert(data); + assert(handler); + + assert(user() != NULL); + assert(user()->auth_type == Auth::AUTH_BEARER); + + if (static_cast(Auth::Config::Find("bearer"))->authenticateProgram == NULL) { + debugs(29, DBG_CRITICAL, "ERROR: No Bearer authentication program configured."); + handler(data); + return; + } + + Auth::Bearer::User *bearer_auth = dynamic_cast(user().getRaw()); + assert(bearer_auth != NULL); + + // check to see if the user already has a request outstanding + if (user()->credentials() == Auth::Pending) { + + debugs(29, 8, "token " << bearer_auth->token->b68encoded << " queue after lookup already underway"); + // there is a request with the same credentials already being verified + Auth::QueueNode *node = new Auth::QueueNode(this, handler, data); + + // queue this validation request to be informed of the pending lookup results + node->next = bearer_auth->queue; + bearer_auth->queue = node; + return; + } + // otherwise submit this request to the auth helper(s) for validation + + debugs(29, 8, "credentials state is " << user()->credentials()); + + static char buf[MAX_AUTHTOKEN_LEN]; + int sz; + if (const char *keyExtras = helperRequestKeyExtras(req, al)) + sz = snprintf(buf, sizeof(buf), SQUIDSBUFPH " %s\n", SQUIDSBUFPRINT(bearer_auth->token->b68encoded), keyExtras); + else + sz = snprintf(buf, sizeof(buf), SQUIDSBUFPH "\n", SQUIDSBUFPRINT(bearer_auth->token->b68encoded)); + + if (sz<=0) { + debugs(9, DBG_CRITICAL, "ERROR: Bearer Authentication Failure. Can not build helper validation request."); + handler(data); + } else if (static_cast(sz) >= sizeof(buf)) { + debugs(9, DBG_CRITICAL, "ERROR: Bearer Authentication Failure. Helper request line exceeds " << sizeof(buf) << " bytes."); + handler(data); + } else { + user()->credentials(Auth::Pending); + debugs(29, 3, "token " << bearer_auth->token->b68encoded << " lookup started"); + helperSubmit(bearerauthenticators, buf, Auth::Bearer::UserRequest::HandleReply, + new Auth::StateData(this, handler, data)); + } +} + +void +Auth::Bearer::UserRequest::authenticate(HttpRequest * aRequest, ConnStateData * conn, http_hdr_type type) +{ + assert(user() != NULL); + + // if the password is not ok, do an identity + if (!user() || user()->credentials() != Auth::Ok) + return; + + // are we about to recheck the credentials externally? + if (user()->ttl() <= 0) { + debugs(29, 4, "credentials expired - rechecking"); + user()->credentials(Auth::Unchecked); + return; + } + + // we have been through the external helper, and the credentials haven't expired + debugs(29, 9, "user " << user()->username() << " authenticated"); +} + +void +Auth::Bearer::UserRequest::HandleReply(void *data, const HelperReply &reply) +{ + Auth::StateData *r = static_cast(data); + + debugs(29, 8, "helper: " << reply.whichServer << " sent us reply=" << reply); + + if (!cbdataReferenceValid(r->data)) { + debugs(29, DBG_IMPORTANT, "ERROR: Bearer Authentication invalid callback data."); + delete r; + return; + } + + Auth::UserRequest::Pointer auth_user_request = r->auth_user_request; + assert(auth_user_request != NULL); + + // add new helper kv-pair notes to the credentials object + // so that any transaction using those credentials can access them + auth_user_request->user()->notes.appendNewOnly(&reply.notes); + + assert(auth_user_request->user() != NULL); + assert(auth_user_request->user()->auth_type == Auth::AUTH_BEARER); + + switch (reply.result) { + case HelperReply::Okay: { + const char *userNote = reply.notes.findFirst("user"); + const char *ttlNote = reply.notes.findFirst("ttl"); + if (userNote == NULL) { + /* protocol error */ + fatalf("Auth::Bearer::HandleReply: *** Unsupported helper response ***, '%s'\n", reply.other().content()); + break; + } + + Auth::Bearer::User *usr = dynamic_cast(auth_user_request->user().getRaw()); + /* we're finished, user is authenticated */ + usr->username(userNote); + auth_user_request->denyMessage("Login successful"); + const int64_t ttl = (ttlNote!= NULL) ? strtoll(ttlNote, NULL, 10) : -1; + usr->token->expires = current_time.tv_sec + ttl; + usr->expiretime = max(usr->expiretime, usr->token->expires); + usr->credentials(Auth::Ok); + usr->addToNameCache(); + debugs(29, 4, "Successfully validated user via Bearer. Username " << auth_user_request->user()->username()); + } + break; + + case HelperReply::Error: { + const char *messageNote = reply.notes.find("message"); + const char *ttlNote = reply.notes.findFirst("ttl"); + + /* authentication failure (wrong password, etc.) */ + if (messageNote != NULL) + auth_user_request->denyMessage(messageNote); + else + auth_user_request->denyMessage("Bearer Authentication denied with no reason given"); + + Auth::Bearer::User *usr = dynamic_cast(auth_user_request->user().getRaw()); + + const int64_t ttl = (ttlNote!= NULL) ? strtoll(ttlNote, NULL, 10) : -1; + usr->token->expires = current_time.tv_sec + ttl; + usr->expiretime = max(usr->expiretime, usr->token->expires); + usr->credentials(Auth::Failed); + debugs(29, 4, "Failed validating user via Bearer. Result: " << reply); + } + break; + + case HelperReply::Unknown: + debugs(29, DBG_IMPORTANT, "ERROR: Bearer Authentication Helper '" << reply.whichServer << "' crashed!."); + /* continue to the next case */ + + case HelperReply::TT: + /* continue to the next case */ + + case HelperReply::BrokenHelper: { + const char *errNote = reply.notes.find("message"); + if (reply.result == HelperReply::Unknown) + auth_user_request->denyMessage("Internal Error"); + else if (errNote != NULL) + auth_user_request->denyMessage(errNote); + else + auth_user_request->denyMessage("Bearer Authentication failed with no reason given"); + auth_user_request->user()->credentials(Auth::Failed); + debugs(29, DBG_IMPORTANT, "ERROR: Bearer Authentication validating user. Result: " << reply); + } // break; + } + + // Notify all waiting transactions of the result + void *cbdata; + if (cbdataReferenceValidDone(r->data, &cbdata)) + r->handler(cbdata); + + cbdataReferenceDone(r->data); + + Auth::Bearer::User *local_usr = dynamic_cast(auth_user_request->user().getRaw()); + while (local_usr->queue) { + if (cbdataReferenceValidDone(local_usr->queue->data, &cbdata)) + local_usr->queue->handler(cbdata); + + Auth::QueueNode *tmpnode = local_usr->queue->next; + local_usr->queue->next = NULL; + delete local_usr->queue; + + local_usr->queue = tmpnode; + } + + delete r; +} === added file 'src/auth/bearer/UserRequest.h' --- src/auth/bearer/UserRequest.h 1970-01-01 00:00:00 +0000 +++ src/auth/bearer/UserRequest.h 2014-05-28 11:48:12 +0000 @@ -0,0 +1,38 @@ +#ifndef _SQUID_SRC_AUTH_BEARER_USERREQUEST_H +#define _SQUID_SRC_AUTH_BEARER_USERREQUEST_H + +#include "auth/UserRequest.h" +#include "MemPool.h" + +class ConnStateData; +class HttpReply; +class HttpRequest; + +namespace Auth +{ +namespace Bearer +{ + +class UserRequest : public Auth::UserRequest +{ +public: + MEMPROXY_CLASS(Auth::Bearer::UserRequest); + + UserRequest(); + virtual ~UserRequest(); + virtual int authenticated() const; + virtual void authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type); + virtual Direction module_direction(); + virtual void startHelperLookup(HttpRequest *request, AccessLogEntry::Pointer &al, AUTHCB *, void *); + virtual const char *credentialsStr(); + +private: + static HLPCB HandleReply; +}; + +} // namespace Bearer +} // namespace Auth + +MEMPROXY_CLASS_INLINE(Auth::Bearer::UserRequest); + +#endif /* _SQUID_SRC_AUTH_BEARER_USERREQUEST_H */ === added file 'src/auth/bearer/forward.h' --- src/auth/bearer/forward.h 1970-01-01 00:00:00 +0000 +++ src/auth/bearer/forward.h 2014-05-28 08:11:03 +0000 @@ -0,0 +1,29 @@ +#ifndef _SQUID_SRC_AUTH_BEARER_FORWARD_H +#define _SQUID_SRC_AUTH_BEARER_FORWARD_H + +#include "base/RefCount.h" +#include "SBuf.h" + +#include + +namespace Auth { + +/** OAuth 2.0 Bearer token Authentication in HTTP + * + * RFC 6750 OAuth 2.0 Authorization Framework: Bearer Token Usage + * http://tools.ietf.org/rfc/rfc6750 + */ +namespace Bearer { + +class Token; +class User; +class UserRequest; + +typedef RefCount TokenPointer; + +typedef std::map TokenCache; + +} // namespace Bearer +} // namespace Auth + +#endif /* _SQUID_SRC_AUTH_BEARER_FORWARD_H */ === modified file 'src/cf.data.pre' --- src/cf.data.pre 2014-07-30 15:31:10 +0000 +++ src/cf.data.pre 2014-07-31 06:12:39 +0000 @@ -352,41 +352,41 @@ The expanded key_extras value is added to the Squid credentials cache and, hence, will affect authentication. It can be used to autenticate different users with identical user names (e.g., when user authentication depends on http_port). Avoid adding frequently changing information to key_extras. For example, if you add user source IP, and it changes frequently in your environment, then max_user_ip ACL is going to treat every user+IP combination as a unique "user", breaking the ACL and wasting a lot of memory on those user records. It will also force users to authenticate from scratch whenever their IP changes. "realm" string Specifies the protection scope (aka realm name) which is to be reported to the client for the authentication scheme. It is commonly part of the text the user will see when prompted for their username and password. - For Basic the default is "Squid proxy-caching web server". + For Basic and Bearer the default is "Squid proxy-caching web server". For Digest there is no default, this parameter is mandatory. For NTLM and Negotiate this parameter is ignored. "children" numberofchildren [startup=N] [idle=N] [concurrency=N] The maximum number of authenticator processes to spawn. If you start too few Squid will have to wait for them to process a backlog of credential verifications, slowing it down. When password verifications are done via a (slow) network you are likely to need lots of authenticator processes. The startup= and idle= options permit some skew in the exact amount run. A minimum of startup=N will begin during startup and reconfigure. Squid will start more in groups of up to idle=N in an attempt to meet traffic needs and to keep idle=N free above those traffic needs up to the maximum. The concurrency= option sets the number of concurrent requests the helper can process. The default of 0 is used for helpers who only supports one request at a time. Setting this to a @@ -414,40 +414,55 @@ "credentialsttl" timetolive Specifies how long squid assumes an externally validated username:password pair is valid for - in other words how often the helper program is called for that user. Set this low to force revalidation with short lived passwords. NOTE: setting this high does not impact your susceptibility to replay attacks unless you are using an one-time password system (such as SecureID). If you are using such a system, you will be vulnerable to replay attacks unless you also use the max_user_ip ACL in an http_access rule. "casesensitive" on|off Specifies if usernames are case sensitive. Most user databases are case insensitive allowing the same username to be spelled using both lower and upper case letters, but some are case sensitive. This makes a big difference for user_max_ip ACL processing and similar. ENDIF +IF HAVE_AUTH_MODULE_BEARER + === Bearer authentication parameters === + + "scope" scopestring + Specifies the scope name(s) which are to be reported to the + client for the Bearer proxy authentication scheme. + The default is: proxy:HTTP + + "cleanup_interval" timeinterval + Specifies the interval for garbage collection events which + remove excessively stale Bearer tokens. Tokens are deemed + excessively stale if they have not been seen for an hour or + more since their expiry time. + +ENDIF IF HAVE_AUTH_MODULE_DIGEST === Digest authentication parameters === "utf8" on|off HTTP uses iso-latin-1 as character set, while some authentication backends such as LDAP expects UTF-8. If this is set to on Squid will translate the HTTP iso-latin-1 charset to UTF-8 before sending the username and password to the helper. "nonce_garbage_interval" timeinterval Specifies the interval that nonces that have been issued to client_agent's are checked for validity. "nonce_max_duration" timeinterval Specifies the maximum length of time a given nonce will be valid for. "nonce_max_count" number Specifies the maximum number of times a given nonce can be used. @@ -492,40 +507,43 @@ are supported by the proxy. ENDIF === Example Configuration === This configuration displays the recommended authentication scheme order from most to least secure with recommended minimum configuration settings for each scheme: #auth_param negotiate program #auth_param negotiate children 20 startup=0 idle=1 #auth_param negotiate keep_alive on # #auth_param digest program #auth_param digest children 20 startup=0 idle=1 #auth_param digest realm Squid proxy-caching web server #auth_param digest nonce_garbage_interval 5 minutes #auth_param digest nonce_max_duration 30 minutes #auth_param digest nonce_max_count 50 # +#auth_param bearer program +#auth_param bearer scope proxy:squid +# #auth_param ntlm program #auth_param ntlm children 20 startup=0 idle=1 #auth_param ntlm keep_alive on # #auth_param basic program #auth_param basic children 5 startup=5 idle=1 #auth_param basic realm Squid proxy-caching web server #auth_param basic credentialsttl 2 hours DOC_END NAME: authenticate_cache_garbage_interval TYPE: time_t DEFAULT: 1 hour LOC: Config.authenticateGCInterval DOC_START The time period between garbage collection across the username cache. This is a trade-off between memory utilization (long intervals - say 2 days) and CPU (short intervals - say 1 minute). Only change if you have good reason to. DOC_END