perl-modperl mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From André Warnier>
Subject Re: requests and sub-requests
Date Sun, 12 Oct 2008 17:09:58 GMT

Many thanks for the excellent information, I will ponder that.

More below, but one more question here :
Where does $r->internal_redirect "live" (in which package) ?
I am having trouble finding it.

Torsten Foertsch wrote:
> On Sun 12 Oct 2008, André Warnier wrote:
>> In an attempt at being clever, I put the following code in the
>> handler :
>>      unless ($r->is_initial_req) {
>>          if (defined $r->prev) {
>>              # we are in a subrequest.  Just copy user from main
>> request. $r->user( $r->prev->user );
>>          }
>>          # Also disable authorization phase
>>          $r->set_handlers(PerlAuthzHandler => undef);
>>          return OK;
>>      }
> You have to distinguish between subrequests and internal redirects. The 
> former result from $r->lookup_uri, $r->lookup_file or similar (there 
> are a few more such functions in the C API) and internal redirects that 
> result from $r->internal_redirect (internal_fast_redirect() is not as 
> the name suggests an internal redirect but simply overrides the current 
> request). Subrequests are used for example by mod_rewrite, mod_include, 
> mod_negotiation to look for some characteristics of a document and 
> perhaps pull it in (run() it). Internal redirects are used in mod_cgi 
> when the CGI output indicates a status 200 (HTTP_OK) but also contains 
> a Location header. But the main usage of internal redirects is the 
> ErrorDocument.
> Now, is_initial_req() checks if the current $r is the result of a 
> subrequest or the result of a internal redirect and returns false if 
> so. prev() returns the parent request if the current $r is the result 
> of an internal redirect and main() returns the main request if the 
> current $r is a subrequest. So, your code checks only for internal 
> redirects (ErrorDocument).
> Now, have a look at httpd-2.x.y/server/request.c around line 170. You'll 
> see this piece of code:
>     /* Skip authn/authz if the parent or prior request passed the
>      * authn/authz,
>      * and that configuration didn't change (this requires
>      * optimized _walk()
>      * functions in map_to_storage that use the same merge results given
>      * identical input.)  If the config changes, we must re-auth.
>      */
>     if (r->main && (r->main->per_dir_config == r->per_dir_config))
>         r->user = r->main->user;
>         r->ap_auth_type = r->main->ap_auth_type;
>     }
>     else if (r->prev && (r->prev->per_dir_config == r->per_dir_config))

> {
>         r->user = r->prev->user;
>         r->ap_auth_type = r->prev->ap_auth_type;
>     }
>     else {
>         switch (ap_satisfies(r)) {
>         case SATISFY_ALL:
>         case SATISFY_NOSPEC:
>             if ((access_status = ap_run_access_checker(r)) != 0) {
>                 return decl_die(access_status, "check access", r);
>     ...
Ok, I get it.

I have a little question related to the above, but not very urgent : why 
  the check on the configuration change ? what can change between a 
request and a sub-request (or internal redirect) ?

> You see, you are not the first who had had the idea of reusing an 
> established identity. 
I did not think I would be.

If your subreq or internal redirect hits the same
> Location or Directory container the AAA phases are completely skipped.
> Maybe this is enough optimization if you shift a few directives around 
> in your httpd.conf.
I don't think so, because this is a really specific authentication 
method, for a special case.
And I don't think that Apache will skip the mod_perl AAA phases, will it ?

> If not, the code above shows you how to do it. But you must ask yourself 
> if it really is valid to reuse the identity. I believe, you can safely 
> inherit the identity from $r->main or $r->prev but you must not skip 
> the other 2 A's. If you can't it would mean you have one realm of 
> identities for the main request and another for the subreq. That, I'd 
> say, is a configuration error.
As a first stage of the AAA, for some Locations, there is a filtering on 
the remote IP of the caller.  Some IP's get an "automatic" user-id, 
which can vary according to the IP. In some cases, this is authoritative 
(no access unless you have the right IP), in some cases not (you get a 
second chance).  Some Locations don't have the IP filter, they always 
get the second chance below.  This IP filter is implemented as a 
PerlAccessHandler. This is the main reason for trying to optimise, 
because it is expensive : the IP of the caller must be compared to 
several ranges of IP, not necessarily matching regular subnets.

The second step is a PerlAuthenHandler, which can re-direct to a login 
Then there is a PerlAuthenzHandler to check if this user is allowed to 
access that resource.
It also combines with SSO, with some URL rewriting, and with trying to 
control access to a Tomcat application behind the Apache.

The back-end for the authentication is a special DB system, whose access 
for that is rather heavy, but required.
On the positive side, this is for a limited range of well-known 
applications, for a limited public and for a reasonable number of 
expected transactions/s.
So I am trying to wring out the optimisations I can, without going too far.
I started this module wanting to keep it "clean and lean and mean", but 
as I discover more and more twists, it is getting to look like the 
classical spaghetti bowl..

I am also, but on a separate thread, looking at tying this AAA stuff to 
the $r->connection (with notes()).

I'm also having fun doing this, it's interesting.

>> The idea being that if we are in a sub-request, there is no point in
>> authenticating/authorizing it again, since the main request should
>> already do that, right ?  Optimisation..
>> Now the above works very nicely, except in the case where, before
>> this handler gets called, there is an intervention by mod_rewrite. It
>> seems as if mod_rewrite makes the above fail, even when the rewrite
>> condition does not apply and the URL is considered as a
>> "pass-through".
>> I suspect that it is because mod_rewrite, no matter what, invoques
>> the original (or modified) URL as a sub-request of the original
>> request. This would cause the above to fail, because in such a case,
>> the above conditional code would be invoked, but there is no
>> $r->prev->user to be copied.
> mod_rewrite doesn't make subrequests if not asked to. I know only of 2 
> ways to have mod_rewrite perform a subreq: %{LA-U:variable} 
> and %{LA-F:variable} in a RewriteCond.

This :
may be missing ".. or an internal redirect" in a couple of places.

View raw message