]>
Commit | Line | Data |
---|---|---|
f7f3304a | 1 | #include "squid.h" |
928f3421 | 2 | #include "auth/basic/auth_basic.h" |
aa110616 | 3 | #include "auth/basic/User.h" |
616cfc4c | 4 | #include "auth/basic/UserRequest.h" |
bf929433 | 5 | #include "auth/QueueNode.h" |
fe0a0419 AJ |
6 | #include "auth/State.h" |
7 | #include "charset.h" | |
582c2af2 | 8 | #include "Debug.h" |
86c63190 | 9 | #include "format/Format.h" |
e166785a | 10 | #include "HelperReply.h" |
d4806c91 CT |
11 | #include "HttpMsg.h" |
12 | #include "HttpRequest.h" | |
d4806c91 | 13 | #include "MemBuf.h" |
fe0a0419 | 14 | #include "rfc1738.h" |
616cfc4c | 15 | #include "SquidTime.h" |
928f3421 | 16 | |
fe0a0419 AJ |
17 | #if !defined(HELPER_INPUT_BUFFER) |
18 | #define HELPER_INPUT_BUFFER 8192 | |
19 | #endif | |
20 | ||
928f3421 | 21 | int |
c7baff40 | 22 | Auth::Basic::UserRequest::authenticated() const |
928f3421 | 23 | { |
aa110616 | 24 | Auth::Basic::User const *basic_auth = dynamic_cast<Auth::Basic::User const *>(user().getRaw()); |
928f3421 AJ |
25 | |
26 | if (basic_auth && basic_auth->authenticated()) | |
27 | return 1; | |
28 | ||
29 | return 0; | |
30 | } | |
31 | ||
d4806c91 CT |
32 | const char * |
33 | Auth::Basic::UserRequest::credentialsStr() | |
34 | { | |
35 | Auth::Basic::User const *basic_auth = dynamic_cast<Auth::Basic::User const *>(user().getRaw()); | |
36 | if (basic_auth) | |
37 | return basic_auth->passwd; | |
38 | return NULL; | |
39 | } | |
40 | ||
928f3421 AJ |
41 | /* log a basic user in |
42 | */ | |
43 | void | |
c7baff40 | 44 | Auth::Basic::UserRequest::authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type) |
928f3421 AJ |
45 | { |
46 | assert(user() != NULL); | |
47 | ||
928f3421 | 48 | /* if the password is not ok, do an identity */ |
d87154ee | 49 | if (!user() || user()->credentials() != Auth::Ok) |
928f3421 AJ |
50 | return; |
51 | ||
52 | /* are we about to recheck the credentials externally? */ | |
372fccd6 | 53 | if ((user()->expiretime + static_cast<Auth::Basic::Config*>(Auth::Config::Find("basic"))->credentialsTTL) <= squid_curtime) { |
d232141d | 54 | debugs(29, 4, HERE << "credentials expired - rechecking"); |
928f3421 AJ |
55 | return; |
56 | } | |
57 | ||
58 | /* we have been through the external helper, and the credentials haven't expired */ | |
d232141d | 59 | debugs(29, 9, HERE << "user '" << user()->username() << "' authenticated"); |
928f3421 AJ |
60 | |
61 | /* Decode now takes care of finding the AuthUser struct in the cache */ | |
62 | /* after external auth occurs anyway */ | |
d232141d | 63 | user()->expiretime = current_time.tv_sec; |
928f3421 AJ |
64 | |
65 | return; | |
66 | } | |
67 | ||
51a3dd58 | 68 | Auth::Direction |
c7baff40 | 69 | Auth::Basic::UserRequest::module_direction() |
928f3421 | 70 | { |
c7baff40 | 71 | /* null auth_user is checked for by Auth::UserRequest::direction() */ |
616cfc4c | 72 | if (user()->auth_type != Auth::AUTH_BASIC) |
51a3dd58 | 73 | return Auth::CRED_ERROR; |
928f3421 | 74 | |
d232141d | 75 | switch (user()->credentials()) { |
928f3421 | 76 | |
d87154ee AJ |
77 | case Auth::Unchecked: |
78 | case Auth::Pending: | |
51a3dd58 | 79 | return Auth::CRED_LOOKUP; |
928f3421 | 80 | |
d87154ee | 81 | case Auth::Ok: |
372fccd6 | 82 | if (user()->expiretime + static_cast<Auth::Basic::Config*>(Auth::Config::Find("basic"))->credentialsTTL <= squid_curtime) |
51a3dd58 AJ |
83 | return Auth::CRED_LOOKUP; |
84 | return Auth::CRED_VALID; | |
928f3421 | 85 | |
d87154ee | 86 | case Auth::Failed: |
51a3dd58 | 87 | return Auth::CRED_VALID; |
928f3421 | 88 | |
d232141d | 89 | default: |
51a3dd58 | 90 | return Auth::CRED_ERROR; |
d232141d | 91 | } |
928f3421 AJ |
92 | } |
93 | ||
94 | /* send the initial data to a basic authenticator module */ | |
95 | void | |
d4806c91 | 96 | Auth::Basic::UserRequest::module_start(HttpRequest *request, AccessLogEntry::Pointer &al, AUTHCB * handler, void *data) |
928f3421 | 97 | { |
616cfc4c | 98 | assert(user()->auth_type == Auth::AUTH_BASIC); |
aa110616 | 99 | Auth::Basic::User *basic_auth = dynamic_cast<Auth::Basic::User *>(user().getRaw()); |
928f3421 AJ |
100 | assert(basic_auth != NULL); |
101 | debugs(29, 9, HERE << "'" << basic_auth->username() << ":" << basic_auth->passwd << "'"); | |
102 | ||
372fccd6 | 103 | if (static_cast<Auth::Basic::Config*>(Auth::Config::Find("basic"))->authenticateProgram == NULL) { |
d232141d | 104 | debugs(29, DBG_CRITICAL, "ERROR: No Basic authentication program configured."); |
4c535e87 | 105 | handler(data); |
928f3421 AJ |
106 | return; |
107 | } | |
108 | ||
109 | /* check to see if the auth_user already has a request outstanding */ | |
d87154ee | 110 | if (user()->credentials() == Auth::Pending) { |
928f3421 | 111 | /* there is a request with the same credentials already being verified */ |
fe0a0419 | 112 | |
bf929433 | 113 | Auth::QueueNode *node = new Auth::QueueNode(this, handler, data); |
fe0a0419 AJ |
114 | |
115 | /* queue this validation request to be infored of the pending lookup results */ | |
bf929433 AJ |
116 | node->next = basic_auth->queue; |
117 | basic_auth->queue = node; | |
928f3421 AJ |
118 | return; |
119 | } | |
fe0a0419 AJ |
120 | // otherwise submit this request to the auth helper(s) for validation |
121 | ||
122 | /* mark this user as having verification in progress */ | |
123 | user()->credentials(Auth::Pending); | |
124 | char buf[HELPER_INPUT_BUFFER]; | |
9dca980d | 125 | static char usern[HELPER_INPUT_BUFFER]; |
fe0a0419 AJ |
126 | static char pass[HELPER_INPUT_BUFFER]; |
127 | if (static_cast<Auth::Basic::Config*>(user()->config)->utf8) { | |
9dca980d | 128 | latin1_to_utf8(usern, sizeof(usern), user()->username()); |
fe0a0419 | 129 | latin1_to_utf8(pass, sizeof(pass), basic_auth->passwd); |
9dca980d | 130 | xstrncpy(usern, rfc1738_escape(usern), sizeof(usern)); |
fe0a0419 AJ |
131 | xstrncpy(pass, rfc1738_escape(pass), sizeof(pass)); |
132 | } else { | |
9dca980d | 133 | xstrncpy(usern, rfc1738_escape(user()->username()), sizeof(usern)); |
fe0a0419 AJ |
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 |
e166785a | 154 | Auth::Basic::UserRequest::HandleReply(void *data, const HelperReply &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 | |
165 | r->auth_user_request->user()->notes.appendNewOnly(&reply.notes); | |
166 | ||
fe0a0419 AJ |
167 | /* this is okay since we only play with the Auth::Basic::User child fields below |
168 | * and dont pass the pointer itself anywhere */ | |
169 | Auth::Basic::User *basic_auth = dynamic_cast<Auth::Basic::User *>(r->auth_user_request->user().getRaw()); | |
170 | ||
171 | assert(basic_auth != NULL); | |
172 | ||
e166785a | 173 | if (reply.result == HelperReply::Okay) |
fe0a0419 AJ |
174 | basic_auth->credentials(Auth::Ok); |
175 | else { | |
176 | basic_auth->credentials(Auth::Failed); | |
177 | ||
e166785a AJ |
178 | if (reply.other().hasContent()) |
179 | r->auth_user_request->setDenyMessage(reply.other().content()); | |
fe0a0419 AJ |
180 | } |
181 | ||
182 | basic_auth->expiretime = squid_curtime; | |
183 | ||
184 | if (cbdataReferenceValidDone(r->data, &cbdata)) | |
4c535e87 | 185 | r->handler(cbdata); |
fe0a0419 AJ |
186 | |
187 | cbdataReferenceDone(r->data); | |
188 | ||
bf929433 AJ |
189 | while (basic_auth->queue) { |
190 | if (cbdataReferenceValidDone(basic_auth->queue->data, &cbdata)) | |
191 | basic_auth->queue->handler(cbdata); | |
fe0a0419 | 192 | |
bf929433 AJ |
193 | Auth::QueueNode *tmpnode = basic_auth->queue->next; |
194 | basic_auth->queue->next = NULL; | |
195 | delete basic_auth->queue; | |
fe0a0419 | 196 | |
bf929433 | 197 | basic_auth->queue = tmpnode; |
fe0a0419 AJ |
198 | } |
199 | ||
200 | delete r; | |
201 | } |