sethandlers question

sethandlers question

am 12.10.2008 19:28:18 von aw

Hi.

Still around a new perl AAA module I'm writing, a question :

If I have a Location like so :



SetHandler jakarta-servlet
SetEnvIf REQUEST_URI "\.(htm|web|css|gif|jpg|js|html?)$" no-jk

PerlXXXHandler My::Module->some_method

...



("jakarta-servlet" above means mod_jk --> Tomcat)
(and PerlXXXHandler being any kind of Perl HTTP Handler running soon enough)

The Question :
Is it possible, in the PerlXXXHandler, on a request-by-request base, to
"disable" the jakarta-servlet handler, and install the following instead

SetHandler modperl
PerlResponseHandler My::Module->some_other_method

?

I know that I can do something like the above for regular static pages,
and I use this already :
$r->handler('modperl');
$r->set_handlers(PerlAuthzHandler => []); # stop authorization from
running
$r->set_handlers(PerlResponseHandler => \&_send_login_form);


However, when I try to do the same in a Location like the above, it
seems that the jakarta-servlet handler runs anyway, and my
PerlResponseHandler is never called.

The reason I want to do it that way, is that it allows me, in the
substituted PerlResponseHandler, to do some stuff to the login page that
I send, which would be more complicated to do via a simple redirect.
Or ?

(One thing I have not tried (nor researched) e.g., is to see if I can
install both modperl and the jakarta-servlet as handlers, and disable
the modperl handler if the condition is /not/ met.)

Thanks

Re: sethandlers question

am 13.10.2008 10:13:11 von torsten.foertsch

On Sun 12 Oct 2008, Andr=E9 Warnier wrote:
>
>
> =A0 =A0SetHandler jakarta-servlet
> =A0 =A0SetEnvIf REQUEST_URI "\.(htm|web|css|gif|jpg|js|html?)$" no-jk
>
> =A0 =A0PerlXXXHandler My::Module->some_method
>
> =A0 =A0...
>
>

>
> ("jakarta-servlet" above means mod_jk --> Tomcat)
> (and PerlXXXHandler being any kind of Perl HTTP Handler running soon
> enough)
>
> The Question :
> Is it possible, in the PerlXXXHandler, on a request-by-request base,
> to "disable" the jakarta-servlet handler, and install the following
> instead
>
> =A0 =A0SetHandler modperl
> =A0 =A0PerlResponseHandler My::Module->some_other_method
>
> ?
>
> I know that I can do something like the above for regular static
> pages, and I use this already :
> =A0 =A0$r->handler('modperl');
> =A0 =A0$r->set_handlers(PerlAuthzHandler =3D> []); # stop authorization
> from running
> =A0 =A0$r->set_handlers(PerlResponseHandler =3D> \&_send_login_form);
>
>
> However, when I try to do the same in a Location like the above, it
> seems that the jakarta-servlet handler runs anyway, and my
> PerlResponseHandler is never called.

Does that piece of code run in a /Perl(PostReadRequest|Trans|
MapToStorage)Handler/ ?

Please, have a look again at the ap_process_request_internal() function=20
in httpd-2.x.y/server/request.c. This function implements almost the=20
complete request cycle (save PostReadRequest, Response and Log).

Just after ap_run_translate_name(), that is the PerlTransHandler, you'll=20
see this piece:

/* Reset to the server default config prior to running=20
map_to_storage
*/
r->per_dir_config =3D r->server->lookup_defaults;

if ((access_status =3D ap_run_map_to_storage(r))) {
/* This request wasn't in storage (e.g. TRACE) */
return access_status;
}

/* Rerun the location walk, which overrides any map_to_storage=20
config.
*/
if ((access_status =3D ap_location_walk(r))) {
return access_status;
}

/* Only on the main request! */
if (r->main == NULL) {
if ((access_status =3D ap_run_header_parser(r))) {
return access_status;
}
}
..

