You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Jan Kasprzak <ka...@fi.muni.cz> on 2018/03/12 15:15:07 UTC

Recognizing user in PerlFixupHandler

	Hello, mod_perl users,

I have a cookies-based authentication similar to Apache2::AuthCookie,
and I have problem with setting up authentication with recognizing users
in PerlFixupHandler also for URLs accessible even without authentication
(similar to what Apache2::AuthCookie->recognize_user is supposed to do).
My httpd.conf contains something along these lines:

DocumentRoot /www

<Directory /www>
	<Files *.pl>
		SetHandler perl-script
		PerlFixupHandler My::Auth->recognize_user
		PerlResponseHandler My::Registry
	</Files>
	Order deny, allow
	allow from all
	DirectoryIndex index.pl
</Directory>

<Directory /www/auth>
        AuthName "PrivateArea"
	AuthType My::Auth
	PerlAuthenHandler My::Auth->authenticate
	require valid-user

	<Files *.pl>
		SetHandler perl-script
		PerlResponseHandler My::Registry
	</Files>
</Directory>

If I point my browser to https://my.server/auth/, the user authenticates,
and the auth info is stored in a cookie. In that case, I want subsequent
requests to Perl scripts with that cookie even outside the /auth/ area
to be recognized as authenticated, i.e. to have $r->user() nonempty.
This is what the PerlFixupHandler above is supposed to do.

It mostly works except when some URL rewriting happens:

https://my.server/index.pl works correctly (has non-empty $r->user), but
https://my.server/ without /index.pl suffix has empty $r->user, even though
I have verified that the PerlFixupHandler is also being executed and it sets
non-empty $r->user($user_from_cookie) correctly. After it returns
Apache2::Const::DECLINED, the My::Registry::handler() starts,
but it has empty $r->user, despite it being set to non-empty
in the PerlFixupHandler.

When I move the PerlFixupHandler directive outside the <Files *.pl> scope,
recognizing user works even for https://my.server/ without /index.pl, 
but then the PerlFixupHandler is unnecessarily executed even for
things like static (non-Perl) data: images, Javascript files, etc.

Why does the $r->user() value disappear between PerlFixupHandler
and PerlResponseHandler calls?

	Thanks,

-Yenya

-- 
| Jan "Yenya" Kasprzak <kas at {fi.muni.cz - work | yenya.net - private}> |
| http://www.fi.muni.cz/~kas/                         GPG: 4096R/A45477D5 |
> That's why this kind of vulnerability is a concern: deploying stuff is  <
> often about collecting an obscene number of .jar files and pushing them <
> up to the application server.                          --pboddie at LWN <

Re: Recognizing user in PerlFixupHandler

Posted by "André Warnier (tomcat)" <aw...@ice-sa.com>.
Hi.

I do use similar (but a bit less clever) code in one of my modules :

	if (my $prev = ($r->main || $r->prev)) {
		$logger->warn("$pfx sub-request or internal redirect") if ($debug > 2);
		# we are in a subrequest.
...
		if (defined(my $uid = $prev->user)) {
			$r->user( $uid );
...

but I do not recurse. I guess I should also do that, in case this is a sub-sub-request..


On 12.03.2018 16:35, pali@cpan.org wrote:
> Hi Yenya!
>
> On Monday 12 March 2018 16:15:07 Jan Kasprzak wrote:
>> https://my.server/index.pl works correctly (has non-empty $r->user), but
>> https://my.server/ without /index.pl suffix has empty $r->user, even though
>
> This looks like an apache's internal redirect...
>
>> I have verified that the PerlFixupHandler is also being executed and it sets
>> non-empty $r->user($user_from_cookie) correctly. After it returns
>> Apache2::Const::DECLINED, the My::Registry::handler() starts,
>> but it has empty $r->user, despite it being set to non-empty
>> in the PerlFixupHandler.
>
> It is possible that in an internal redirect you get a new $r instance.
>
>> When I move the PerlFixupHandler directive outside the <Files *.pl> scope,
>> recognizing user works even for https://my.server/ without /index.pl,
>> but then the PerlFixupHandler is unnecessarily executed even for
>> things like static (non-Perl) data: images, Javascript files, etc.
>>
>> Why does the $r->user() value disappear between PerlFixupHandler
>> and PerlResponseHandler calls?
>
> And therefore it does not see $r->user as it was set in another request.
> Internal redirect is a new (internal) request.
>
> Those request objects are in some list or tree structure. Years ago I
> needed to solve a similar problem, that value set in the MapToStorage
> handler was not "visible" in the Authen handler. To access parent/upper
> request object there is ->prev or ->main method.
>
> You can try to set ->user on the "main" request object. And then read
> ->user again from the main object.
>
> I used following code to retrieve main object, maybe it helps you.
>
> 	my $r_main = $r;
> 	$r_main = $r_main->main // $r_main->prev
> 		until $r_main->is_initial_req;
>


Re: Recognizing user in PerlFixupHandler

Posted by pa...@cpan.org.
Hi Yenya!

On Monday 12 March 2018 16:15:07 Jan Kasprzak wrote:
> https://my.server/index.pl works correctly (has non-empty $r->user), but
> https://my.server/ without /index.pl suffix has empty $r->user, even though

This looks like an apache's internal redirect...

> I have verified that the PerlFixupHandler is also being executed and it sets
> non-empty $r->user($user_from_cookie) correctly. After it returns
> Apache2::Const::DECLINED, the My::Registry::handler() starts,
> but it has empty $r->user, despite it being set to non-empty
> in the PerlFixupHandler.

It is possible that in an internal redirect you get a new $r instance.

> When I move the PerlFixupHandler directive outside the <Files *.pl> scope,
> recognizing user works even for https://my.server/ without /index.pl, 
> but then the PerlFixupHandler is unnecessarily executed even for
> things like static (non-Perl) data: images, Javascript files, etc.
> 
> Why does the $r->user() value disappear between PerlFixupHandler
> and PerlResponseHandler calls?

And therefore it does not see $r->user as it was set in another request.
Internal redirect is a new (internal) request.

Those request objects are in some list or tree structure. Years ago I
needed to solve a similar problem, that value set in the MapToStorage
handler was not "visible" in the Authen handler. To access parent/upper
request object there is ->prev or ->main method.

You can try to set ->user on the "main" request object. And then read
->user again from the main object.

I used following code to retrieve main object, maybe it helps you.

	my $r_main = $r;
	$r_main = $r_main->main // $r_main->prev
		until $r_main->is_initial_req;