Authentication and cookies

Authentication and cookies

am 21.01.2011 15:25:11 von Dan Axtell

I'm trying to upgrade mod_perl authentication/authorization handlers for
application menu to be more fine-grained by using cookies. The basic idea is
- restrict a script alias in httpd.conf with basic authentication calling the
custon handlers
- validate the user ID/password in the authentication handler, and look up
role and client access info; stash in cookie. If a valid cookie is already
there, authenticat
- in authorization, check for cookie, reset if it's not there, and authorize
based on role and client information
- in menu app, check for cookie, and configure output depending on user's
role.

What happens is that even though the browser shows a cookie with the correct
info, the menu ends up with a "no cookie found" error, and the logs show
neither the authorization handler nor app are seeing the cookie. Hitting
refresh on the menu shows both handlers seeing the cookie and the menu comes
up correctly.

I've tried using both CGI::Cookie and Apache2::Cookie; I get the same problem
either way. Currently the authentication handler sets the cookie as follows:

my $cookie = Apache2::Cookie->new($r, -name => 'ls_authentication',
value => { user_id => $user, digest => crypt($password,
$salt), role_id => $ur{role_id}, clients => $client_list });
if ($cookie) {
$cookie->bake($r);
} else {
warn "Unable to make cookie";
}

I get no warning, and the cookie looks fine in the browser's debug tool, but
the next handler and app just don't see it. This is how I try and read it in
the authorization handler:

my $jar = Apache2::Cookie::Jar->new($r);
my $cookie = $jar->cookies('ls_authentication');
if ($cookie) {
$have_cookie = 1;
my %fields = $cookie->value;
if ($fields{'user_id'}) {
$user = $fields{'user_id'};
}
if ( $fields{'role_id'} ) {
$user_role = $fields{'role_id'};
}
if ( $fields{'clients'} ) {
@user_clients = split(/,/, $fields{'clients'}); # turn client
list back into array
}
warn "AUTHORIZATION: found cookie, user ID = $user, user role =
$user_role" if $DEBUG;
} else {
warn "AUTHORIZATION: NO COOKIE FOUND" if $DEBUG;
}


I'm running Perl 5.12.1, Apache 2.2.17 and libapreq2 2.13 built from source.
Is using 'bake' insufficient to make the cookie visible by the next handler?
I've tried using both
$r->err_headers_out->set('Set-Cookie', $cookie);
and
$r->err_headers_out->addt('Set-Cookie', $cookie);
but I get the same problem.

Does anyone know of any up to date demos of using cookies in mod_perl2
authentication handlers?

Re: Authentication and cookies

am 23.01.2011 21:09:01 von aw

Hi.

This is a suggestion to solve what I understand of your problem, but slightly differently.
(And I admit that it is because I do not know if you can do that with a cookie-jar, I have
never tried; but what is below, I did try and it works).