The line "r->per_dir_config =3D r->server->lookup_defaults;" resets all=20
request specific configurations applied so far. After that line the=20
request is configured as if no Directory/Location or other container=20
were present in your httpd.conf. Next comes MapToStorage. Here=20
Directory, DirectoryMatch, Files and FilesMatch containers are applied=20
to the request. Then, and this is what I think hits you, comes an=20
ap_location_walk. Here Location containers are applied. So, your=20
SetHandler inside the Location overrides any $r->handler seen before.

After the ap_location_walk comes the PerlHeaderParserHandler. But it is=20
skipped for subrequests. A further examination will show you that the=20
next phase that is run by all requests is the PerlTypeHandler just=20
before Fixup. So, move your "$r->handler('modperl');" to one of those=20
and it will work. I prefer Fixup but that is based only on the fact=20
that it is documented as do-what-you-want phase. There are directives=20
that change the handler in the type-checker phase. In fact the=20
AddHandler directive works that way. Mod_mime looks at the file=20
extension and adjusts the handler, e.g "AddHandler cgi-script .pl". So=20
using Fixup your module is the last to kick in.

To carry state around use pnotes, notes or subprocess_env.

Torsten

=2D-
Need professional mod_perl support?
Just hire me: torsten.foertsch@gmx.net

Re: sethandlers question

am 13.10.2008 16:41:17 von aw

Hi Torsten.
Once again, I thank you for the time spent researching and answering my
question(s).
Unfortunately, I am less fluent in C than you (which is why after all I
like and use mod_perl), so sometimes referring me to the C code is not
as enlightening to me as it undoubtedly is to you. But I am trying to
follow, nevertheless.

Torsten Foertsch wrote:
> On Sun 12 Oct 2008, André Warnier wrote:
>>
>>
>> SetHandler jakarta-servlet
>> SetEnvIf REQUEST_URI "\.(htm|web|css|gif|jpg|js|html?)$" no-jk
>>
>> PerlXXXHandler My::Module->some_method
>>
>> ...
>>
>>

>>
>> ("jakarta-servlet" above means mod_jk --> Tomcat)
>> (and PerlXXXHandler being any kind of Perl HTTP Handler running soon
>> enough)
>>
>> The Question :
>> Is it possible, in the PerlXXXHandler, on a request-by-request base,
>> to "disable" the jakarta-servlet handler, and install the following
>> instead
>>
>> SetHandler modperl
>> PerlResponseHandler My::Module->some_other_method
>>
>> ?
>>
>> I know that I can do something like the above for regular static
>> pages, and I use this already :
>> $r->handler('modperl');
>> $r->set_handlers(PerlAuthzHandler => []); # stop authorization
>> from running
>> $r->set_handlers(PerlResponseHandler => \&_send_login_form);
>>
>>
>> However, when I try to do the same in a Location like the above, it
>> seems that the jakarta-servlet handler runs anyway, and my
>> PerlResponseHandler is never called.
>
> Does that piece of code run in a /Perl(PostReadRequest|Trans|
> MapToStorage)Handler/ ?

No, at the moment it runs in a PerlAuthenHandler.
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.
(One main reason is that it allows me, in that content handler,to
"filter" the login page and insert in it, things I have stored
previously in $r->pnotes().)
For that thus, when the user is not authenticated when the request hits
the PerlAuthenHandler, this handler tries to set the content handler
(PerlResponseHandler) to the method send_login_form() in the same module.
This works fine when the previous content handler is Apache's default,
iow for static pages. But it fails miserably when there is already a
specific content handler (like mod_jk) for this Location.

>
> 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 ?

