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