On Mon 13 Oct 2008, André Warnier wrote:
> As explained the other thread (requests and subrequests), I thought
> it was more elegant and mod_perl-ish, instead of doing a re-direct to
> a login page if the user needed authentifying, to having the login
> page returned by a content handler.

The apache-way to do this has a name: ErrorDocument or in mod_perl 
$r->custom_response. Configure an ErrorDocument for 403 and return 
HTTP_FORBIDDEN in your A...Handler. That has the benefit that the 403 
status is logged and that the browser (think about search engines) sees 
it. But the custom response page must be larger than 512 bytes or 
you'll encounter problems with IE. If you don't care about that you can 
use $r->internal_redirect. That is a bit less work to do for your 
server.

> > Please, have a look again at the ap_process_request_internal()
> > function in httpd-2.x.y/server/request.c.
>
> I would first have to know where this thing is.  I have never so far
> looked at the Apache source code, so I need some pointers there.
> Not that if I look, I would necessarily understand much of it, but I
> can try.
> Now, why would I, since you provide the nice explanation below ?

Out of curiosity! Just download the apache source untar it and open in 
in your favorite editor. C is not that much different from perl and the 
request.c file is really easy to read. You don't have to modify it, 
just try to understand what is going on!

> So, you mean that for every and each request, Apache re-configures
> itself ?  If that is so, it is quite amazing the speed at which it
> can serve a page..

Just keep in mind for the following that apache is originally designed 
to have a static configuration. So at start it splits the configuration 
into blocks, one holds the basic config that is outside all containers 
and others for each Location/Directory/etc. From those blocks it 
generates pre-parsed configuration vectors. At runtime each request 
starts with the basic config fetched from r->server->lookup_defaults 
then it looks for other vectors matching the request and merges them.

But there is another configuration source, .htaccess. Those are read in, 
compiled and merged in the same function (ap_directory_walk() (hard to 
understand)) that applies Directory containers (called from 
ap_run_map_to_storage()).

With mod_perl comes yet another configuration source, $r->add_config. 
This is implemented very similar to .htaccess only the directives are 
not read from a file but from memory and they are compiled and merged 
at the time $r->add_config is called.

> Well, I am not sure :
> The handler set in the configuration file for that Location, is
> originally "jakarta-servlet" (as per the snippet below).
> It is I, in my PerlAuthenHandler, who is trying to reset this to
> "modperl", and in mod_perl, to my send_login_page() method.
> Before I do that, there is no $r->handler nor PerlResponseHandler
> set.

So, why not issue a $r->internal_redirect. I don't exactly know when the 
SetHandler directive sets $r->handler. Maybe it is done in the type 
checker phase. So perhaps you have to move your code to Fixup or use 
$r->add_config(['SetHandler modperl']).

> I don't think I can do that, unless I want the PerlTypeHandler or
> PerlFixupHandler to become an authentication handler.  That would
> probably for one upset Adam, for two be kind of funky, no ?

Why not?

    if( $override_handler ) {
      $r->push_handlers( PerlFixupHandler=>__PACKAGE__.'::fixup' );
      $r->pnotes->{override_handler}='modperl';
    }
...
sub fixup {
  $_[0]->handler($_[0]->pnotes->{override_handler};
  return Apache2::Const::OK;
}

> Now, in summary :
> This is a very specialised authentication module, meant to be used in
> very specific circumstances and not for general usage.  I control the
> environment, so I can pretty much do what I want as long as it does
> not crash the system or present some big security hole or the like.
>
> In my case, that <Location> containing the
> sethandler jakarta-servlet
> is pretty much unique: it is not a sub- or super-location of anything
> else, and it fulfills only one very narrow purpose.
> To my knowledge, there will be no other module playing a role there,
> other than the jakarta-servlet initial handler, plus whatever I
> decide to put in there as mod_perl modules and methods.
> This for the entire duration of one request.
>
> Now, assuming I have no other stuff in there than the following lines
> <LocationMatch "/servlet.xyz$">
>     SetHandler jakarta-servlet
>     SetEnvIf REQUEST_URI "\.(htm|web|css|gif|jpg|js|html?)$" no-jk
>
>     AuthType MyModule
>     AuthName MyXyzApp
>     PerlSetVar MyModule_var1 "value"
>     PerlAccessHandler My::Module->some_access_method
>     PerlAuthenHandler My::Module->some_auth_method
>     PerlAuthzHandler My::Module->some_authz_method
>     require valid-user
>
> </Location>
>
> then, if I understand correctly what you write above, since I have no
> PerlTransHandler, nor Fixup, etc..  I should be able to do the same
> in the PerlAuthenHandler, is it no so ?
> Or am I still confused about the order in which things happen ?

I think I am confused a bit here.

> Or, a thought that just occurred to me, is the solution for me
> (stopping jakarta-servlet from running and running my
> PerlresponseHandler instead), as easy as setting the "no-jk" variable
> (if I can do that within my PerlAuthenHandler, and how) ?

I was tempted to suggest that. But I don't know nothing about jakarta. 
If you want to try use $r->subprocess_env->{'no-jk'}=1;

> Or, another thought that just occurred : can I comment out the
> "SetHandler jakarta-servlet" originally, set my PerlresponseHandler
> as the default handler in the <Location>, and then *if the user is
> authenticated* (the contrary of my current condition), *set* the
> content handler to be jakarta-servlet instead of modperl ?

Of course.

I think the best solution is the ErrorDocument or custom_response. The 
second best is the internal_redirect. Both need a way to address you 
login form by an URI.

<Location /login>
SetHandler modperl
PerlResponseHandler My::LoginForm
</Location>
<Perl>
package My::LoginForm;
sub handler {
  my ($r)[EMAIL PROTECTED];
  my $original_req=$r->prev;
  unless( $original_req ) {
    $r->log_reason("/login is to be called as internal redirect");
    return Apache2::Const::SERVER_ERROR;
  }
  my $original_pnotes=$original_req->pnotes;
  ...
  return Apache2::Const::OK;
}
</Perl>
ErrorDocument 403 /login


Torsten

--
Need professional mod_perl support?
Just hire me: [EMAIL PROTECTED]

Reply via email to