This function implements almost the
> complete request cycle (save PostReadRequest, Response and Log).
>
> Just after ap_run_translate_name(), that is the PerlTransHandler, you'll
> see this piece:
>
> /* Reset to the server default config prior to running
> map_to_storage
> */
> r->per_dir_config = r->server->lookup_defaults;
>
> if ((access_status = ap_run_map_to_storage(r))) {
> /* This request wasn't in storage (e.g. TRACE) */
> return access_status;
> }
>
> /* Rerun the location walk, which overrides any map_to_storage
> config.
> */
> if ((access_status = ap_location_walk(r))) {
> return access_status;
> }
>
> /* Only on the main request! */
> if (r->main == NULL) {
> if ((access_status = ap_run_header_parser(r))) {
> return access_status;
> }
> }
> ...
>
> The line "r->per_dir_config = r->server->lookup_defaults;" resets all
> request specific configurations applied so far. After that line the
> request is configured as if no Directory/Location or other container
> were present in your httpd.conf. Next comes MapToStorage. Here
> Directory, DirectoryMatch, Files and FilesMatch containers are applied
> to the request.
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..

Then, and this is what I think hits you, comes an
> ap_location_walk. Here Location containers are applied. So, your
> SetHandler inside the Location overrides any $r->handler seen before.
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.

I may be misunderstanding what you say above of course..

>
> After the ap_location_walk comes the PerlHeaderParserHandler. But it is
> skipped for subrequests.
That's fine, we are always in a main request here.

A further examination will show you
(probably not)
that the
> next phase that is run by all requests is the PerlTypeHandler just
> before Fixup. So, move your "$r->handler('modperl');" to one of those
> and it will work.
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 ?

I prefer Fixup but that is based only on the fact
> that it is documented as do-what-you-want phase. There are directives
> that change the handler in the type-checker phase. In fact the
> AddHandler directive works that way. Mod_mime looks at the file
> extension and adjusts the handler, e.g "AddHandler cgi-script .pl". So
> using Fixup your module is the last to kick in.

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 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

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



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 ?

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) ?

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

