]>
Commit | Line | Data |
---|---|---|
bbc27441 | 1 | /* |
77b1029d | 2 | * Copyright (C) 1996-2020 The Squid Software Foundation and contributors |
bbc27441 AJ |
3 | * |
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. | |
7 | */ | |
8 | ||
f7f3304a | 9 | #include "squid.h" |
12daeef6 | 10 | #include "auth/basic/Config.h" |
aa110616 | 11 | #include "auth/basic/User.h" |
616cfc4c | 12 | #include "auth/basic/UserRequest.h" |
bf929433 | 13 | #include "auth/QueueNode.h" |
fe0a0419 | 14 | #include "auth/State.h" |
582c2af2 | 15 | #include "Debug.h" |
86c63190 | 16 | #include "format/Format.h" |
24438ec5 AJ |
17 | #include "helper.h" |
18 | #include "helper/Reply.h" | |
d4806c91 | 19 | #include "HttpRequest.h" |
d4806c91 | 20 | #include "MemBuf.h" |
fe0a0419 | 21 | #include "rfc1738.h" |
616cfc4c | 22 | #include "SquidTime.h" |
928f3421 | 23 | |
fe0a0419 AJ |
24 | #if !defined(HELPER_INPUT_BUFFER) |
25 | #define HELPER_INPUT_BUFFER 8192 | |
26 | #endif | |
27 | ||
928f3421 | 28 | int |
c7baff40 | 29 | Auth::Basic::UserRequest::authenticated() const |
928f3421 | 30 | { |
aa110616 | 31 | Auth::Basic::User const *basic_auth = dynamic_cast<Auth::Basic::User const *>(user().getRaw()); |
928f3421 AJ |
32 | |
33 | if (basic_auth && basic_auth->authenticated()) | |
34 | return 1; | |
35 | ||
36 | return 0; | |
37 | } | |
38 | ||
d4806c91 CT |
39 | const char * |
40 | Auth::Basic::UserRequest::credentialsStr() | |
41 | { | |
42 | Auth::Basic::User const *basic_auth = dynamic_cast<Auth::Basic::User const *>(user().getRaw()); | |
43 | if (basic_auth) | |
44 | return basic_auth->passwd; | |
45 | return NULL; | |
46 | } | |
47 | ||
928f3421 AJ |
48 | /* log a basic user in |
49 | */ | |
50 | void | |
789217a2 | 51 | Auth::Basic::UserRequest::authenticate(HttpRequest *, ConnStateData *, Http::HdrType) |
928f3421 AJ |
52 | { |
53 | assert(user() != NULL); | |
54 | ||
928f3421 | 55 | /* if the password is not ok, do an identity */ |
d87154ee | 56 | if (!user() || user()->credentials() != Auth::Ok) |
928f3421 AJ |
57 | return; |
58 | ||
59 | /* are we about to recheck the credentials externally? */ | |
dc79fed8 | 60 | if ((user()->expiretime + static_cast<Auth::Basic::Config*>(Auth::SchemeConfig::Find("basic"))->credentialsTTL) <= squid_curtime) { |
d232141d | 61 | debugs(29, 4, HERE << "credentials expired - rechecking"); |
928f3421 AJ |
62 | return; |
63 | } | |
64 | ||
65 | /* we have been through the external helper, and the credentials haven't expired */ | |
d232141d | 66 | debugs(29, 9, HERE << "user '" << user()->username() << "' authenticated"); |
928f3421 AJ |
67 | |
68 | /* Decode now takes care of finding the AuthUser struct in the cache */ | |
69 | /* after external auth occurs anyway */ | |
d232141d | 70 | user()->expiretime = current_time.tv_sec; |
928f3421 AJ |
71 | } |
72 | ||
51a3dd58 | 73 | Auth::Direction |
c7baff40 | 74 | Auth::Basic::UserRequest::module_direction() |
928f3421 | 75 | { |
c7baff40 | 76 | /* null auth_user is checked for by Auth::UserRequest::direction() */ |
616cfc4c | 77 | if (user()->auth_type != Auth::AUTH_BASIC) |
51a3dd58 | 78 | return Auth::CRED_ERROR; |
928f3421 | 79 | |
d232141d | 80 | switch (user()->credentials()) { |
928f3421 | 81 | |
d87154ee AJ |
82 | case Auth::Unchecked: |
83 | case Auth::Pending: | |
51a3dd58 | 84 | return Auth::CRED_LOOKUP; |
928f3421 | 85 | |
d87154ee | 86 | case Auth::Ok: |
dc79fed8 | 87 | if (user()->expiretime + static_cast<Auth::Basic::Config*>(Auth::SchemeConfig::Find("basic"))->credentialsTTL <= squid_curtime) |
51a3dd58 AJ |
88 | return Auth::CRED_LOOKUP; |
89 | return Auth::CRED_VALID; | |
928f3421 | 90 | |
d87154ee | 91 | case Auth::Failed: |
51a3dd58 | 92 | return Auth::CRED_VALID; |
928f3421 | 93 | |
d232141d | 94 | default: |
51a3dd58 | 95 | return Auth::CRED_ERROR; |
d232141d | 96 | } |
928f3421 AJ |
97 | } |
98 | ||
99 | /* send the initial data to a basic authenticator module */ | |
100 | void | |
30c3f584 | 101 | Auth::Basic::UserRequest::startHelperLookup(HttpRequest *request, AccessLogEntry::Pointer &al, AUTHCB * handler, void *data) |
928f3421 | 102 | { |
616cfc4c | 103 | assert(user()->auth_type == Auth::AUTH_BASIC); |
aa110616 | 104 | Auth::Basic::User *basic_auth = dynamic_cast<Auth::Basic::User *>(user().getRaw()); |
928f3421 AJ |
105 | assert(basic_auth != NULL); |
106 | debugs(29, 9, HERE << "'" << basic_auth->username() << ":" << basic_auth->passwd << "'"); | |
107 | ||
dc79fed8 | 108 | if (static_cast<Auth::Basic::Config*>(Auth::SchemeConfig::Find("basic"))->authenticateProgram == NULL) { |
d232141d | 109 | debugs(29, DBG_CRITICAL, "ERROR: No Basic authentication program configured."); |
4c535e87 | 110 | handler(data); |
928f3421 AJ |
111 | return; |
112 | } | |
113 | ||
114 | /* check to see if the auth_user already has a request outstanding */ | |
d87154ee | 115 | if (user()->credentials() == Auth::Pending) { |
928f3421 | 116 | /* there is a request with the same credentials already being verified */ |
fe0a0419 | 117 | |
bf929433 | 118 | Auth::QueueNode *node = new Auth::QueueNode(this, handler, data); |
fe0a0419 AJ |
119 | |
120 | /* queue this validation request to be infored of the pending lookup results */ | |
bf929433 AJ |
121 | node->next = basic_auth->queue; |
122 | basic_auth->queue = node; | |
928f3421 AJ |
123 | return; |
124 | } | |
fe0a0419 AJ |
125 | // otherwise submit this request to the auth helper(s) for validation |
126 | ||
127 | /* mark this user as having verification in progress */ | |
128 | user()->credentials(Auth::Pending); | |
129 | char buf[HELPER_INPUT_BUFFER]; | |
9dca980d | 130 | static char usern[HELPER_INPUT_BUFFER]; |
fe0a0419 | 131 | static char pass[HELPER_INPUT_BUFFER]; |
7e851a3e SK |
132 | |
133 | xstrncpy(usern, rfc1738_escape(user()->username()), sizeof(usern)); | |
134 | xstrncpy(pass, rfc1738_escape(basic_auth->passwd), sizeof(pass)); | |
135 | ||
d4806c91 CT |
136 | int sz = 0; |
137 | if (const char *keyExtras = helperRequestKeyExtras(request, al)) | |
138 | sz = snprintf(buf, sizeof(buf), "%s %s %s\n", usern, pass, keyExtras); | |
139 | else | |
140 | sz = snprintf(buf, sizeof(buf), "%s %s\n", usern, pass); | |
141 | ||
fe0a0419 AJ |
142 | if (sz<=0) { |
143 | debugs(9, DBG_CRITICAL, "ERROR: Basic Authentication Failure. Can not build helper validation request."); | |
4c535e87 | 144 | handler(data); |
56946509 | 145 | } else if (static_cast<size_t>(sz) >= sizeof(buf)) { |
fe0a0419 | 146 | debugs(9, DBG_CRITICAL, "ERROR: Basic Authentication Failure. user:password exceeds " << sizeof(buf) << " bytes."); |
4c535e87 | 147 | handler(data); |
fe0a0419 | 148 | } else |
c7baff40 | 149 | helperSubmit(basicauthenticators, buf, Auth::Basic::UserRequest::HandleReply, |
fe0a0419 | 150 | new Auth::StateData(this, handler, data)); |
928f3421 AJ |
151 | } |
152 | ||
fe0a0419 | 153 | void |
24438ec5 | 154 | Auth::Basic::UserRequest::HandleReply(void *data, const Helper::Reply &reply) |
fe0a0419 AJ |
155 | { |
156 | Auth::StateData *r = static_cast<Auth::StateData *>(data); | |
fe0a0419 | 157 | void *cbdata; |
e166785a | 158 | debugs(29, 5, HERE << "reply=" << reply); |
fe0a0419 AJ |
159 | |
160 | assert(r->auth_user_request != NULL); | |
161 | assert(r->auth_user_request->user()->auth_type == Auth::AUTH_BASIC); | |
162 | ||
71e7400c AJ |
163 | // add new helper kv-pair notes to the credentials object |
164 | // so that any transaction using those credentials can access them | |
d665de37 A |
165 | static const NotePairs::Names appendables = { SBuf("group"), SBuf("tag") }; |
166 | r->auth_user_request->user()->notes.replaceOrAddOrAppend(&reply.notes, appendables); | |
71e7400c | 167 | |
fe0a0419 | 168 | /* this is okay since we only play with the Auth::Basic::User child fields below |
61beade2 | 169 | * and do not pass the pointer itself anywhere */ |
fe0a0419 AJ |
170 | Auth::Basic::User *basic_auth = dynamic_cast<Auth::Basic::User *>(r->auth_user_request->user().getRaw()); |
171 | ||
172 | assert(basic_auth != NULL); | |
173 | ||
2428ce02 | 174 | if (reply.result == Helper::Okay) |
fe0a0419 AJ |
175 | basic_auth->credentials(Auth::Ok); |
176 | else { | |
177 | basic_auth->credentials(Auth::Failed); | |
178 | ||
e166785a AJ |
179 | if (reply.other().hasContent()) |
180 | r->auth_user_request->setDenyMessage(reply.other().content()); | |
fe0a0419 AJ |
181 | } |
182 | ||
183 | basic_auth->expiretime = squid_curtime; | |
184 | ||
185 | if (cbdataReferenceValidDone(r->data, &cbdata)) | |
4c535e87 | 186 | r->handler(cbdata); |
fe0a0419 AJ |
187 | |
188 | cbdataReferenceDone(r->data); | |
189 | ||
bf929433 AJ |
190 | while (basic_auth->queue) { |
191 | if (cbdataReferenceValidDone(basic_auth->queue->data, &cbdata)) | |
192 | basic_auth->queue->handler(cbdata); | |
fe0a0419 | 193 | |
bf929433 AJ |
194 | Auth::QueueNode *tmpnode = basic_auth->queue->next; |
195 | basic_auth->queue->next = NULL; | |
196 | delete basic_auth->queue; | |
fe0a0419 | 197 | |
bf929433 | 198 | basic_auth->queue = tmpnode; |
fe0a0419 AJ |
199 | } |
200 | ||
201 | delete r; | |
202 | } | |
f53969cc | 203 |