The idea is as follows.
A cookie is useful in the sense that it is an "information store" which you can offload to
the browser by means of a "Set-Cookie" header /at the moment when you send a response to
the browser/, and of which you can be (almost) sure that when the browser sends its next
request to your server, it will re-send this same cookie along with the new request (in a
"Cookie" header.
So it saves you from creating a local store on the server, and anyway have to manage some
way for the browser to receive and send back some "session-id" that allows your server to
retrieve the corresponding local store entry.

But a cookie is less useful at the server level, as a means to save information between
Apache (and mod_perl) request processing phases.
For that, you have a better choice : the "pnotes".
http://perl.apache.org/docs/2.0/api/Apache2/RequestUtil.html #C_pnotes_

In your first handler (e.g. PerlAccessHandler), you get and decode the cookie sent by the
browser; you store the user-id, and whatever else you have from the cookie, in a perl hash
for example, and then store this perl hash as an entry in the $r->pnotes.
$r->pnotes("key" => $hashref);
In later phases of the same request, another handler can retrieve this same hash from the
$hashref = $r->pnotes("key").
E.g. in the PerlAuthenHandler, instead of decoding the cookie again, you retrieve the
hash, and check the values stored in the hash.
Same thing in a PerlAuthzHandler.

Then right before you create the response to the user (e.g. a PerlFixupHandler), you
retrieve this hash again, and you create the cookie to send along with the response, in
the HTTP response headers.

At the end of the request, the pnotes disappear automatically.

Actually, it is a bit more complicated than that, because Web AAA is quite spaghetti-like
in terms of logic. But that, I suppose, you have already found out.



Dan Axtell wrote:
> I'm trying to upgrade mod_perl authentication/authorization handlers for
> application menu to be more fine-grained by using cookies. The basic idea is
> - restrict a script alias in httpd.conf with basic authentication calling the
> custon handlers
> - validate the user ID/password in the authentication handler, and look up
> role and client access info; stash in cookie. If a valid cookie is already
> there, authenticat
> - in authorization, check for cookie, reset if it's not there, and authorize
> based on role and client information
> - in menu app, check for cookie, and configure output depending on user's
> role.
>
> What happens is that even though the browser shows a cookie with the correct
> info, the menu ends up with a "no cookie found" error, and the logs show
> neither the authorization handler nor app are seeing the cookie. Hitting
> refresh on the menu shows both handlers seeing the cookie and the menu comes
> up correctly.
>
> I've tried using both CGI::Cookie and Apache2::Cookie; I get the same problem
> either way. Currently the authentication handler sets the cookie as follows:
>
> my $cookie = Apache2::Cookie->new($r, -name => 'ls_authentication',
> value => { user_id => $user, digest => crypt($password,
> $salt), role_id => $ur{role_id}, clients => $client_list });
> if ($cookie) {
> $cookie->bake($r);
> } else {
> warn "Unable to make cookie";
> }
>
> I get no warning, and the cookie looks fine in the browser's debug tool, but
> the next handler and app just don't see it. This is how I try and read it in
> the authorization handler:
>
> my $jar = Apache2::Cookie::Jar->new($r);
> my $cookie = $jar->cookies('ls_authentication');
> if ($cookie) {
> $have_cookie = 1;
> my %fields = $cookie->value;
> if ($fields{'user_id'}) {
> $user = $fields{'user_id'};
> }
> if ( $fields{'role_id'} ) {
> $user_role = $fields{'role_id'};
> }
> if ( $fields{'clients'} ) {
> @user_clients = split(/,/, $fields{'clients'}); # turn client
> list back into array
> }
> warn "AUTHORIZATION: found cookie, user ID = $user, user role =
> $user_role" if $DEBUG;
> } else {
> warn "AUTHORIZATION: NO COOKIE FOUND" if $DEBUG;
> }
>
>
> I'm running Perl 5.12.1, Apache 2.2.17 and libapreq2 2.13 built from source.
> Is using 'bake' insufficient to make the cookie visible by the next handler?
> I've tried using both
> $r->err_headers_out->set('Set-Cookie', $cookie);
> and
> $r->err_headers_out->addt('Set-Cookie', $cookie);
> but I get the same problem.
>
> Does anyone know of any up to date demos of using cookies in mod_perl2
> authentication handlers?
>

Re: Authentication and cookies

am 27.01.2011 20:22:41 von Joe Schaefer

OP, see =0Ahttps://svn.apache.org/repos/infra/websites/cms/webgui/li b/ASF/C=
MS/Cookie.pm=0Afor typical APR::Request::Cookie usage with FreezeThaw as se=
rializer. Unless =0Ayou=0Awant to use arrays this is one of the ways to de=
al with hashrefs as cookie =0Avalues. In your calling code you'd do so=
mething like this my $apreq =3D APR::Request::Apache2->handle($r);=0Am=
y $jar =3D $apreq->jar;=0A$jar->cookie_class($cookie_package); =0A my $=
cookie =3D $jar->get('ls_authentication');=0Amy $hashref =3D $cookie->thaw =
if $cookie;=0A... =0A----- Original Message ----=0A> From: Andr=E9 War=
nier =0A> To: mod_perl list =0A> Se=
nt: Sun, January 23, 2011 3:09:01 PM=0A> Subject: Re: Authentication and co=
okies=0A> =0A> Hi.=0A> =0A> This is a suggestion to solve what I understand=
of your problem, but slightly =0A>differently.=0A> (And I admit that it i=
s because I do not know if you can do that with a =0A>cookie-jar, I have n=
ever tried; but what is below, I did try and it works).=0A> =0A> The idea =
is as follows.=0A> A cookie is useful in the sense that it is an "informat=
ion store" which you =0A>can offload to the browser by means of a "Set-Coo=
kie" header /at the moment =0A>when you send a response to the browser/, a=
nd of which you can be (almost) sure =0A>that when the browser sends its n=
ext request to your server, it will re-send =0A>this same cookie along with=
the new request (in a "Cookie" header.=0A> So it saves you from creating =
a local store on the server, and anyway have to =0A>manage some way for th=
e browser to receive and send back some "session-id" that =0A>allows your =
server to retrieve the corresponding local store entry.=0A> =0A> But a coo=
kie is less useful at the server level, as a means to save =0A>information=
between Apache (and mod_perl) request processing phases.=0A> For that, yo=
u have a better choice : the "pnotes".=0A> http://perl.apache.org/docs/2.0=
/api/Apache2/RequestUtil.html#C_pnotes_=0A> =0A> In your first handler (e.=
g. PerlAccessHandler), you get and decode the cookie =0A>sent by the brows=
er; you store the user-id, and whatever else you have from the =0A>cookie,=
in a perl hash for example, and then store this perl hash as an entry in =
=0A>the $r->pnotes.=0A> $r->pnotes("key" =3D> $hashref);=0A> In later phase=
s of the same request, another handler can retrieve this same =0A>hash fro=
m the $hashref =3D $r->pnotes("key").=0A> E.g. in the PerlAuthenHandler, i=
nstead of decoding the cookie again, you =0A>retrieve the hash, and check =
the values stored in the hash.=0A> Same thing in a PerlAuthzHandler.=0A> =
=0A> Then right before you create the response to the user (e.g. a =0A>Per=
lFixupHandler), you retrieve this hash again, and you create the cookie to=
=0A>send along with the response, in the HTTP response headers.=0A> =0A> =
At the end of the request, the pnotes disappear automatically.=0A> =0A> Ac=
tually, it is a bit more complicated than that, because Web AAA is quite =
=0A>spaghetti-like in terms of logic. But that, I suppose, you have alrea=
dy found =0A>out.=0A> =0A> =0A> =0A> Dan Axtell wrote:=0A> > I'm trying to=
upgrade mod_perl authentication/authorization handlers for =0A>application=
menu to be more fine-grained by using cookies. The basic idea is=0A> > -=
restrict a script alias in httpd.conf with basic authentication calling =
=0A>the custon handlers=0A> > - validate the user ID/password in the authe=
ntication handler, and look up =0A>role and client access info; stash in c=
ookie. If a valid cookie is already =0A>there, authenticat=0A> > - in aut=
horization, check for cookie, reset if it's not there, and authorize =0A>b=
ased on role and client information=0A> > - in menu app, check for cookie,=
and configure output depending on user's =0A>role.=0A> > =0A> > What happ=
ens is that even though the browser shows a cookie with the correct =0A>in=
fo, the menu ends up with a "no cookie found" error, and the logs show =0A=
>neither the authorization handler nor app are seeing the cookie. Hitting=
=0A>refresh on the menu shows both handlers seeing the cookie and the men=
u comes up =0A>correctly.=0A> > =0A> > I've tried using both CGI::Cookie a=
nd Apache2::Cookie; I get the same =0A>problem either way. Currently the =
authentication handler sets the cookie as =0A>follows:=0A> > =0A> > my $co=
okie =3D Apache2::Cookie->new($r, -name =3D> 'ls_authentication', =
=0A> value =3D> { user_id =3D> $user, digest =3D> crypt($password=
, $salt), =0A>role_id =3D> $ur{role_id}, clients =3D> $client_list });=0A>=
> if ($cookie) {=0A> > $cookie->bake($r);=0A> > } else {=0A> > =
warn "Unable to make cookie";=0A> > }=0A> > I get no warning, a=
nd the cookie looks fine in the browser's debug tool, =0A>but the next hand=
ler and app just don't see it. This is how I try and read it =0A>in the a=
uthorization handler:=0A> > =0A> > my $jar =3D Apache2::Cookie::J=
ar->new($r);=0A> > my $cookie =3D $jar->cookies('ls_authentication=
');=0A> > if ($cookie) {=0A> > $have_cookie =3D 1;=0A=
> > my %fields =3D $cookie->value;=0A> > if ($fie=
lds{'user_id'}) {=0A> > $user =3D $fields{'user_id'};=0A> =
> }=0A> > if ( $fields{'role_id'} ) {=0A> > =
$user_role =3D $fields{'role_id'};=0A> > }=0A> > =
if ( $fields{'clients'} ) {=0A> > @user_client=
s =3D split(/,/, $fields{'clients'}); # turn =0A>client list back into arr=
ay=0A> > }=0A> > warn "AUTHORIZATION: found cookie=
, user ID =3D $user, user role =3D =0A>$user_role" if $DEBUG;=0A> > =
} else {=0A> > warn "AUTHORIZATION: NO COOKIE FOUND" if $DE=
BUG;=0A> > }=0A> > =0A> > =0A> > I'm running Perl 5.12.1, Apache 2.=
2.17 and libapreq2 2.13 built from =0A>source. Is using 'bake' insufficie=
nt to make the cookie visible by the next =0A>handler? I've tried using b=
oth=0A> > $r->err_headers_out->set('Set-Cookie', $cookie);=0A> > and=0A> =
> $r->err_headers_out->addt('Set-Cookie', $cookie);=0A> > but I get the =
same problem. =0A> > Does anyone know of any up to date demos of using co=
okies in mod_perl2 =0A>authentication handlers? =0A>=0A> =0A> =0A =