>
> To carry state around use pnotes
(that's what I use mostly)
, notes or subprocess_env.
>

Re: sethandlers question

am 13.10.2008 18:44:03 von torsten.foertsch

On Mon 13 Oct 2008, Andr=E9 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=20
$r->custom_response. Configure an ErrorDocument for 403 and return=20
HTTP_FORBIDDEN in your A...Handler. That has the benefit that the 403=20
status is logged and that the browser (think about search engines) sees=20
it. But the custom response page must be larger than 512 bytes or=20
you'll encounter problems with IE. If you don't care about that you can=20
use $r->internal_redirect. That is a bit less work to do for your=20
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. =A0I 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=20
in your favorite editor. C is not that much different from perl and the=20
request.c file is really easy to read. You don't have to modify it,=20
just try to understand what is going on!

> So, you mean that for every and each request, Apache re-configures
> itself ? =A0If 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=20
to have a static configuration. So at start it splits the configuration=20
into blocks, one holds the basic config that is outside all containers=20
and others for each Location/Directory/etc. From those blocks it=20
generates pre-parsed configuration vectors. At runtime each request=20
starts with the basic config fetched from r->server->lookup_defaults=20
then it looks for other vectors matching the request and merges them.

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

With mod_perl comes yet another configuration source, $r->add_config.=20
This is implemented very similar to .htaccess only the directives are=20
not read from a file but from memory and they are compiled and merged=20
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=20
SetHandler directive sets $r->handler. Maybe it is done in the type=20
checker phase. So perhaps you have to move your code to Fixup or use=20
$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. =A0That would
> probably for one upset Adam, for two be kind of funky, no ?

Why not?

if( $override_handler ) {
$r->push_handlers( PerlFixupHandler=3D>__PACKAGE__.'::fixup' );
$r->pnotes->{override_handler}=3D'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. =A0I 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 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
>
> =A0 =A0 SetHandler jakarta-servlet
> =A0 =A0 SetEnvIf REQUEST_URI "\.(htm|web|css|gif|jpg|js|html?)$" no-jk
>
> =A0 =A0 AuthType MyModule
> =A0 =A0 AuthName MyXyzApp
> =A0 =A0 PerlSetVar MyModule_var1 "value"
> =A0 =A0 PerlAccessHandler My::Module->some_access_method
> =A0 =A0 PerlAuthenHandler My::Module->some_auth_method
> =A0 =A0 PerlAuthzHandler My::Module->some_authz_method
> =A0 =A0 require valid-user
>
>

>
> then, if I understand correctly what you write above, since I have no
> PerlTransHandler, nor Fixup, etc.. =A0I 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.=20
If you want to try use $r->subprocess_env->{'no-jk'}=3D1;

> Or, another thought that just occurred : can I comment out the
> "SetHandler jakarta-servlet" originally, set my PerlresponseHandler
> as the default handler in the , 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=20
second best is the internal_redirect. Both need a way to address you=20
login form by an URI.


SetHandler modperl
PerlResponseHandler My::LoginForm


package My::LoginForm;
sub handler {
my ($r)=3D@_;
my $original_req=3D$r->prev;
unless( $original_req ) {
$r->log_reason("/login is to be called as internal redirect");
return Apache2::Const::SERVER_ERROR;
}
my $original_pnotes=3D$original_req->pnotes;
...
return Apache2::Const::OK;
}

ErrorDocument 403 /login


Torsten

=2D-
Need professional mod_perl support?
Just hire me: torsten.foertsch@gmx.net

Re: sethandlers question

am 14.10.2008 13:00:09 von aw

Hi.

I have read and pondered your earlier responses, and I am sure that the
correct solution is somewhere around the ErrorDocument or the
$r->internal_redirect.
But I wanted to exhaust the other possibilities first, for the sake of
completeness and also to learn more about this all.

So one little bit at a time :

reminder of my config :
>>
>> 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
>>
>>
>>
And, in summary, what I was trying to do is :
if the PerlAuthenHandler finds that the request is not authenticated,
then it tries to change the response handler for this request, from the
original "jakarta-servlet" handler, to my own response handler, which in
fact returns a login page.
(I need something "active" to return the login page, because I need to
insert some data into the login page prior to returning it).

And for that I used this code in the PerlAuthenHandler :

# set our own response handler
$r->handler('modperl');
$r->set_handlers(PerlResponseHandler => \&_send_login_form);
return OK;


One of the possibilities envisioned previously was :
>
>> 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;
>

I tried this, because it was the smallest possible change to my module.
It works, in the sense that it sets the "no-jk" variable, which
consequently has the effect of making the "jakarta-servlet" handler
above not process this link.
But it is not a solution for me, since what happens is that the
jakarta-servlet handler is in fact still executed by Apache as the
response handler, but it probably just returns DECLINED.
Then Apache seems to handle the response with its own default handler,
which results in a "404 not found" error.

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

> Torsten said : Of course.
But Torsten did not say how, and I don't know how to do that.
How can I set the Apache response handler to be "xyz" ? All I have at
this point is the name of that handler : "jakarta-servlet".
This is not a perl handler, it is mod_jk.so, the Apache/Tomcat AJP
connector. (And I do not need code, I just need a pointer in the right
direction).

This is now purely for curiosity and for future reference, because after
your previous explanations, I am convinced that this is not the right
solution for the current problem.

In the meantime, I'll go have a look at $r->internal_redirect, which is
probably the correct solution.

Re: sethandlers question

am 14.10.2008 14:39:59 von torsten.foertsch

On Tue 14 Oct 2008, Andr=E9 Warnier wrote:
> reminder of my config :
> >>
> >> =A0 =A0 SetHandler jakarta-servlet
..
> >>
>
> And, in summary, what I was trying to do is :
> if the PerlAuthenHandler finds that the request is not authenticated,
> then it tries to change the response handler for this request, from
> the original "jakarta-servlet" handler, to my own response handler,
> which in fact returns a login page.
> (I need something "active" to return the login page, because I need
> to insert some data into the login page prior to returning it).
>
> And for that I used this code in the PerlAuthenHandler :
>
> # set our own response handler
> $r->handler('modperl');
> $r->set_handlers(PerlResponseHandler =3D> \&_send_login_form);
> return OK;

The problem is the $r->handler statement. The program flow is this:

=2D ...
=2D uri translation
=2D map to storage
=2D Location container is applied
the SetHandler directive is applied to the requests configuration
structure. That does not mean $r->handler is set. It is simply noted
there is a SetHandler directive active for the request.
=2D aaa
=2D ...
=2D fixup
the SetHandler value is copied to $r->handler. See
httpd-2.x.y/server/core.c:core_override_type()

if (conf->handler && strcmp(conf->handler, "none"))
r->handler =3D conf->handler;

That means $r->handler is set only if there was a SetHandler directive
and if it was not "SetHandler none".

So, that leads us to 4 possible solutions:

1) remove the SetHandler directive from the Location container and set=20
$r->handler either to jakarta-servelet or to modperl in your aaa=20
handler. It won't be touched if other modules don't kick in. mod_dir=20
comes to mind but it reads (fixup handler):

/* In case mod_mime wasn't present, and no handler was assigned. */
if (!r->handler) {
r->handler =3D DIR_MAGIC_TYPE;
}

So, that's not a problem. But there may be other modules that don't=20
check that.

2) replace $r->handler('modperl') in the aaa phase by=20
$r->add_config(['SetHandler modperl']). This way you override the=20
handler set in the configuration structure. In the fixup phase it is=20
then automagically copied to $r->handler.

