]>
Commit | Line | Data |
---|---|---|
f5691f9c | 1 | /* |
bf95c10a | 2 | * Copyright (C) 1996-2022 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 | ||
135 | static void | |
c7baff40 | 136 | authenticateAuthUserRequestSetIp(Auth::UserRequest::Pointer auth_user_request, Ip::Address &ipaddr) |
f5691f9c | 137 | { |
d87154ee | 138 | Auth::User::Pointer auth_user = auth_user_request->user(); |
f5691f9c | 139 | |
4c19ba24 | 140 | if (!auth_user) |
f5691f9c | 141 | return; |
142 | ||
4c19ba24 | 143 | auth_user->addIp(ipaddr); |
f5691f9c | 144 | } |
145 | ||
146 | void | |
c7baff40 | 147 | authenticateAuthUserRequestRemoveIp(Auth::UserRequest::Pointer auth_user_request, Ip::Address const &ipaddr) |
f5691f9c | 148 | { |
d87154ee | 149 | Auth::User::Pointer auth_user = auth_user_request->user(); |
f5691f9c | 150 | |
4c19ba24 | 151 | if (!auth_user) |
f5691f9c | 152 | return; |
153 | ||
4c19ba24 | 154 | auth_user->removeIp(ipaddr); |
f5691f9c | 155 | } |
156 | ||
157 | void | |
c7baff40 | 158 | authenticateAuthUserRequestClearIp(Auth::UserRequest::Pointer auth_user_request) |
f5691f9c | 159 | { |
aee3523a | 160 | if (auth_user_request != nullptr) |
f5691f9c | 161 | auth_user_request->user()->clearIp(); |
162 | } | |
163 | ||
4b0f5de8 | 164 | int |
c7baff40 | 165 | authenticateAuthUserRequestIPCount(Auth::UserRequest::Pointer auth_user_request) |
f5691f9c | 166 | { |
aee3523a AR |
167 | assert(auth_user_request != nullptr); |
168 | assert(auth_user_request->user() != nullptr); | |
f5691f9c | 169 | return auth_user_request->user()->ipcount; |
170 | } | |
171 | ||
f5691f9c | 172 | /* |
173 | * authenticateUserAuthenticated: is this auth_user structure logged in ? | |
174 | */ | |
175 | int | |
c7baff40 | 176 | authenticateUserAuthenticated(Auth::UserRequest::Pointer auth_user_request) |
f5691f9c | 177 | { |
aee3523a | 178 | if (auth_user_request == nullptr || !auth_user_request->valid()) |
f5691f9c | 179 | return 0; |
180 | ||
181 | return auth_user_request->authenticated(); | |
182 | } | |
183 | ||
51a3dd58 | 184 | Auth::Direction |
c7baff40 | 185 | Auth::UserRequest::direction() |
f5691f9c | 186 | { |
aee3523a | 187 | if (user() == nullptr) |
51a3dd58 AJ |
188 | return Auth::CRED_ERROR; // No credentials. Should this be a CHALLENGE instead? |
189 | ||
f5691f9c | 190 | if (authenticateUserAuthenticated(this)) |
51a3dd58 | 191 | return Auth::CRED_VALID; |
f5691f9c | 192 | |
193 | return module_direction(); | |
f5691f9c | 194 | } |
195 | ||
196 | void | |
ced8def3 | 197 | Auth::UserRequest::addAuthenticationInfoHeader(HttpReply *, int) |
f5691f9c | 198 | {} |
199 | ||
200 | void | |
ced8def3 | 201 | Auth::UserRequest::addAuthenticationInfoTrailer(HttpReply *, int) |
f5691f9c | 202 | {} |
203 | ||
204 | void | |
cc1e110a | 205 | Auth::UserRequest::releaseAuthServer() |
f5691f9c | 206 | {} |
207 | ||
208 | const char * | |
c7baff40 | 209 | Auth::UserRequest::connLastHeader() |
f5691f9c | 210 | { |
c7baff40 | 211 | fatal("Auth::UserRequest::connLastHeader should always be overridden by conn based auth schemes"); |
aee3523a | 212 | return nullptr; |
f5691f9c | 213 | } |
214 | ||
215 | /* | |
26ac0430 | 216 | * authenticateAuthenticateUser: call the module specific code to |
f5691f9c | 217 | * log this user request in. |
218 | * Cache hits may change the auth_user pointer in the structure if needed. | |
219 | * This is basically a handle approach. | |
220 | */ | |
221 | static void | |
789217a2 | 222 | authenticateAuthenticateUser(Auth::UserRequest::Pointer auth_user_request, HttpRequest * request, ConnStateData * conn, Http::HdrType type) |
f5691f9c | 223 | { |
aee3523a | 224 | assert(auth_user_request.getRaw() != nullptr); |
f5691f9c | 225 | |
226 | auth_user_request->authenticate(request, conn, type); | |
227 | } | |
228 | ||
c7baff40 AJ |
229 | static Auth::UserRequest::Pointer |
230 | authTryGetUser(Auth::UserRequest::Pointer auth_user_request, ConnStateData * conn, HttpRequest * request) | |
f5691f9c | 231 | { |
71e7400c AJ |
232 | Auth::UserRequest::Pointer res; |
233 | ||
aee3523a | 234 | if (auth_user_request != nullptr) |
71e7400c | 235 | res = auth_user_request; |
aee3523a | 236 | else if (request != nullptr && request->auth_user_request != nullptr) |
71e7400c | 237 | res = request->auth_user_request; |
aee3523a | 238 | else if (conn != nullptr) |
71e7400c AJ |
239 | res = conn->getAuth(); |
240 | ||
241 | // attach the credential notes from helper to the transaction | |
aee3523a | 242 | if (request != nullptr && res != nullptr && res->user() != nullptr) { |
2f8abb64 | 243 | // XXX: we have no access to the transaction / AccessLogEntry so can't SyncNotes(). |
71e7400c AJ |
244 | // workaround by using anything already set in HttpRequest |
245 | // OR use new and rely on a later Sync copying these to AccessLogEntry | |
71e7400c | 246 | |
457857fe | 247 | UpdateRequestNotes(conn, *request, res->user()->notes); |
71e7400c AJ |
248 | } |
249 | ||
250 | return res; | |
f5691f9c | 251 | } |
252 | ||
253 | /* returns one of | |
254 | * AUTH_ACL_CHALLENGE, | |
255 | * AUTH_ACL_HELPER, | |
256 | * AUTH_ACL_CANNOT_AUTHENTICATE, | |
257 | * AUTH_AUTHENTICATED | |
258 | * | |
26ac0430 | 259 | * How to use: In your proxy-auth dependent acl code, use the following |
f5691f9c | 260 | * construct: |
261 | * int rv; | |
262 | * if ((rv = AuthenticateAuthenticate()) != AUTH_AUTHENTICATED) | |
263 | * return rv; | |
26ac0430 | 264 | * |
f5691f9c | 265 | * when this code is reached, the request/connection is authenticated. |
266 | * | |
26ac0430 | 267 | * if you have non-acl code, but want to force authentication, you need a |
f5691f9c | 268 | * callback mechanism like the acl testing routines that will send a 40[1|7] to |
26ac0430 | 269 | * the client when rv==AUTH_ACL_CHALLENGE, and will communicate with |
f5691f9c | 270 | * the authenticateStart routine for rv==AUTH_ACL_HELPER |
4f0ef8e8 | 271 | * |
272 | * Caller is responsible for locking and unlocking their *auth_user_request! | |
f5691f9c | 273 | */ |
56a49fda | 274 | AuthAclState |
789217a2 | 275 | Auth::UserRequest::authenticate(Auth::UserRequest::Pointer * auth_user_request, Http::HdrType headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr, AccessLogEntry::Pointer &al) |
f5691f9c | 276 | { |
277 | const char *proxy_auth; | |
278 | assert(headertype != 0); | |
279 | ||
a9925b40 | 280 | proxy_auth = request->header.getStr(headertype); |
f5691f9c | 281 | |
282 | /* | |
283 | * a note on proxy_auth logix here: | |
284 | * proxy_auth==NULL -> unauthenticated request || already | |
285 | * authenticated connection so we test for an authenticated | |
2f8abb64 | 286 | * connection when we receive no authentication header. |
f5691f9c | 287 | */ |
288 | ||
a1ce83aa | 289 | /* a) can we find other credentials to use? and b) are they logged in already? */ |
aee3523a | 290 | if (proxy_auth == nullptr && !authenticateUserAuthenticated(authTryGetUser(*auth_user_request,conn,request))) { |
f5691f9c | 291 | /* no header or authentication failed/got corrupted - restart */ |
bf95c10a | 292 | debugs(29, 4, "No Proxy-Auth header and no working alternative. Requesting auth header."); |
a1ce83aa | 293 | |
f5691f9c | 294 | /* something wrong with the AUTH credentials. Force a new attempt */ |
295 | ||
a1ce83aa | 296 | /* connection auth we must reset on auth errors */ |
aee3523a AR |
297 | if (conn != nullptr) { |
298 | conn->setAuth(nullptr, "HTTP request missing credentials"); | |
f5691f9c | 299 | } |
300 | ||
aee3523a | 301 | *auth_user_request = nullptr; |
f5691f9c | 302 | return AUTH_ACL_CHALLENGE; |
303 | } | |
304 | ||
305 | /* | |
306 | * Is this an already authenticated connection with a new auth header? | |
26ac0430 | 307 | * No check for function required in the if: its compulsory for conn based |
f5691f9c | 308 | * auth modules |
309 | */ | |
aee3523a | 310 | if (proxy_auth && conn != nullptr && conn->getAuth() != nullptr && |
cc1e110a | 311 | authenticateUserAuthenticated(conn->getAuth()) && |
aee3523a | 312 | conn->getAuth()->connLastHeader() != nullptr && |
cc1e110a | 313 | strcmp(proxy_auth, conn->getAuth()->connLastHeader())) { |
a1ce83aa | 314 | debugs(29, 2, "WARNING: DUPLICATE AUTH - authentication header on already authenticated connection!. AU " << |
cc1e110a AJ |
315 | conn->getAuth() << ", Current user '" << |
316 | conn->getAuth()->username() << "' proxy_auth " << | |
bf8fe701 | 317 | proxy_auth); |
318 | ||
a1ce83aa | 319 | /* remove this request struct - the link is already authed and it can't be to reauth. */ |
f5691f9c | 320 | |
321 | /* This should _only_ ever occur on the first pass through | |
26ac0430 | 322 | * authenticateAuthenticate |
f5691f9c | 323 | */ |
aee3523a AR |
324 | assert(*auth_user_request == nullptr); |
325 | conn->setAuth(nullptr, "changed credentials token"); | |
f5691f9c | 326 | } |
327 | ||
328 | /* we have a proxy auth header and as far as we know this connection has | |
329 | * not had bungled connection oriented authentication happen on it. */ | |
bf95c10a | 330 | debugs(29, 9, "header " << (proxy_auth ? proxy_auth : "-") << "."); |
f5691f9c | 331 | |
aee3523a AR |
332 | if (*auth_user_request == nullptr) { |
333 | if (conn != nullptr) { | |
bf95c10a | 334 | debugs(29, 9, "This is a new checklist test on:" << conn->clientConnection); |
5c336a3b | 335 | } |
f5691f9c | 336 | |
aee3523a | 337 | if (proxy_auth && request->auth_user_request == nullptr && conn != nullptr && conn->getAuth() != nullptr) { |
dc79fed8 | 338 | Auth::SchemeConfig * scheme = Auth::SchemeConfig::Find(proxy_auth); |
638b2ce3 | 339 | |
aee3523a | 340 | if (conn->getAuth()->user() == nullptr || conn->getAuth()->user()->config != scheme) { |
c7baff40 | 341 | debugs(29, DBG_IMPORTANT, "WARNING: Unexpected change of authentication scheme from '" << |
aee3523a | 342 | (conn->getAuth()->user()!=nullptr?conn->getAuth()->user()->config->type():"[no user]") << |
bf8fe701 | 343 | "' to '" << proxy_auth << "' (client " << |
cc192b50 | 344 | src_addr << ")"); |
bf8fe701 | 345 | |
aee3523a | 346 | conn->setAuth(nullptr, "changed auth scheme"); |
638b2ce3 | 347 | } |
348 | } | |
349 | ||
aee3523a | 350 | if (request->auth_user_request == nullptr && (conn == nullptr || conn->getAuth() == nullptr)) { |
f5691f9c | 351 | /* beginning of a new request check */ |
bf95c10a | 352 | debugs(29, 4, "No connection authentication type"); |
f5691f9c | 353 | |
dc79fed8 | 354 | *auth_user_request = Auth::SchemeConfig::CreateAuthUser(proxy_auth, al); |
aee3523a | 355 | if (*auth_user_request == nullptr) |
0a608df9 AJ |
356 | return AUTH_ACL_CHALLENGE; |
357 | else if (!(*auth_user_request)->valid()) { | |
f5691f9c | 358 | /* the decode might have left a username for logging, or a message to |
359 | * the user */ | |
360 | ||
361 | if ((*auth_user_request)->username()) { | |
f5691f9c | 362 | request->auth_user_request = *auth_user_request; |
363 | } | |
364 | ||
aee3523a | 365 | *auth_user_request = nullptr; |
f5691f9c | 366 | return AUTH_ACL_CHALLENGE; |
367 | } | |
368 | ||
aee3523a | 369 | } else if (request->auth_user_request != nullptr) { |
f5691f9c | 370 | *auth_user_request = request->auth_user_request; |
f5691f9c | 371 | } else { |
aee3523a AR |
372 | assert (conn != nullptr); |
373 | if (conn->getAuth() != nullptr) { | |
cc1e110a | 374 | *auth_user_request = conn->getAuth(); |
f5691f9c | 375 | } else { |
376 | /* failed connection based authentication */ | |
bf95c10a | 377 | debugs(29, 4, "Auth user request " << *auth_user_request << " conn-auth missing and failed to authenticate."); |
aee3523a | 378 | *auth_user_request = nullptr; |
f5691f9c | 379 | return AUTH_ACL_CHALLENGE; |
380 | } | |
381 | } | |
382 | } | |
383 | ||
26ac0430 | 384 | if (!authenticateUserAuthenticated(*auth_user_request)) { |
51a3dd58 | 385 | /* User not logged in. Try to log them in */ |
a33a428a | 386 | authenticateAuthenticateUser(*auth_user_request, request, conn, headertype); |
f5691f9c | 387 | |
51a3dd58 | 388 | switch ((*auth_user_request)->direction()) { |
f5691f9c | 389 | |
51a3dd58 | 390 | case Auth::CRED_CHALLENGE: |
f5691f9c | 391 | |
aee3523a | 392 | if (request->auth_user_request == nullptr) { |
f5691f9c | 393 | request->auth_user_request = *auth_user_request; |
394 | } | |
8b082ed9 FC |
395 | *auth_user_request = nullptr; |
396 | return AUTH_ACL_CHALLENGE; | |
f5691f9c | 397 | |
51a3dd58 | 398 | case Auth::CRED_ERROR: |
4f0ef8e8 | 399 | /* this ACL check is finished. */ |
aee3523a | 400 | *auth_user_request = nullptr; |
f5691f9c | 401 | return AUTH_ACL_CHALLENGE; |
402 | ||
51a3dd58 | 403 | case Auth::CRED_LOOKUP: |
f5691f9c | 404 | /* we are partway through authentication within squid, |
405 | * the *auth_user_request variables stores the auth_user_request | |
406 | * for the callback to here - Do not Unlock */ | |
407 | return AUTH_ACL_HELPER; | |
f5691f9c | 408 | |
51a3dd58 AJ |
409 | case Auth::CRED_VALID: |
410 | /* authentication is finished */ | |
411 | /* See if user authentication failed for some reason */ | |
412 | if (!authenticateUserAuthenticated(*auth_user_request)) { | |
413 | if ((*auth_user_request)->username()) { | |
414 | if (!request->auth_user_request) { | |
415 | request->auth_user_request = *auth_user_request; | |
416 | } | |
f5691f9c | 417 | } |
f5691f9c | 418 | |
aee3523a | 419 | *auth_user_request = nullptr; |
51a3dd58 AJ |
420 | return AUTH_ACL_CHALLENGE; |
421 | } | |
422 | // otherwise fallthrough to acceptance. | |
f5691f9c | 423 | } |
424 | } | |
425 | ||
426 | /* copy username to request for logging on client-side */ | |
427 | /* the credentials are correct at this point */ | |
aee3523a | 428 | if (request->auth_user_request == nullptr) { |
f5691f9c | 429 | request->auth_user_request = *auth_user_request; |
f5691f9c | 430 | authenticateAuthUserRequestSetIp(*auth_user_request, src_addr); |
431 | } | |
432 | ||
f5691f9c | 433 | return AUTH_AUTHENTICATED; |
434 | } | |
435 | ||
56a49fda | 436 | AuthAclState |
789217a2 | 437 | Auth::UserRequest::tryToAuthenticateAndSetAuthUser(Auth::UserRequest::Pointer * aUR, Http::HdrType headertype, HttpRequest * request, ConnStateData * conn, Ip::Address &src_addr, AccessLogEntry::Pointer &al) |
f5691f9c | 438 | { |
c7baff40 AJ |
439 | // If we have already been called, return the cached value |
440 | Auth::UserRequest::Pointer t = authTryGetUser(*aUR, conn, request); | |
f5691f9c | 441 | |
aee3523a AR |
442 | if (t != nullptr && t->lastReply != AUTH_ACL_CANNOT_AUTHENTICATE && t->lastReply != AUTH_ACL_HELPER) { |
443 | if (*aUR == nullptr) | |
c7baff40 | 444 | *aUR = t; |
f5691f9c | 445 | |
aee3523a | 446 | if (request->auth_user_request == nullptr && t->lastReply == AUTH_AUTHENTICATED) { |
26ac0430 | 447 | request->auth_user_request = t; |
26ac0430 | 448 | } |
f5691f9c | 449 | return t->lastReply; |
450 | } | |
451 | ||
c7baff40 | 452 | // ok, call the actual authenticator routine. |
d4806c91 | 453 | AuthAclState result = authenticate(aUR, headertype, request, conn, src_addr, al); |
f5691f9c | 454 | |
c7baff40 AJ |
455 | // auth process may have changed the UserRequest we are dealing with |
456 | t = authTryGetUser(*aUR, conn, request); | |
f5691f9c | 457 | |
aee3523a | 458 | if (t != nullptr && result != AUTH_ACL_CANNOT_AUTHENTICATE && result != AUTH_ACL_HELPER) |
f5691f9c | 459 | t->lastReply = result; |
460 | ||
461 | return result; | |
462 | } | |
463 | ||
5bfc3dbd EB |
464 | static Auth::ConfigVector & |
465 | schemesConfig(HttpRequest *request, HttpReply *rep) | |
466 | { | |
d6e94bda | 467 | if (!Auth::TheConfig.schemeLists.empty() && Auth::TheConfig.schemeAccess) { |
aee3523a | 468 | ACLFilledChecklist ch(nullptr, request, nullptr); |
5bfc3dbd EB |
469 | ch.reply = rep; |
470 | HTTPMSGLOCK(ch.reply); | |
329c128c | 471 | const auto answer = ch.fastCheck(Auth::TheConfig.schemeAccess); |
06bf5384 | 472 | if (answer.allowed()) |
d6e94bda | 473 | return Auth::TheConfig.schemeLists.at(answer.kind).authConfigs; |
5bfc3dbd | 474 | } |
5c112575 | 475 | return Auth::TheConfig.schemes; |
5bfc3dbd EB |
476 | } |
477 | ||
f5691f9c | 478 | void |
923a8d89 | 479 | Auth::UserRequest::AddReplyAuthHeader(HttpReply * rep, Auth::UserRequest::Pointer auth_user_request, HttpRequest * request, int accelerated, int internal) |
f5691f9c | 480 | /* send the auth types we are configured to support (and have compiled in!) */ |
481 | { | |
789217a2 | 482 | Http::HdrType type; |
f5691f9c | 483 | |
9b769c67 | 484 | switch (rep->sline.status()) { |
f5691f9c | 485 | |
955394ce | 486 | case Http::scProxyAuthenticationRequired: |
f5691f9c | 487 | /* Proxy authorisation needed */ |
789217a2 | 488 | type = Http::HdrType::PROXY_AUTHENTICATE; |
f5691f9c | 489 | break; |
490 | ||
955394ce | 491 | case Http::scUnauthorized: |
f5691f9c | 492 | /* WWW Authorisation needed */ |
789217a2 | 493 | type = Http::HdrType::WWW_AUTHENTICATE; |
f5691f9c | 494 | break; |
495 | ||
496 | default: | |
497 | /* Keep GCC happy */ | |
498 | /* some other HTTP status */ | |
81ab22b6 | 499 | type = Http::HdrType::BAD_HDR; |
f5691f9c | 500 | break; |
501 | } | |
502 | ||
81ab22b6 | 503 | debugs(29, 9, "headertype:" << type << " authuser:" << auth_user_request); |
f5691f9c | 504 | |
9b769c67 AJ |
505 | if (((rep->sline.status() == Http::scProxyAuthenticationRequired) |
506 | || (rep->sline.status() == Http::scUnauthorized)) && internal) | |
f5691f9c | 507 | /* this is a authenticate-needed response */ |
508 | { | |
509 | ||
aee3523a | 510 | if (auth_user_request != nullptr && auth_user_request->direction() == Auth::CRED_CHALLENGE) |
51a3dd58 | 511 | /* add the scheme specific challenge header to the response */ |
f5691f9c | 512 | auth_user_request->user()->config->fixHeader(auth_user_request, rep, type, request); |
26ac0430 | 513 | else { |
dc79fed8 | 514 | /* call each configured & running auth scheme */ |
5bfc3dbd | 515 | Auth::ConfigVector &configs = schemesConfig(request, rep); |
dc79fed8 | 516 | for (auto *scheme : configs) { |
34401cfb | 517 | if (scheme->active()) { |
aee3523a | 518 | if (auth_user_request != nullptr && auth_user_request->scheme()->type() == scheme->type()) |
34401cfb HN |
519 | scheme->fixHeader(auth_user_request, rep, type, request); |
520 | else | |
aee3523a | 521 | scheme->fixHeader(nullptr, rep, type, request); |
34401cfb | 522 | } else |
bf95c10a | 523 | debugs(29, 4, "Configured scheme " << scheme->type() << " not Active"); |
f5691f9c | 524 | } |
525 | } | |
526 | ||
527 | } | |
7afc3bf2 | 528 | |
f5691f9c | 529 | /* |
530 | * allow protocol specific headers to be _added_ to the existing | |
7afc3bf2 | 531 | * response - currently Digest or Negotiate auth |
f5691f9c | 532 | */ |
aee3523a | 533 | if (auth_user_request != nullptr) { |
7afc3bf2 | 534 | auth_user_request->addAuthenticationInfoHeader(rep, accelerated); |
26ac0430 AJ |
535 | if (auth_user_request->lastReply != AUTH_AUTHENTICATED) |
536 | auth_user_request->lastReply = AUTH_ACL_CANNOT_AUTHENTICATE; | |
f5691f9c | 537 | } |
538 | } | |
539 | ||
c6cf8dee | 540 | Auth::Scheme::Pointer |
c7baff40 | 541 | Auth::UserRequest::scheme() const |
f5691f9c | 542 | { |
c6cf8dee | 543 | return Auth::Scheme::Find(user()->config->type()); |
f5691f9c | 544 | } |
d4806c91 CT |
545 | |
546 | const char * | |
547 | Auth::UserRequest::helperRequestKeyExtras(HttpRequest *request, AccessLogEntry::Pointer &al) | |
548 | { | |
549 | if (Format::Format *reqFmt = user()->config->keyExtras) { | |
550 | static MemBuf mb; | |
551 | mb.reset(); | |
552 | // We should pass AccessLogEntry as second argument .... | |
553 | Auth::UserRequest::Pointer oldReq = request->auth_user_request; | |
554 | request->auth_user_request = this; | |
555 | reqFmt->assemble(mb, al, 0); | |
556 | request->auth_user_request = oldReq; | |
557 | debugs(29, 5, "Assembled line to send :" << mb.content()); | |
558 | return mb.content(); | |
559 | } | |
aee3523a | 560 | return nullptr; |
d4806c91 | 561 | } |
f53969cc | 562 | |
6f9a30f8 EB |
563 | void |
564 | Auth::UserRequest::denyMessageFromHelper(const char *proto, const Helper::Reply &reply) | |
565 | { | |
566 | static SBuf messageNote; | |
567 | if (!reply.notes.find(messageNote, "message")) { | |
568 | messageNote.append(proto); | |
569 | messageNote.append(" Authentication denied with no reason given"); | |
570 | } | |
571 | setDenyMessage(messageNote.c_str()); | |
572 | } | |
573 |