4 #include "ConfigParser.h"
5 #include "HttpRequest.h"
7 #include "acl/FilledChecklist.h"
8 #include "adaptation/Service.h"
9 #include "adaptation/ServiceGroups.h"
10 #include "adaptation/AccessRule.h"
11 #include "adaptation/Config.h"
12 #include "adaptation/AccessCheck.h"
15 /** \cond AUTODOCS-IGNORE */
16 cbdata_type
Adaptation::AccessCheck::CBDATA_AccessCheck
= CBDATA_UNKNOWN
;
20 Adaptation::AccessCheck::Start(Method method
, VectPoint vp
,
21 HttpRequest
*req
, HttpReply
*rep
, AccessCheckCallback
*cb
, void *cbdata
)
24 if (Config::Enabled
) {
25 // the new check will call the callback and delete self, eventually
26 return AsyncStart(new AccessCheck(
27 ServiceFilter(method
, vp
, req
, rep
), cb
, cbdata
));
30 debugs(83, 3, HERE
<< "adaptation off, skipping");
34 Adaptation::AccessCheck::AccessCheck(const ServiceFilter
&aFilter
,
35 AccessCheckCallback
*aCallback
,
37 AsyncJob("AccessCheck"), filter(aFilter
),
39 callback_data(cbdataReference(aCallbackData
)),
43 Adaptation::Icap::History::Pointer h
= filter
.request
->icapHistory();
48 debugs(93, 5, HERE
<< "AccessCheck constructed for " <<
49 methodStr(filter
.method
) << " " << vectPointStr(filter
.point
));
52 Adaptation::AccessCheck::~AccessCheck()
55 Adaptation::Icap::History::Pointer h
= filter
.request
->icapHistory();
60 cbdataReferenceDone(callback_data
);
64 Adaptation::AccessCheck::start()
70 /// Walk the access rules list to find rules with applicable service groups
72 Adaptation::AccessCheck::check()
74 debugs(93, 4, HERE
<< "start checking");
76 typedef AccessRules::iterator ARI
;
77 for (ARI i
= AllRules().begin(); i
!= AllRules().end(); ++i
) {
79 if (isCandidate(*r
)) {
80 debugs(93, 5, HERE
<< "check: rule '" << r
->id
<< "' is a candidate");
88 // XXX: Here and everywhere we call FindRule(topCandidate()):
89 // Once we identified the candidate, we should not just ignore it
90 // if reconfigure changes rules. We should either lock the rule to
91 // prevent reconfigure from stealing it or restart the check with
92 // new rules. Throwing an exception may also be appropriate.
94 Adaptation::AccessCheck::checkCandidates()
96 debugs(93, 4, HERE
<< "has " << candidates
.size() << " rules");
98 while (!candidates
.empty()) {
99 if (AccessRule
*r
= FindRule(topCandidate())) {
100 /* BUG 2526: what to do when r->acl is empty?? */
101 // XXX: we do not have access to conn->rfc931 here.
102 acl_checklist
= new ACLFilledChecklist(r
->acl
, filter
.request
, dash_str
);
103 acl_checklist
->reply
= filter
.reply
? HTTPMSGLOCK(filter
.reply
) : NULL
;
104 acl_checklist
->nonBlockingCheck(AccessCheckCallbackWrapper
, this);
108 candidates
.shift(); // the rule apparently went away (reconfigure)
111 debugs(93, 4, HERE
<< "NO candidates left");
117 Adaptation::AccessCheck::AccessCheckCallbackWrapper(int answer
, void *data
)
119 debugs(93, 8, HERE
<< "callback answer=" << answer
);
120 AccessCheck
*ac
= (AccessCheck
*)data
;
122 /** \todo AYJ 2008-06-12: If answer == ACCESS_REQ_PROXY_AUTH
123 * we should be kicking off an authentication before continuing
124 * with this request. see bug 2400 for details.
126 ac
->noteAnswer(answer
==ACCESS_ALLOWED
);
129 /// process the results of the ACL check
131 Adaptation::AccessCheck::noteAnswer(int answer
)
133 Must(!candidates
.empty()); // the candidate we were checking must be there
134 debugs(93,5, HERE
<< topCandidate() << " answer=" << answer
);
136 if (answer
) { // the rule matched
137 ServiceGroupPointer g
= topGroup();
138 if (g
!= NULL
) { // the corresponding group found
145 // no match or the group disappeared during reconfiguration
150 /// call back with a possibly nil group; the job ends here because all failures
151 /// at this point are fatal to the access check process
153 Adaptation::AccessCheck::callBack(const ServiceGroupPointer
&g
)
155 debugs(93,3, HERE
<< g
);
157 void *validated_cbdata
;
158 if (cbdataReferenceValidDone(callback_data
, &validated_cbdata
)) {
159 callback(g
, validated_cbdata
);
161 mustStop("done"); // called back or will never be able to call back
164 Adaptation::ServiceGroupPointer
165 Adaptation::AccessCheck::topGroup() const
167 ServiceGroupPointer g
;
168 if (candidates
.size()) {
169 if (AccessRule
*r
= FindRule(topCandidate())) {
170 g
= FindGroup(r
->groupId
);
171 debugs(93,5, HERE
<< "top group for " << r
->id
<< " is " << g
);
173 debugs(93,5, HERE
<< "no rule for " << topCandidate());
176 debugs(93,5, HERE
<< "no candidates"); // should not happen
182 /** Returns true iff the rule's service group will be used after ACL matches.
183 Used to detect rules worth ACl-checking. */
185 Adaptation::AccessCheck::isCandidate(AccessRule
&r
)
187 debugs(93,7,HERE
<< "checking candidacy of " << r
.id
<< ", group " <<
190 ServiceGroupPointer g
= FindGroup(r
.groupId
);
193 debugs(93,7,HERE
<< "lost " << r
.groupId
<< " group in rule" << r
.id
);
197 const bool wants
= g
->wants(filter
);
198 debugs(93,7,HERE
<< r
.groupId
<< (wants
? " wants" : " ignores"));