3) leave the $r->handler('modperl') and add a=20
$r->add_config(['SetHandler none']);

4) set $r->handler in a fixup handler.

$r->add_config works very similar to


your directives


The only difference is the time when it is applied to the config struct.=20
That config is reset after the translation phase. So it is useless to=20
try $r->add_config before. Location containers from the httpd.conf are=20
applied after MapToStorage. So anything you do in your own MapToStorage=20
handler can be overridden in Location containers even if your handler=20
returns OK to skip the core MapToStorage handler.

But anything applied after that, that means from the header-parser phase=20
onward overrides the httpd.conf settings.

> One of the possibilities envisioned previously was :
> >> 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'}=3D1;
>
> I tried this, because it was the smallest possible change to my
> module. It works, in the sense that it sets the "no-jk" variable,
> which consequently has the effect of making the "jakarta-servlet"
> handler above not process this link.
> But it is not a solution for me, since what happens is that the
> jakarta-servlet handler is in fact still executed by Apache as the
> response handler, but it probably just returns DECLINED.

That's what I thought it would.

Torsten

=2D-
Need professional mod_perl support?
Just hire me: torsten.foertsch@gmx.net

Re: sethandlers question

am 14.10.2008 16:21:03 von aw

I am trying the 4 receipes one after the other, in order of easiest to
more complicated.

Torsten Foertsch wrote:
>
> 2) replace $r->handler('modperl') in the aaa phase by
> $r->add_config(['SetHandler modperl']). This way you override the
> handler set in the configuration structure. In the fixup phase it is
> then automagically copied to $r->handler.
When I try this, I get an Apache error with the following logfile message :
[Tue Oct 14 16:19:39 2008] [error] [client 84.158.163.207]
$r->add_config() has failed: SetHandler not allowed here at
/usr/local/lib/apache2/perllib/AUTH/StarLogCookie.pm line 416.\n

>
> 3) leave the $r->handler('modperl') and add a
> $r->add_config(['SetHandler none']);
>
When I try this, I get an Apache error with the following logfile message :
[Tue Oct 14 16:10:40 2008] [error] [client 84.158.163.207]
$r->add_config() has failed: SetHandler not allowed here at
/usr/local/lib/apache2/perllib/AUTH/StarLogCookie.pm line 414.\n


So it seems that something does not like the $r->add_config from within
an AAA method, or at least not when trying to change the handler.

I'll try the others now.

Re: sethandlers question

