external ACL soemtimes cannot find the credentials in ACL Checklist even
if they are attached to the HTTPRequest object.
This seems to happen when the checklist is created and the line match
started before the credentials are known.
Unless someone knows of a better place to duplicate the credentials
reference from request to checklist. I would like to apply this patch to:
* locate the %LOGIN value from either place where credentials can be
found,
* updates the checklist if it was unset,
* passes '-' to the helper if no credentials at all were given.
Although the earlier logics forcing a lookup means this '-' case should
not happen.
Amos
--
Please be using
Current Stable Squid 2.7.STABLE9 or 3.1.16
Beta testers wanted for 3.2.0.13
=== modified file 'src/external_acl.cc'
--- src/external_acl.cc 2011-10-10 03:28:26 +0000
+++ src/external_acl.cc 2011-10-25 05:03:11 +0000
@@ -746,88 +746,109 @@
static allow_t
aclMatchExternal(external_acl_data *acl, ACLFilledChecklist *ch)
{
const char *key = "";
debugs(82, 9, HERE << "acl=\"" << acl->def->name << "\"");
external_acl_entry *entry = ch->extacl_entry;
if (entry) {
if (cbdataReferenceValid(entry) && entry->def == acl->def) {
/* Ours, use it.. */
} else {
/* Not valid, or not ours.. get rid of it */
debugs(82, 9, HERE << "entry " << entry << " not valid or not ours. Discarded.");
if (entry) {
debugs(82, 9, HERE << "entry def=" << entry->def << ", our def=" << acl->def);
key = makeExternalAclKey(ch, acl);
debugs(82, 9, HERE << "entry key='" << (char *)entry->key << "', our key='" << key << "'");
}
cbdataReferenceDone(ch->extacl_entry);
entry = NULL;
}
}
external_acl_message = "MISSING REQUIRED INFORMATION";
if (!entry) {
debugs(82, 9, HERE << "No helper entry available");
#if USE_AUTH
if (acl->def->require_auth) {
- int ti = AuthenticateAcl(ch);
/* Make sure the user is authenticated */
debugs(82, 3, HERE << acl->def->name << " check user authenticated.");
- if (ti != 1) {
+ allow_t ti = AuthenticateAcl(ch);
+ switch(ti)
+ {
+ case ACCESS_ALLOWED:
+ case ACCESS_AUTH_EXPIRED_OK:
+ // we have credentials. Trust them.
+ debugs(82, 3, HERE << acl->def->name << " user has okay authentication credentials.");
+ break;
+
+ case ACCESS_DENIED:
+ case ACCESS_AUTH_EXPIRED_BAD:
+ // XXX: should we re-challenge instead?
+ debugs(82, 3, HERE << acl->def->name << " user has failed authentication credentials.");
+ case ACCESS_DUNNO: // need to wait for a full answer.
+ // XXX: what will happen though?
+ // AuthenticateAcl() might schedule a lookup on the given credentials
+ // but what schedules a re-check of this ACL test after they come back?
+ return ti;
+
+ case ACCESS_AUTH_REQUIRED:
+ // XXX: why is this so important?
+ debugs(82, 1, "WARNING: " << acl->def->name <<
+ " user authentication failure (" << ti << ", ch=" << ch << ")");
debugs(82, 2, HERE << acl->def->name << " user not authenticated (" << ti << ")");
return ACCESS_AUTH_REQUIRED;
}
debugs(82, 3, HERE << acl->def->name << " user is authenticated.");
}
#endif
key = makeExternalAclKey(ch, acl);
if (!key) {
/* Not sufficient data to process */
return ACCESS_DUNNO;
}
entry = static_cast<external_acl_entry *>(hash_lookup(acl->def->cache, key));
if (!entry || external_acl_grace_expired(acl->def, entry)) {
debugs(82, 2, HERE << acl->def->name << "(\"" << key << "\") = lookup needed");
debugs(82, 2, HERE << "\"" << key << "\": entry=@" <<
entry << ", age=" << (entry ? (long int) squid_curtime - entry->date : 0));
if (acl->def->theHelper->stats.queue_size <= (int)acl->def->theHelper->childs.n_active) {
debugs(82, 2, HERE << "\"" << key << "\": queueing a call.");
ch->changeState(ExternalACLLookup::Instance());
- debugs(82, 2, HERE << "\"" << key << "\": return -1.");
+ debugs(82, 2, HERE << "\"" << key << "\": return " << ACCESS_DUNNO);
return ACCESS_DUNNO; // to get here we have to have an expired cache entry. MUST not use.
} else {
if (!entry) {
debugs(82, DBG_IMPORTANT, "WARNING: external ACL '" << acl->def->name <<
"' queue overload. Request rejected '" << key << "'.");
external_acl_message = "SYSTEM TOO BUSY, TRY AGAIN LATER";
return ACCESS_DUNNO;
} else {
debugs(82, DBG_IMPORTANT, "WARNING: external ACL '" << acl->def->name <<
"' queue overload. Using stale result. '" << key << "'.");
/* Fall thru to processing below */
}
}
}
}
external_acl_cache_touch(acl->def, entry);
external_acl_message = entry->message.termedBuf();
debugs(82, 2, HERE << acl->def->name << " = " << entry->result);
if (ch->request) {
#if USE_AUTH
if (entry->user.size())
ch->request->extacl_user = entry->user;
if (entry->password.size())
ch->request->extacl_passwd = entry->password;
#endif
if (!ch->request->tag.size())
@@ -1331,71 +1352,83 @@
do {
void *cbdata;
cbdataReferenceDone(state->def);
if (state->callback && cbdataReferenceValidDone(state->callback_data, &cbdata))
state->callback(cbdata, entry);
next = state->queue;
cbdataFree(state);
state = next;
} while (state);
}
void
ACLExternal::ExternalAclLookup(ACLChecklist *checklist, ACLExternal * me, EAH * callback, void *callback_data)
{
MemBuf buf;
external_acl_data *acl = me->data;
external_acl *def = acl->def;
externalAclState *state;
dlink_node *node;
externalAclState *oldstate = NULL;
bool graceful = 0;
ACLFilledChecklist *ch = Filled(checklist);
#if USE_AUTH
if (acl->def->require_auth) {
- int ti;
/* Make sure the user is authenticated */
debugs(82, 3, HERE << acl->def->name << " check user authenticated.");
- if ((ti = AuthenticateAcl(ch)) != 1) {
+ allow_t ti = AuthenticateAcl(ch);
+ switch(ti)
+ {
+ case ACCESS_ALLOWED:
+ case ACCESS_AUTH_EXPIRED_OK:
+ // we have credentials. Trust them?
+ debugs(82, 3, HERE << acl->def->name << " user has okay authentication credentials.");
+ break;
+ case ACCESS_DENIED:
+ case ACCESS_AUTH_EXPIRED_BAD:
+ // we have credentials. Trust them?
+ debugs(82, 3, HERE << acl->def->name << " user has failed authentication credentials.");
+ break;
+ case ACCESS_DUNNO:
+ case ACCESS_AUTH_REQUIRED:
debugs(82, DBG_IMPORTANT, "WARNING: " << acl->def->name <<
" user authentication failure (" << ti << ", ch=" << ch << ")");
callback(callback_data, NULL);
return;
}
- debugs(82, 3, HERE << acl->def->name << " user is authenticated.");
}
#endif
const char *key = makeExternalAclKey(ch, acl);
if (!key) {
debugs(82, 1, "externalAclLookup: lookup in '" << def->name <<
"', prerequisit failure (ch=" << ch << ")");
callback(callback_data, NULL);
return;
}
debugs(82, 2, "externalAclLookup: lookup in '" << def->name << "' for '" << key << "'");
external_acl_entry *entry = static_cast<external_acl_entry *>(hash_lookup(def->cache, key));
if (entry && external_acl_entry_expired(def, entry))
entry = NULL;
/* Check for a pending lookup to hook into */
// only possible if we are caching results.
if (def->cache_size > 0) {
for (node = def->queue.head; node; node = node->next) {
externalAclState *oldstatetmp = static_cast<externalAclState *>(node->data);
if (strcmp(key, oldstatetmp->key) == 0) {
oldstate = oldstatetmp;
break;
}
}