]>
Commit | Line | Data |
---|---|---|
f5691f9c | 1 | /* |
1f7b830e | 2 | * Copyright (C) 1996-2025 The Squid Software Foundation and contributors |
f5691f9c | 3 | * |
bbc27441 AJ |
4 | * Squid software is distributed under GPLv2+ license and includes |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
f5691f9c | 7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 29 Authenticator */ |
10 | ||
f5691f9c | 11 | /* The functions in this file handle authentication. |
12 | * They DO NOT perform access control or auditing. | |
13 | * See acl.c for access control and client_side.c for auditing */ | |
14 | ||
582c2af2 | 15 | #include "squid.h" |
5bfc3dbd | 16 | #include "acl/FilledChecklist.h" |
5c112575 | 17 | #include "auth/Config.h" |
582c2af2 | 18 | #include "client_side.h" |
5c336a3b | 19 | #include "comm/Connection.h" |
ed6e9fb9 | 20 | #include "fatal.h" |
86c63190 | 21 | #include "format/Format.h" |
6f9a30f8 EB |
22 | #include "helper.h" |
23 | #include "helper/Reply.h" | |
d3dddfb5 | 24 | #include "http/Stream.h" |
f5691f9c | 25 | #include "HttpReply.h" |
26 | #include "HttpRequest.h" | |
d4806c91 | 27 | #include "MemBuf.h" |
f5691f9c | 28 | |
29 | /* Generic Functions */ | |
30 | ||
f5691f9c | 31 | char const * |
c7baff40 | 32 | Auth::UserRequest::username() const |
f5691f9c | 33 | { |
aee3523a | 34 | if (user() != nullptr) |
f5691f9c | 35 | return user()->username(); |
36 | else | |
aee3523a | 37 | return nullptr; |
f5691f9c | 38 | } |
39 | ||
f5691f9c | 40 | /**** PUBLIC FUNCTIONS (ALL GENERIC!) ****/ |
41 | ||
42 | /* send the initial data to an authenticator module */ | |
43 | void | |
d4806c91 | 44 | Auth::UserRequest::start(HttpRequest *request, AccessLogEntry::Pointer &al, AUTHCB * handler, void *data) |
f5691f9c | 45 | { |
46 | assert(handler); | |
a088a999 | 47 | assert(data); |
30c3f584 AJ |
48 | debugs(29, 9, this); |
49 | startHelperLookup(request, al, handler, data); | |
f5691f9c | 50 | } |
51 | ||
2e39494f | 52 | bool |
c7baff40 | 53 | Auth::UserRequest::valid() const |
f5691f9c | 54 | { |
bf95c10a | 55 | debugs(29, 9, "Validating Auth::UserRequest '" << this << "'."); |
f5691f9c | 56 | |
aee3523a | 57 | if (user() == nullptr) { |
bf95c10a | 58 | debugs(29, 4, "No associated Auth::User data"); |
0a608df9 | 59 | return false; |
f5691f9c | 60 | } |
61 | ||
616cfc4c | 62 | if (user()->auth_type == Auth::AUTH_UNKNOWN) { |
bf95c10a | 63 | debugs(29, 4, "Auth::User '" << user() << "' uses unknown scheme."); |
2e39494f | 64 | return false; |
f5691f9c | 65 | } |
66 | ||
616cfc4c | 67 | if (user()->auth_type == Auth::AUTH_BROKEN) { |
bf95c10a | 68 | debugs(29, 4, "Auth::User '" << user() << "' is broken for it's scheme."); |
2e39494f | 69 | return false; |
f5691f9c | 70 | } |
71 | ||
72 | /* any other sanity checks that we need in the future */ | |
73 | ||
f5691f9c | 74 | /* finally return ok */ |
bf95c10a | 75 | debugs(29, 5, "Validated. Auth::UserRequest '" << this << "'."); |
2e39494f | 76 | return true; |
f5691f9c | 77 | } |
78 | ||
79 | void * | |
ced8def3 | 80 | Auth::UserRequest::operator new (size_t) |
f5691f9c | 81 | { |
c7baff40 | 82 | fatal("Auth::UserRequest not directly allocatable\n"); |
f5691f9c | 83 | return (void *)1; |
84 | } | |
85 | ||
86 | void | |
ced8def3 | 87 | Auth::UserRequest::operator delete (void *) |
f5691f9c | 88 | { |
c7baff40 | 89 | fatal("Auth::UserRequest child failed to override operator delete\n"); |
f5691f9c | 90 | } |
91 | ||
c7baff40 | 92 | Auth::UserRequest::UserRequest(): |
aee3523a AR |
93 | _auth_user(nullptr), |
94 | message(nullptr), | |
f53969cc | 95 | lastReply(AUTH_ACL_CANNOT_AUTHENTICATE) |
f5691f9c | 96 | { |
bf95c10a | 97 | debugs(29, 5, "initialised request " << this); |
f5691f9c | 98 | } |
99 | ||
c7baff40 | 100 | Auth::UserRequest::~UserRequest() |
f5691f9c | 101 | { |
8bf217bd | 102 | assert(LockCount()==0); |
bf95c10a | 103 | debugs(29, 5, "freeing request " << this); |
f5691f9c | 104 | |
aee3523a | 105 | if (user() != nullptr) { |
56a49fda | 106 | /* release our references to the user credentials */ |
aee3523a | 107 | user(nullptr); |
f5691f9c | 108 | } |
109 | ||
56a49fda | 110 | safe_free(message); |
f5691f9c | 111 | } |
112 | ||
113 | void | |
c7baff40 | 114 | Auth::UserRequest::setDenyMessage(char const *aString) |
f5691f9c | 115 | { |
56a49fda AJ |
116 | safe_free(message); |
117 | message = xstrdup(aString); | |
f5691f9c | 118 | } |
119 | ||
120 | char const * | |
6f9a30f8 | 121 | Auth::UserRequest::getDenyMessage() const |
f5691f9c | 122 | { |
123 | return message; | |
124 | } | |
125 | ||
126 | char const * | |
6f9a30f8 | 127 | Auth::UserRequest::denyMessage(char const * const default_message) const |
f5691f9c | 128 | { |
aee3523a | 129 | if (getDenyMessage() == nullptr) |
f5691f9c | 130 | return default_message; |
f5691f9c | 131 | |
132 | return getDenyMessage(); | |
133 | } | |
134 | ||
e4bcf117 FC |
135 | bool |
136 | Auth::UserRequest::authenticated() const | |
137 | { | |
138 | const auto u = user(); | |
139 | if (u && u->credentials() == Auth::Ok) { | |
140 | debugs(29, 7, "yes"); | |
141 | return true; | |
142 | } | |
143 | ||
144 | debugs(29, 7, "no"); | |
145 | return false; | |
146 | } | |
147 | ||
f5691f9c | 148 | static void |
c7baff40 | 149 | authenticateAuthUserRequestSetIp(Auth::UserRequest::Pointer auth_user_request, Ip::Address &ipaddr) |
f5691f9c | 150 | { |
d87154ee | 151 | Auth::User::Pointer auth_user = auth_user_request->user(); |
f5691f9c | 152 | |
4c19ba24 | 153 | if (!auth_user) |
f5691f9c | 154 | return; |
155 | ||
4c19ba24 | 156 | auth_user->addIp(ipaddr); |
f5691f9c | 157 | } |
158 | ||
159 | void | |
c7baff40 | 160 | authenticateAuthUserRequestRemoveIp(Auth::UserRequest::Pointer auth_user_request, Ip::Address const &ipaddr) |
f5691f9c | 161 | { |
d87154ee | 162 | Auth::User::Pointer auth_user = auth_user_request->user(); |
f5691f9c | 163 | |
4c19ba24 | 164 | if (!auth_user) |
f5691f9c | 165 | return; |
166 | ||
4c19ba24 | 167 | auth_user->removeIp(ipaddr); |
f5691f9c | 168 | } |
169 | ||
170 | void | |
c7baff40 | 171 | authenticateAuthUserRequestClearIp(Auth::UserRequest::Pointer auth_user_request) |
f5691f9c | 172 | { |
aee3523a | 173 | if (auth_user_request != nullptr) |
f5691f9c | 174 | auth_user_request->user()->clearIp(); |
175 | } | |
176 | ||
4b0f5de8 | 177 | int |
c7baff40 | 178 | authenticateAuthUserRequestIPCount(Auth::UserRequest::Pointer auth_user_request) |
f5691f9c | 179 | { |
aee3523a AR |
180 | assert(auth_user_request != nullptr); |
181 | assert(auth_user_request->user() != nullptr); | |
f5691f9c | 182 | return auth_user_request->user()->ipcount; |
183 | } | |
184 | ||
f5691f9c | 185 | /* |
186 | * authenticateUserAuthenticated: is this auth_user structure logged in ? | |
187 | */ | |
e4bcf117 FC |
188 | bool |
189 | authenticateUserAuthenticated(const Auth::UserRequest::Pointer &auth_user_request) | |
f5691f9c | 190 | { |
e4bcf117 FC |
191 | if (!auth_user_request || !auth_user_request->valid()) |
192 | return false; | |
f5691f9c | 193 | |
194 | return auth_user_request->authenticated(); | |
195 | } | |
196 | ||
51a3dd58 | 197 | Auth::Direction |
c7baff40 | 198 | Auth::UserRequest::direction() |
f5691f9c | 199 | { |
aee3523a | 200 | if (user() == nullptr) |
51a3dd58 AJ |
201 | return Auth::CRED_ERROR; // No credentials. Should this be a CHALLENGE instead? |
202 | ||
f5691f9c | 203 | if (authenticateUserAuthenticated(this)) |
51a3dd58 | 204 | return Auth::CRED_VALID; |
f5691f9c | 205 | |
206 | return module_direction(); | |
f5691f9c | 207 | } |
208 | ||
209 | void | |
ced8def3 | 210 | Auth::UserRequest::addAuthenticationInfoHeader(HttpReply *, int) |
f5691f9c | 211 | {} |
212 | ||
213 | void | |
ced8def3 | 214 | Auth::UserRequest::addAuthenticationInfoTrailer(HttpReply *, int) |
f5691f9c | 215 | {} |
216 | ||
217 | void | |
cc1e110a | 218 | Auth::UserRequest::releaseAuthServer() |
f5691f9c | 219 | {} |
220 | ||
221 | const char * | |
c7baff40 | 222 | Auth::UserRequest::connLastHeader() |
f5691f9c | 223 | { |
c7baff40 | 224 | fatal("Auth::UserRequest::connLastHeader should always be overridden by conn based auth schemes"); |
aee3523a | 225 | return nullptr; |
f5691f9c | 226 | } |
227 | ||
228 | /* | |
26ac0430 | 229 | * authenticateAuthenticateUser: call the module specific code to |
f5691f9c | 230 | * log this user request in. |
231 | * Cache hits may change the auth_user pointer in the structure if needed. | |
232 | * This is basically a handle approach. | |
233 | */ | |
234 | static void | |
789217a2 | 235 | authenticateAuthenticateUser(Auth::UserRequest::Pointer auth_user_request, HttpRequest * request, ConnStateData * conn, Http::HdrType type) |
f5691f9c | 236 | { |
aee3523a | 237 | assert(auth_user_request.getRaw() != nullptr); |
f5691f9c | 238 | |
239 | auth_user_request->authenticate(request, conn, type); | |
240 | } | |
241 | ||
c7baff40 AJ |
242 | static Auth::UserRequest::Pointer |
243 | authTryGetUser(Auth::UserRequest::Pointer auth_user_request, ConnStateData * conn, HttpRequest * request) | |
f5691f9c | 244 | { |
71e7400c AJ |
245 | Auth::UserRequest::Pointer res; |
246 | ||
aee3523a | 247 | if (auth_user_request != nullptr) |
71e7400c | 248 | res = auth_user_request; |
aee3523a | 249 | else if (request != nullptr && request->auth_user_request != nullptr) |
71e7400c | 250 | res = request->auth_user_request; |
aee3523a | 251 | else if (conn != nullptr) |
71e7400c AJ |
252 | res = conn->getAuth(); |
253 | ||
254 | // attach the credential notes from helper to the transaction | |
aee3523a | 255 | if (request != nullptr && res != nullptr && res->user() != nullptr) { |
2f8abb64 | 256 | // XXX: we have no access to the transaction / AccessLogEntry so can't SyncNotes(). |
71e7400c AJ |
257 | // workaround by using anything already set in HttpRequest |
258 | // OR use new and rely on a later Sync copying these to AccessLogEntry | |
71e7400c | 259 | |
457857fe | 260 | UpdateRequestNotes(conn, *request, res->user()->notes); |
71e7400c AJ |
261 | } |
262 | ||
263 | return res; | |
f5691f9c | 264 | } |
265 | ||
266 | /* returns one of | |
267 | * AUTH_ACL_CHALLENGE, | |
268 | * AUTH_ACL_HELPER, | |
269 | * AUTH_ACL_CANNOT_AUTHENTICATE, | |
270 | * AUTH_AUTHENTICATED | |
271 | * | |
26ac0430 | 272 | * How to use: In your proxy-auth dependent acl code, use the following |
f5691f9c | 273 | * construct: |
274 | * int rv; | |
275 | * if ((rv = AuthenticateAuthenticate()) != AUTH_AUTHENTICATED) | |
276 | * return rv; | |
26ac0430 | 277 | * |
f5691f9c | 278 | * when this code is reached, the request/connection is authenticated. |
279 | * | |
26ac0430 | 280 | * if you have non-acl code, but want to force authentication, you need a |
f5691f9c | 281 | * callback mechanism like the acl testing routines that will send a 40[1|7] to |
26ac0430 | 282 | * the client when rv==AUTH_ACL_CHALLENGE, and will communicate with |
f5691f9c | 283 | * the authenticateStart routine for rv==AUTH_ACL_HELPER |
4f0ef8e8 | 284 | * |
285 | * Caller is responsible for locking and unlocking their *auth_user_request! | |
f5691f9c | 286 | */ |
56a49fda | 287 | AuthAclState |
789217a2 | 288 | Auth::UserRequest::authenticate(Auth::UserRequest::Pointer * auth_user_request, Http::HdrType headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr, AccessLogEntry::Pointer &al) |
f5691f9c | 289 | { |
290 | const char *proxy_auth; | |
291 | assert(headertype != 0); | |
292 | ||
a9925b40 | 293 | proxy_auth = request->header.getStr(headertype); |
f5691f9c | 294 | |
295 | /* | |
296 | * a note on proxy_auth logix here: | |
297 | * proxy_auth==NULL -> unauthenticated request || already | |
298 | * authenticated connection so we test for an authenticated | |
2f8abb64 | 299 | * connection when we receive no authentication header. |
f5691f9c | 300 | */ |
301 | ||
a1ce83aa | 302 | /* a) can we find other credentials to use? and b) are they logged in already? */ |
aee3523a | 303 | if (proxy_auth == nullptr && !authenticateUserAuthenticated(authTryGetUser(*auth_user_request,conn,request))) { |
f5691f9c | 304 | /* no header or authentication failed/got corrupted - restart */ |
bf95c10a | 305 | debugs(29, 4, "No Proxy-Auth header and no working alternative. Requesting auth header."); |
a1ce83aa | 306 | |
f5691f9c | 307 | /* something wrong with the AUTH credentials. Force a new attempt */ |
308 | ||
a1ce83aa | 309 | /* connection auth we must reset on auth errors */ |
aee3523a AR |
310 | if (conn != nullptr) { |
311 | conn->setAuth(nullptr, "HTTP request missing credentials"); | |
f5691f9c | 312 | } |
313 | ||
aee3523a | 314 | *auth_user_request = nullptr; |
f5691f9c | 315 | return AUTH_ACL_CHALLENGE; |
316 | } | |
317 | ||
318 | /* | |
319 | * Is this an already authenticated connection with a new auth header? | |
26ac0430 | 320 | * No check for function required in the if: its compulsory for conn based |
f5691f9c | 321 | * auth modules |
322 | */ | |
aee3523a | 323 | if (proxy_auth && conn != nullptr && conn->getAuth() != nullptr && |
cc1e110a | 324 | authenticateUserAuthenticated(conn->getAuth()) && |
aee3523a | 325 | conn->getAuth()->connLastHeader() != nullptr && |
cc1e110a | 326 | strcmp(proxy_auth, conn->getAuth()->connLastHeader())) { |
a1ce83aa | 327 | debugs(29, 2, "WARNING: DUPLICATE AUTH - authentication header on already authenticated connection!. AU " << |
cc1e110a AJ |
328 | conn->getAuth() << ", Current user '" << |
329 | conn->getAuth()->username() << "' proxy_auth " << | |
bf8fe701 | 330 | proxy_auth); |
331 | ||
a1ce83aa | 332 | /* remove this request struct - the link is already authed and it can't be to reauth. */ |
f5691f9c | 333 | |
334 | /* This should _only_ ever occur on the first pass through | |
26ac0430 | 335 | * authenticateAuthenticate |
f5691f9c | 336 | */ |
aee3523a AR |
337 | assert(*auth_user_request == nullptr); |
338 | conn->setAuth(nullptr, "changed credentials token"); | |
f5691f9c | 339 | } |
340 | ||
341 | /* we have a proxy auth header and as far as we know this connection has | |
342 | * not had bungled connection oriented authentication happen on it. */ | |
bf95c10a | 343 | debugs(29, 9, "header " << (proxy_auth ? proxy_auth : "-") << "."); |
f5691f9c | 344 | |
aee3523a AR |
345 | if (*auth_user_request == nullptr) { |
346 | if (conn != nullptr) { | |
bf95c10a | 347 | debugs(29, 9, "This is a new checklist test on:" << conn->clientConnection); |
5c336a3b | 348 | } |
f5691f9c | 349 | |
aee3523a | 350 | if (proxy_auth && request->auth_user_request == nullptr && conn != nullptr && conn->getAuth() != nullptr) { |
dc79fed8 | 351 | Auth::SchemeConfig * scheme = Auth::SchemeConfig::Find(proxy_auth); |
638b2ce3 | 352 | |
aee3523a | 353 | if (conn->getAuth()->user() == nullptr || conn->getAuth()->user()->config != scheme) { |
c7baff40 | 354 | debugs(29, DBG_IMPORTANT, "WARNING: Unexpected change of authentication scheme from '" << |
aee3523a | 355 | (conn->getAuth()->user()!=nullptr?conn->getAuth()->user()->config->type():"[no user]") << |
bf8fe701 | 356 | "' to '" << proxy_auth << "' (client " << |
cc192b50 | 357 | src_addr << ")"); |
bf8fe701 | 358 | |
aee3523a | 359 | conn->setAuth(nullptr, "changed auth scheme"); |
638b2ce3 | 360 | } |
361 | } | |
362 | ||
aee3523a | 363 | if (request->auth_user_request == nullptr && (conn == nullptr || conn->getAuth() == nullptr)) { |
f5691f9c | 364 | /* beginning of a new request check */ |
bf95c10a | 365 | debugs(29, 4, "No connection authentication type"); |
f5691f9c | 366 | |
dc79fed8 | 367 | *auth_user_request = Auth::SchemeConfig::CreateAuthUser(proxy_auth, al); |
aee3523a | 368 | if (*auth_user_request == nullptr) |
0a608df9 AJ |
369 | return AUTH_ACL_CHALLENGE; |
370 | else if (!(*auth_user_request)->valid()) { | |
f5691f9c | 371 | /* the decode might have left a username for logging, or a message to |
372 | * the user */ | |
373 | ||
374 | if ((*auth_user_request)->username()) { | |
f5691f9c | 375 | request->auth_user_request = *auth_user_request; |
376 | } | |
377 | ||
aee3523a | 378 | *auth_user_request = nullptr; |
f5691f9c | 379 | return AUTH_ACL_CHALLENGE; |
380 | } | |
381 | ||
aee3523a | 382 | } else if (request->auth_user_request != nullptr) { |
f5691f9c | 383 | *auth_user_request = request->auth_user_request; |
f5691f9c | 384 | } else { |
aee3523a AR |
385 | assert (conn != nullptr); |
386 | if (conn->getAuth() != nullptr) { | |
cc1e110a | 387 | *auth_user_request = conn->getAuth(); |
f5691f9c | 388 | } else { |
389 | /* failed connection based authentication */ | |
bf95c10a | 390 | debugs(29, 4, "Auth user request " << *auth_user_request << " conn-auth missing and failed to authenticate."); |
aee3523a | 391 | *auth_user_request = nullptr; |
f5691f9c | 392 | return AUTH_ACL_CHALLENGE; |
393 | } | |
394 | } | |
395 | } | |
396 | ||
26ac0430 | 397 | if (!authenticateUserAuthenticated(*auth_user_request)) { |
51a3dd58 | 398 | /* User not logged in. Try to log them in */ |
a33a428a | 399 | authenticateAuthenticateUser(*auth_user_request, request, conn, headertype); |
f5691f9c | 400 | |
51a3dd58 | 401 | switch ((*auth_user_request)->direction()) { |
f5691f9c | 402 | |
51a3dd58 | 403 | case Auth::CRED_CHALLENGE: |
f5691f9c | 404 | |
aee3523a | 405 | if (request->auth_user_request == nullptr) { |
f5691f9c | 406 | request->auth_user_request = *auth_user_request; |
407 | } | |
8b082ed9 FC |
408 | *auth_user_request = nullptr; |
409 | return AUTH_ACL_CHALLENGE; | |
f5691f9c | 410 | |
51a3dd58 | 411 | case Auth::CRED_ERROR: |
4f0ef8e8 | 412 | /* this ACL check is finished. */ |
aee3523a | 413 | *auth_user_request = nullptr; |
f5691f9c | 414 | return AUTH_ACL_CHALLENGE; |
415 | ||
51a3dd58 | 416 | case Auth::CRED_LOOKUP: |
f5691f9c | 417 | /* we are partway through authentication within squid, |
418 | * the *auth_user_request variables stores the auth_user_request | |
419 | * for the callback to here - Do not Unlock */ | |
420 | return AUTH_ACL_HELPER; | |
f5691f9c | 421 | |
51a3dd58 AJ |
422 | case Auth::CRED_VALID: |
423 | /* authentication is finished */ | |
424 | /* See if user authentication failed for some reason */ | |
425 | if (!authenticateUserAuthenticated(*auth_user_request)) { | |
426 | if ((*auth_user_request)->username()) { | |
427 | if (!request->auth_user_request) { | |
428 | request->auth_user_request = *auth_user_request; | |
429 | } | |
f5691f9c | 430 | } |
f5691f9c | 431 | |
aee3523a | 432 | *auth_user_request = nullptr; |
51a3dd58 AJ |
433 | return AUTH_ACL_CHALLENGE; |
434 | } | |
435 | // otherwise fallthrough to acceptance. | |
f5691f9c | 436 | } |
437 | } | |
438 | ||
439 | /* copy username to request for logging on client-side */ | |
440 | /* the credentials are correct at this point */ | |
aee3523a | 441 | if (request->auth_user_request == nullptr) { |
f5691f9c | 442 | request->auth_user_request = *auth_user_request; |
f5691f9c | 443 | authenticateAuthUserRequestSetIp(*auth_user_request, src_addr); |
444 | } | |
445 | ||
f5691f9c | 446 | return AUTH_AUTHENTICATED; |
447 | } | |
448 | ||
56a49fda | 449 | AuthAclState |
789217a2 | 450 | Auth::UserRequest::tryToAuthenticateAndSetAuthUser(Auth::UserRequest::Pointer * aUR, Http::HdrType headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr, AccessLogEntry::Pointer &al) |
f5691f9c | 451 | { |
c7baff40 AJ |
452 | // If we have already been called, return the cached value |
453 | Auth::UserRequest::Pointer t = authTryGetUser(*aUR, conn, request); | |
f5691f9c | 454 | |
aee3523a AR |
455 | if (t != nullptr && t->lastReply != AUTH_ACL_CANNOT_AUTHENTICATE && t->lastReply != AUTH_ACL_HELPER) { |
456 | if (*aUR == nullptr) | |
c7baff40 | 457 | *aUR = t; |
f5691f9c | 458 | |
aee3523a | 459 | if (request->auth_user_request == nullptr && t->lastReply == AUTH_AUTHENTICATED) { |
26ac0430 | 460 | request->auth_user_request = t; |
26ac0430 | 461 | } |
f5691f9c | 462 | return t->lastReply; |
463 | } | |
464 | ||
c7baff40 | 465 | // ok, call the actual authenticator routine. |
d4806c91 | 466 | AuthAclState result = authenticate(aUR, headertype, request, conn, src_addr, al); |
f5691f9c | 467 | |
c7baff40 AJ |
468 | // auth process may have changed the UserRequest we are dealing with |
469 | t = authTryGetUser(*aUR, conn, request); | |
f5691f9c | 470 | |
aee3523a | 471 | if (t != nullptr && result != AUTH_ACL_CANNOT_AUTHENTICATE && result != AUTH_ACL_HELPER) |
f5691f9c | 472 | t->lastReply = result; |
473 | ||
474 | return result; | |
475 | } | |
476 | ||
5bfc3dbd EB |
477 | static Auth::ConfigVector & |
478 | schemesConfig(HttpRequest *request, HttpReply *rep) | |
479 | { | |
d6e94bda | 480 | if (!Auth::TheConfig.schemeLists.empty() && Auth::TheConfig.schemeAccess) { |
e94ff527 | 481 | ACLFilledChecklist ch(nullptr, request); |
b1c2ea7a | 482 | ch.updateReply(rep); |
17e41e03 | 483 | const auto &answer = ch.fastCheck(Auth::TheConfig.schemeAccess); |
06bf5384 | 484 | if (answer.allowed()) |
d6e94bda | 485 | return Auth::TheConfig.schemeLists.at(answer.kind).authConfigs; |
5bfc3dbd | 486 | } |
5c112575 | 487 | return Auth::TheConfig.schemes; |
5bfc3dbd EB |
488 | } |
489 | ||
f5691f9c | 490 | void |
923a8d89 | 491 | Auth::UserRequest::AddReplyAuthHeader(HttpReply * rep, Auth::UserRequest::Pointer auth_user_request, HttpRequest * request, int accelerated, int internal) |
f5691f9c | 492 | /* send the auth types we are configured to support (and have compiled in!) */ |
493 | { | |
789217a2 | 494 | Http::HdrType type; |
f5691f9c | 495 | |
9b769c67 | 496 | switch (rep->sline.status()) { |
f5691f9c | 497 | |
955394ce | 498 | case Http::scProxyAuthenticationRequired: |
f5691f9c | 499 | /* Proxy authorisation needed */ |
789217a2 | 500 | type = Http::HdrType::PROXY_AUTHENTICATE; |
f5691f9c | 501 | break; |
502 | ||
955394ce | 503 | case Http::scUnauthorized: |
f5691f9c | 504 | /* WWW Authorisation needed */ |
789217a2 | 505 | type = Http::HdrType::WWW_AUTHENTICATE; |
f5691f9c | 506 | break; |
507 | ||
508 | default: | |
509 | /* Keep GCC happy */ | |
510 | /* some other HTTP status */ | |
81ab22b6 | 511 | type = Http::HdrType::BAD_HDR; |
f5691f9c | 512 | break; |
513 | } | |
514 | ||
81ab22b6 | 515 | debugs(29, 9, "headertype:" << type << " authuser:" << auth_user_request); |
f5691f9c | 516 | |
9b769c67 AJ |
517 | if (((rep->sline.status() == Http::scProxyAuthenticationRequired) |
518 | || (rep->sline.status() == Http::scUnauthorized)) && internal) | |
f5691f9c | 519 | /* this is a authenticate-needed response */ |
520 | { | |
521 | ||
aee3523a | 522 | if (auth_user_request != nullptr && auth_user_request->direction() == Auth::CRED_CHALLENGE) |
51a3dd58 | 523 | /* add the scheme specific challenge header to the response */ |
f5691f9c | 524 | auth_user_request->user()->config->fixHeader(auth_user_request, rep, type, request); |
26ac0430 | 525 | else { |
dc79fed8 | 526 | /* call each configured & running auth scheme */ |
5bfc3dbd | 527 | Auth::ConfigVector &configs = schemesConfig(request, rep); |
dc79fed8 | 528 | for (auto *scheme : configs) { |
34401cfb | 529 | if (scheme->active()) { |
aee3523a | 530 | if (auth_user_request != nullptr && auth_user_request->scheme()->type() == scheme->type()) |
34401cfb HN |
531 | scheme->fixHeader(auth_user_request, rep, type, request); |
532 | else | |
aee3523a | 533 | scheme->fixHeader(nullptr, rep, type, request); |
34401cfb | 534 | } else |
bf95c10a | 535 | debugs(29, 4, "Configured scheme " << scheme->type() << " not Active"); |
f5691f9c | 536 | } |
537 | } | |
538 | ||
539 | } | |
7afc3bf2 | 540 | |
f5691f9c | 541 | /* |
542 | * allow protocol specific headers to be _added_ to the existing | |
7afc3bf2 | 543 | * response - currently Digest or Negotiate auth |
f5691f9c | 544 | */ |
aee3523a | 545 | if (auth_user_request != nullptr) { |
7afc3bf2 | 546 | auth_user_request->addAuthenticationInfoHeader(rep, accelerated); |
26ac0430 AJ |
547 | if (auth_user_request->lastReply != AUTH_AUTHENTICATED) |
548 | auth_user_request->lastReply = AUTH_ACL_CANNOT_AUTHENTICATE; | |
f5691f9c | 549 | } |
550 | } | |
551 | ||
c6cf8dee | 552 | Auth::Scheme::Pointer |
c7baff40 | 553 | Auth::UserRequest::scheme() const |
f5691f9c | 554 | { |
c6cf8dee | 555 | return Auth::Scheme::Find(user()->config->type()); |
f5691f9c | 556 | } |
d4806c91 CT |
557 | |
558 | const char * | |
559 | Auth::UserRequest::helperRequestKeyExtras(HttpRequest *request, AccessLogEntry::Pointer &al) | |
560 | { | |
561 | if (Format::Format *reqFmt = user()->config->keyExtras) { | |
562 | static MemBuf mb; | |
563 | mb.reset(); | |
564 | // We should pass AccessLogEntry as second argument .... | |
565 | Auth::UserRequest::Pointer oldReq = request->auth_user_request; | |
566 | request->auth_user_request = this; | |
567 | reqFmt->assemble(mb, al, 0); | |
568 | request->auth_user_request = oldReq; | |
569 | debugs(29, 5, "Assembled line to send :" << mb.content()); | |
570 | return mb.content(); | |
571 | } | |
aee3523a | 572 | return nullptr; |
d4806c91 | 573 | } |
f53969cc | 574 | |
6f9a30f8 EB |
575 | void |
576 | Auth::UserRequest::denyMessageFromHelper(const char *proto, const Helper::Reply &reply) | |
577 | { | |
578 | static SBuf messageNote; | |
579 | if (!reply.notes.find(messageNote, "message")) { | |
580 | messageNote.append(proto); | |
581 | messageNote.append(" Authentication denied with no reason given"); | |
582 | } | |
583 | setDenyMessage(messageNote.c_str()); | |
584 | } | |
585 |