am 14.10.2008 17:18:12 von torsten.foertsch

On Tue 14 Oct 2008, Andr=E9 Warnier wrote:
> When I try this, I get an Apache error with the following logfile
> message : [Tue Oct 14 16:10:40 2008] [error] [client 84.158.163.207]
> $r->add_config() has failed: SetHandler not allowed here at
> /usr/local/lib/apache2/perllib/AUTH/StarLogCookie.pm line 414.\n

That is an apache error. SetHandler needs the FileInfo override flag,=20
see http://httpd.apache.org/docs/2.2/mod/core.html#sethandler. So, the=20
correct command would be:

$r->add_config(['SetHandler ...'], Apache2::Const::OR_FILEINFO)

or simpler

$r->add_config(['SetHandler ...'], ~0)

(since you know what directive you are adding).

Torsten

=2D-
Need professional mod_perl support?
Just hire me: torsten.foertsch@gmx.net

Re: sethandlers question

am 14.10.2008 17:32:50 von aw

André Warnier wrote:
> I am trying the 4 receipes one after the other, in order of easiest to
> more complicated.
>
> Torsten Foertsch wrote:
>>
>> 2) replace $r->handler('modperl') in the aaa phase by
>> $r->add_config(['SetHandler modperl']). This way you override the
>> handler set in the configuration structure. In the fixup phase it is
>> then automagically copied to $r->handler.
> When I try this, I get an Apache error with the following logfile message :
> [Tue Oct 14 16:19:39 2008] [error] [client 84.158.163.207]
> $r->add_config() has failed: SetHandler not allowed here at
> /usr/local/lib/apache2/perllib/AUTH/StarLogCookie.pm line 416.\n
>
>>
>> 3) leave the $r->handler('modperl') and add a
>> $r->add_config(['SetHandler none']);
>>
> When I try this, I get an Apache error with the following logfile message :
> [Tue Oct 14 16:10:40 2008] [error] [client 84.158.163.207]
> $r->add_config() has failed: SetHandler not allowed here at
> /usr/local/lib/apache2/perllib/AUTH/StarLogCookie.pm line 414.\n
>
>
> So it seems that something does not like the $r->add_config from within
> an AAA method, or at least not when trying to change the handler.
>

But
> 4) set $r->handler in a fixup handler.

this works :

$r->set_handlers(PerlAuthzHandler => []); # disable authorization
$r->set_handlers(PerlResponseHandler => \&_send_login_form);
$r->set_handlers(PerlFixupHandler => \{$_[0]->handler('modperl')});


Many, many thanks for all the explanations and tips.

I doubly appreciate not only because my immediate problem is solved, but
also because I learned a lot in the process.

It seems to me that this whole thread could be collected and re-arranged
into a Tutorial on mod_perl phases, authentication, interactions with
Apache etc.. but honestly at the moment I don't know where to begin.

Re: sethandlers question

am 14.10.2008 18:27:31 von torsten.foertsch

On Tue 14 Oct 2008, Andr=E9 Warnier wrote:
> I doubly appreciate not only because my immediate problem is solved,
> but also because I learned a lot in the process.

Try the $r->add_config again with the right override flag (OR_FILEINFO)=20
and you'll see it will also work.

> It seems to me that this whole thread could be collected and
> re-arranged into a Tutorial on mod_perl phases, authentication,
> interactions with Apache etc.. =A0but honestly at the moment I don't
> know where to begin.

=46ind a place where you think it would fit and send in a patch, see=20
http://perl.apache.org/contribute/svn_howto.html#Working_wit h_SVN on=20
how to get the source.

Torsten

=2D-
Need professional mod_perl support?
Just hire me: torsten.foertsch@gmx.net

Re: sethandlers question

am 14.10.2008 18:35:18 von aw

Torsten Foertsch wrote:
[...]
>
> 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.
>

