UserRequest.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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 
9 #include "squid.h"
10 #include "auth/basic/Config.h"
11 #include "auth/basic/User.h"
12 #include "auth/basic/UserRequest.h"
13 #include "auth/QueueNode.h"
14 #include "auth/State.h"
15 #include "debug/Stream.h"
16 #include "format/Format.h"
17 #include "helper.h"
18 #include "helper/Reply.h"
19 #include "HttpRequest.h"
20 #include "MemBuf.h"
21 #include "rfc1738.h"
22 
23 #if !defined(HELPER_INPUT_BUFFER)
24 #define HELPER_INPUT_BUFFER 8192
25 #endif
26 
27 bool
28 Auth::Basic::UserRequest::authenticated() const
29 {
30  Auth::Basic::User const *basic_auth = dynamic_cast<Auth::Basic::User const *>(user().getRaw());
31 
32  if (basic_auth && basic_auth->authenticated())
33  return true;
34 
35  return false;
36 }
37 
38 const char *
39 Auth::Basic::UserRequest::credentialsStr()
40 {
41  Auth::Basic::User const *basic_auth = dynamic_cast<Auth::Basic::User const *>(user().getRaw());
42  if (basic_auth)
43  return basic_auth->passwd;
44  return nullptr;
45 }
46 
47 /* log a basic user in
48  */
49 void
51 {
52  assert(user() != nullptr);
53 
54  /* if the password is not ok, do an identity */
55  if (!user() || user()->credentials() != Auth::Ok)
56  return;
57 
58  /* are we about to recheck the credentials externally? */
59  if ((user()->expiretime + static_cast<Auth::Basic::Config*>(Auth::SchemeConfig::Find("basic"))->credentialsTTL) <= squid_curtime) {
60  debugs(29, 4, "credentials expired - rechecking");
61  return;
62  }
63 
64  /* we have been through the external helper, and the credentials haven't expired */
65  debugs(29, 9, "user '" << user()->username() << "' authenticated");
66 
67  /* Decode now takes care of finding the AuthUser struct in the cache */
68  /* after external auth occurs anyway */
69  user()->expiretime = current_time.tv_sec;
70 }
71 
73 Auth::Basic::UserRequest::module_direction()
74 {
75  /* null auth_user is checked for by Auth::UserRequest::direction() */
76  if (user()->auth_type != Auth::AUTH_BASIC)
77  return Auth::CRED_ERROR;
78 
79  switch (user()->credentials()) {
80 
81  case Auth::Unchecked:
82  case Auth::Pending:
83  return Auth::CRED_LOOKUP;
84 
85  case Auth::Ok:
86  if (user()->expiretime + static_cast<Auth::Basic::Config*>(Auth::SchemeConfig::Find("basic"))->credentialsTTL <= squid_curtime)
87  return Auth::CRED_LOOKUP;
88  return Auth::CRED_VALID;
89 
90  case Auth::Failed:
91  return Auth::CRED_VALID;
92 
93  default:
94  return Auth::CRED_ERROR;
95  }
96 }
97 
98 /* send the initial data to a basic authenticator module */
99 void
100 Auth::Basic::UserRequest::startHelperLookup(HttpRequest *request, AccessLogEntry::Pointer &al, AUTHCB * handler, void *data)
101 {
102  assert(user()->auth_type == Auth::AUTH_BASIC);
103  Auth::Basic::User *basic_auth = dynamic_cast<Auth::Basic::User *>(user().getRaw());
104  assert(basic_auth != nullptr);
105  debugs(29, 9, "'" << basic_auth->username() << ":" << basic_auth->passwd << "'");
106 
107  if (static_cast<Auth::Basic::Config*>(Auth::SchemeConfig::Find("basic"))->authenticateProgram == nullptr) {
108  debugs(29, DBG_CRITICAL, "ERROR: No Basic authentication program configured.");
109  handler(data);
110  return;
111  }
112 
113  /* check to see if the auth_user already has a request outstanding */
114  if (user()->credentials() == Auth::Pending) {
115  /* there is a request with the same credentials already being verified */
116 
117  Auth::QueueNode *node = new Auth::QueueNode(this, handler, data);
118 
119  /* queue this validation request to be infored of the pending lookup results */
120  node->next = basic_auth->queue;
121  basic_auth->queue = node;
122  return;
123  }
124  // otherwise submit this request to the auth helper(s) for validation
125 
126  /* mark this user as having verification in progress */
127  user()->credentials(Auth::Pending);
128  char buf[HELPER_INPUT_BUFFER];
129  static char usern[HELPER_INPUT_BUFFER];
130  static char pass[HELPER_INPUT_BUFFER];
131 
132  xstrncpy(usern, rfc1738_escape(user()->username()), sizeof(usern));
133  xstrncpy(pass, rfc1738_escape(basic_auth->passwd), sizeof(pass));
134 
135  int sz = 0;
136  if (const char *keyExtras = helperRequestKeyExtras(request, al))
137  sz = snprintf(buf, sizeof(buf), "%s %s %s\n", usern, pass, keyExtras);
138  else
139  sz = snprintf(buf, sizeof(buf), "%s %s\n", usern, pass);
140 
141  if (sz<=0) {
142  debugs(9, DBG_CRITICAL, "ERROR: Basic Authentication Failure. Can not build helper validation request.");
143  handler(data);
144  } else if (static_cast<size_t>(sz) >= sizeof(buf)) {
145  debugs(9, DBG_CRITICAL, "ERROR: Basic Authentication Failure. user:password exceeds " << sizeof(buf) << " bytes.");
146  handler(data);
147  } else
148  helperSubmit(basicauthenticators, buf, Auth::Basic::UserRequest::HandleReply,
149  new Auth::StateData(this, handler, data));
150 }
151 
152 void
153 Auth::Basic::UserRequest::HandleReply(void *data, const Helper::Reply &reply)
154 {
155  Auth::StateData *r = static_cast<Auth::StateData *>(data);
156  void *cbdata;
157  debugs(29, 5, "reply=" << reply);
158 
159  assert(r->auth_user_request != nullptr);
160  assert(r->auth_user_request->user()->auth_type == Auth::AUTH_BASIC);
161 
162  // add new helper kv-pair notes to the credentials object
163  // so that any transaction using those credentials can access them
164  static const NotePairs::Names appendables = { SBuf("group"), SBuf("tag") };
165  r->auth_user_request->user()->notes.replaceOrAddOrAppend(&reply.notes, appendables);
166 
167  /* this is okay since we only play with the Auth::Basic::User child fields below
168  * and do not 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 != nullptr);
172 
173  if (reply.result == Helper::Okay)
174  basic_auth->credentials(Auth::Ok);
175  else {
176  basic_auth->credentials(Auth::Failed);
177 
178  if (reply.other().hasContent())
180  }
181 
182  basic_auth->expiretime = squid_curtime;
183 
185  r->handler(cbdata);
186 
188 
189  while (basic_auth->queue) {
190  if (cbdataReferenceValidDone(basic_auth->queue->data, &cbdata))
191  basic_auth->queue->handler(cbdata);
192 
193  Auth::QueueNode *tmpnode = basic_auth->queue->next;
194  basic_auth->queue->next = nullptr;
195  delete basic_auth->queue;
196 
197  basic_auth->queue = tmpnode;
198  }
199 
200  delete r;
201 }
202 
Definition: parse.c:104
#define DBG_CRITICAL
Definition: Stream.h:37
#define cbdataReferenceValidDone(var, ptr)
Definition: cbdata.h:239
struct node * next
Definition: parse.c:105
void * data
Definition: State.h:38
AUTHCB * handler
Definition: State.h:40
bool hasContent() const
Definition: MemBuf.h:54
Definition: SBuf.h:93
static void authenticate(int socket_fd, const char *username, const char *passwd)
@ CRED_LOOKUP
Credentials need to be validated with the backend helper.
Definition: UserRequest.h:67
Definition: cbdata.cc:37
C * getRaw() const
Definition: RefCount.h:89
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
#define rfc1738_escape(x)
Definition: rfc1738.h:52
UserRequest::Pointer auth_user_request
Definition: State.h:39
void setDenyMessage(char const *)
Definition: UserRequest.cc:114
virtual User::Pointer user()
Definition: UserRequest.h:143
Direction
Definition: UserRequest.h:64
std::vector< SBuf > Names
Definition: Notes.h:206
static SchemeConfig * Find(const char *proxy_auth)
Definition: SchemeConfig.cc:59
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
Definition: gadgets.cc:18
const MemBuf & other() const
Definition: Reply.h:42
Helper::ResultCode result
The helper response 'result' field.
Definition: Reply.h:59
@ CRED_ERROR
ERROR in the auth module. Cannot determine the state of this request.
Definition: UserRequest.h:68
NotePairs notes
Definition: Reply.h:62
#define assert(EX)
Definition: assert.h:17
@ Okay
Definition: ResultCode.h:18
void helperSubmit(const Helper::Client::Pointer &hlp, const char *const buf, HLPCB *const callback, void *const data)
Definition: helper.cc:480
#define cbdataReferenceDone(var)
Definition: cbdata.h:357
time_t squid_curtime
Definition: stub_libtime.cc:20
@ AUTH_BASIC
Definition: Type.h:19
@ CRED_VALID
Credentials are valid and a up to date. The OK/Failed state is accurate.
Definition: UserRequest.h:66
#define HELPER_INPUT_BUFFER
Definition: UserRequest.cc:24
char * content()
start of the added data
Definition: MemBuf.h:41
static char credentials[MAX_USERNAME_LEN+MAX_DOMAIN_LEN+2]
Auth::QueueNode * next
Definition: QueueNode.h:54
void AUTHCB(void *)
Definition: UserRequest.h:57
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
class SquidConfig Config
Definition: SquidConfig.cc:12
Helper::ClientPointer basicauthenticators
Definition: Config.cc:39

 

Introduction

Documentation

Support

Miscellaneous