At this moment, I cannot see clearly how the ErrorDocument solution
would allow me to send back a login page created dynamically, as I need
to do. I will look it up, but as a definitive solution for the time
being I would prefer the $r->internal_redirect method, where I can see
more clearly how to do this.

But I still have some (hopefully) last questions, if you would be so kind :

As I understand this, the internal_redirect() basically stops the
current request, and replaces it in-place by a totally new request,
except that in that new request, $r->prev will be set to the (original)
request that did the redirect, right ?

(So in the new request, I can still access the pnotes set by the
original request, via $r->prev->pnotes()).

For this new request, the cycle restarts right at the beginning, and
runs through all the steps just as if this was a main request. Right ?

Are there any other significant differences between this new request and
the previous one that I should be very aware of (in a mod_perl/AAA
context) ?

One thing I do not really understand, is what happens to the original
request, when it issues a call to $r->internal_redirect().
Does the original request still run to completion, or does it "abort"
right there ?
Does Apache still return something to the browser for the original
request, or is that completely replaced by whatever the new (redirected)
request produces ?
After the call to $r->internal_redirect(), should the original request
still do something ? (like return Apache2::Const::?????) ?

Thanks

P.S.
I have downloaded the Apache source, and looked at the code within
httpd-2.x.y/server/request.c, but it is still a bit obscure to me,
except in a very general sense. I kind of approximately follow the
steps, but do not always understand aspects like why it re-does
directory walks at several stages, nor can I see at all where mod_perl
plugs in to that code.

Re: sethandlers question

am 14.10.2008 19:57:10 von torsten.foertsch

On Tue 14 Oct 2008, Andr=E9 Warnier wrote:
> At this moment, I cannot see clearly how the ErrorDocument solution
> would allow me to send back a login page created dynamically, as I
> need to do. =A0I will look it up, but as a definitive solution for the
> time being I would prefer the $r->internal_redirect method, where I
> can see more clearly how to do this.


PerlAuthenHandler "sub { \
return Apache2::Const::FORBIDDEN unless ...;
}"
ErrorDocument 403 /login



SetHandler modperl
# you still have to supply a login_form function that expects a
# $r object.
PerlResponseHandler "sub { \
my $r=3Dshift; \
$r->content_type('text/html'); \
$r->print(login_form($r->prev));
return Apache2::Const::OK;
}"


Your A-handler returns 403. Instead of sending the standard FORBIDDEN=20
page to the browser apache catches the error because of the=20
ErrorDocument directive. "/login" looks like an URI. Hence apache will=20
perform an internal redirect to it. "/login" is configured in the=20
normal modperl-way.

The browser will see an HTTP status of 403 (it will also be logged as=20
403). But the message sent along will be the output of &login_form. And=20
that is what the user will see. &login_form has access to the original=20
request. So, it can pass the original URI in a hidden field.

See also http://httpd.apache.org/docs/2.2/mod/core.html#errordocument

Instead of 403 you can also use 401 if you want to use=20
http-authentication. That is the user will see a browser generated=20
password box. But I doubt that is what you want.

> But I still have some (hopefully) last questions, if you would be so
> kind :
>
> As I understand this, the internal_redirect() basically stops the
> current request, and replaces it in-place by a totally new request,
> except that in that new request, $r->prev will be set to the
> (original) request that did the redirect, right ?

Yes. Best if you return OK from the current handler right after the=20
$r->internal_redirect line.

> (So in the new request, I can still access the pnotes set by the
> original request, via $r->prev->pnotes()).

Yes.

> For this new request, the cycle restarts right at the beginning, and
> runs through all the steps just as if this was a main request. Right
> ?

AAA are possibly skipped as I mentioned before.

> Are there any other significant differences between this new request
> and the previous one that I should be very aware of (in a
> mod_perl/AAA context) ?

You'll find some, ;-)

> One thing I do not really understand, is what happens to the original
> request, when it issues a call to $r->internal_redirect().
> Does the original request still run to completion, or does it "abort"
> right there ?

I think you'll see the original request again in the logging phase.

> Does Apache still return something to the browser for the original
> request, or is that completely replaced by whatever the new
> (redirected) request produces ?

No, not unless you have sent something prior to the internal_redirect.

> After the call to $r->internal_redirect(), should the original
> request still do something ? (like return Apache2::Const::?????) ?

OK, see=20
http://perl.apache.org/docs/2.0/api/Apache2/SubRequest.html# C_internal_redi=
rect_

> P.S.
> I have downloaded the Apache source, and looked at the code within
> httpd-2.x.y/server/request.c, but it is still a bit obscure to me,
> except in a very general sense. =A0I kind of approximately follow the
> steps, but do not always understand aspects like why it re-does
> directory walks at several stages, nor can I see at all where
> mod_perl plugs in to that code.

great! Many treasures are hidden there.

Torsten

=2D-
Need professional mod_perl support?
Just hire me: torsten.foertsch@gmx.net

Re: sethandlers question

am 15.10.2008 11:33:00 von torsten.foertsch

On Tue 14 Oct 2008, Torsten Foertsch wrote:
> On Tue 14 Oct 2008, Andr=E9 Warnier wrote:
> > When I try this, I get an Apache error with the following logfile
> > message : [Tue Oct 14 16:10:40 2008] [error] [client
> > 84.158.163.207] $r->add_config() has failed: SetHandler not allowed
> > here at /usr/local/lib/apache2/perllib/AUTH/StarLogCookie.pm line
> > 414.\n
>
> That is an apache error. SetHandler needs the FileInfo override flag,
> see http://httpd.apache.org/docs/2.2/mod/core.html#sethandler. So,
> the correct command would be:
>
> $r->add_config(['SetHandler ...'], Apache2::Const::OR_FILEINFO)
>
> or simpler
>
> $r->add_config(['SetHandler ...'], ~0)
>
> (since you know what directive you are adding).

Maybe others are interested too, here are 2 private messages:

On Wed 15 Oct 2008, Andr=E9 Warnier wrote:
> Ok, I did, and it seems to work too :
>
> So I have 2 sequences that work :
> a)
> $r->add_config(['SetHandler modperl'], ~0);
> $r->set_handlers(PerlAuthzHandler =3D> []); # disable authorization
> $r->set_handlers(PerlResponseHandler =3D> \&_send_login_form);
> #$r->set_handlers(PerlFixupHandler =3D> sub {
> $_[0]->handler('modperl') } );
>
> b)
> #$r->add_config(['SetHandler modperl'], ~0);
> $r->set_handlers(PerlAuthzHandler =3D> []); # disable authorization
> $r->set_handlers(PerlResponseHandler =3D> \&_send_login_form);
> $r->set_handlers(PerlFixupHandler =3D> sub {
> $_[0]->handler('modperl') } );
>
> Now, can you explain ?
> I don't even understand what "~0" means..

On Wed 15 Oct 2008, Torsten Foertsch wrote:
> On Wed 15 Oct 2008, Andr=E9 Warnier wrote:
> > 1) you mentioned that it was due to a Apache bug.
>
> Did I really say bug? I meant an Apache error message. You'll see the
> same message if you try something like that:
>
>
> AllowOverride AuthConfig
>

>
> and then have an .htaccess with a SetHandler directive in it.
> SetHandler needs "AllowOverride FileInfo". But only AuthConfig is
> set.
>
> The 2nd parameter to add_config is a AllowOverride bit field. It
> limits what kind of directives are allowed to be added. Think of it
> as if you have read the directives from an untrusted source (like
> .htaccess).
>
> > 2) I do not have a clue why the above would work around that bug.
>
> Apache wants here not only to be told to add the SetHandler but also
> to be ensured "Yes, that is what I want. Just do it!".
>
> ~0 means all bits turned on.

Torsten

=2D-
Need professional mod_perl support?
Just hire me: torsten.foertsch@gmx.net