You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Neil Conway <nc...@klamath.dyndns.org> on 2002/01/07 12:59:59 UTC
silly CGI::Cookie bug/frustrations
Hi all,
I've spent the last couple hours trying to debug a seemingly simple
piece of code. I've come up with something that seems puzzling (but it's
probably just too early in the morning for me) -- any clarification
would be appreciated.
The code I'm writing is a cookie-based authentication scheme, inspired
by Apache::TicketAccess from the Eagle book (thanks Doug & Lincoln!).
I'm sending the client the ticket cookie like so:
use constant TICKET_NAME => 'AdminTicket';
# ... lots of code
my $ticket = CGI::Cookie->new(-name => TICKET_NAME,
-path => '/'
# more stuff
);
$r->header_out('Set-Cookie' => $ticket);
Now, this seems to work fine. The browser is sent a cookie, and sends it
back to the server when it requests a page that requires authentication.
However, I can't seem to verify the cookie properly. Here's my
verification code:
sub verify_ticket {
my $self = shift;
my $r = $self->{_req};
print STDERR "Cookie: " . $r->header_in('Cookie') . "\n"; #DEBUG
my %cookies = CGI::Cookie->parse($r->header_in('Cookie'));
return (0, 'user has no cookies') unless %cookies;
#DEBUG
my $cookie_name;
foreach (keys %cookies) {
print STDERR "Cookie: [$_] -> [$cookies{$_}]\n";
print STDERR "Cookie name: [$_] ; Expected: [" . TICKET_NAME .
"]\n";
print STDERR "The cookies match.\n" if $_ eq TICKET_NAME;
$cookie_name = $_; # HACK: remember a valid hash key
}
# this does NOT work
#return (0, 'user has no ticket') unless $cookies{TICKET_NAME};
# this works, strangely
return (0, 'user has no ticket') unless $cookies{$cookie_name};
# lots more code
}
(As you can tell, I've been banging my head against the wall for a
while, inserting print statements ;-) ).
I get the following log output:
Cookie:
AdminTicket=ip&127.0.0.1&expires&15&hash&f6o%2BtYJ2AFm1aBy3plFrOigo1yg&user&nconway&time&1010403781
Cookie: [AdminTicket] ->
[AdminTicket=ip&127.0.0.1&expires&15&hash&f6o%2BtYJ2AFm1aBy3plFrOigo1yg&user&nconway&time&1010403781; path=/]
Cookie name: [AdminTicket] ; Expected: [AdminTicket]
The cookies match.
Now, this is as I expected it. However, the commented out code such as:
return (0, 'user has no ticket') unless $cookies{TICKET_NAME};
Doesn't work -- it seems to think that there is no such hash element as
TICKET_NAME.
Since there is only 1 cookie, I used the ugly hack above and iterated
through the keys of the hash and used the only actual hash element. The
weird that is that the value I get from this is 'eq' to TICKET_NAME --
yet, it works, but TICKET_NAME does not. IIRC, if I replace the
instances of TICKET_NAME with its literal value ('AdminTicket'), it also
does not work.
Would someone be kind enough to point out what I've missed? Because I'm
stumped...
Thanks in advance,
Neil
--
Neil Conway <ne...@rogers.com>
PGP Key ID: DB3C29FC
Re: silly CGI::Cookie bug/frustrations
Posted by Chip Turner <ct...@redhat.com>.
Here's a one-liner to show what's happening:
perl -le 'use constant FOO => "bar"; $a{bar} = 1; print "bar: ",
$a{bar}, " FOO: ", $a{FOO}, " +FOO: ", $a{+FOO}'
The "use constant" module does its magic via making a subroutine that
returns the appropriate value. So that means in the example above,
there is a sub in the main:: module called FOO() that always returns
the constant string "bar". You can also see this happen below:
perl -e '$a{time} = $a{+time} = 1; print "$_ => $a{$_}\n" foreach keys %a'
The trick in both places is to tell the aggressive Perl parser that
FOO and time are calls to a function, and not a literal string (like
$a{bar} is). The unary + does that, as would &FOO, FOO(), etc.
So your code will work if you make your return statement:
return (0, 'user has no ticket') unless $cookies{+TICKET_NAME};
Just Another Perl Oddity :)
Chip
Neil Conway <nc...@klamath.dyndns.org> writes:
> Hi all,
>
> I've spent the last couple hours trying to debug a seemingly simple
> piece of code. I've come up with something that seems puzzling (but it's
> probably just too early in the morning for me) -- any clarification
> would be appreciated.
>
> The code I'm writing is a cookie-based authentication scheme, inspired
> by Apache::TicketAccess from the Eagle book (thanks Doug & Lincoln!).
>
> I'm sending the client the ticket cookie like so:
>
> use constant TICKET_NAME => 'AdminTicket';
> # ... lots of code
> my $ticket = CGI::Cookie->new(-name => TICKET_NAME,
> -path => '/'
> # more stuff
> );
> $r->header_out('Set-Cookie' => $ticket);
>
> Now, this seems to work fine. The browser is sent a cookie, and sends it
> back to the server when it requests a page that requires authentication.
> However, I can't seem to verify the cookie properly. Here's my
> verification code:
>
> sub verify_ticket {
> my $self = shift;
> my $r = $self->{_req};
> print STDERR "Cookie: " . $r->header_in('Cookie') . "\n"; #DEBUG
> my %cookies = CGI::Cookie->parse($r->header_in('Cookie'));
>
> return (0, 'user has no cookies') unless %cookies;
> #DEBUG
> my $cookie_name;
> foreach (keys %cookies) {
> print STDERR "Cookie: [$_] -> [$cookies{$_}]\n";
> print STDERR "Cookie name: [$_] ; Expected: [" . TICKET_NAME .
> "]\n";
> print STDERR "The cookies match.\n" if $_ eq TICKET_NAME;
> $cookie_name = $_; # HACK: remember a valid hash key
> }
>
> # this does NOT work
> #return (0, 'user has no ticket') unless $cookies{TICKET_NAME};
> # this works, strangely
> return (0, 'user has no ticket') unless $cookies{$cookie_name};
>
> # lots more code
> }
>
> (As you can tell, I've been banging my head against the wall for a
> while, inserting print statements ;-) ).
>
> I get the following log output:
>
> Cookie:
> AdminTicket=ip&127.0.0.1&expires&15&hash&f6o%2BtYJ2AFm1aBy3plFrOigo1yg&user&nconway&time&1010403781
> Cookie: [AdminTicket] ->
> [AdminTicket=ip&127.0.0.1&expires&15&hash&f6o%2BtYJ2AFm1aBy3plFrOigo1yg&user&nconway&time&1010403781; path=/]
> Cookie name: [AdminTicket] ; Expected: [AdminTicket]
> The cookies match.
>
> Now, this is as I expected it. However, the commented out code such as:
>
> return (0, 'user has no ticket') unless $cookies{TICKET_NAME};
>
> Doesn't work -- it seems to think that there is no such hash element as
> TICKET_NAME.
>
> Since there is only 1 cookie, I used the ugly hack above and iterated
> through the keys of the hash and used the only actual hash element. The
> weird that is that the value I get from this is 'eq' to TICKET_NAME --
> yet, it works, but TICKET_NAME does not. IIRC, if I replace the
> instances of TICKET_NAME with its literal value ('AdminTicket'), it also
> does not work.
>
> Would someone be kind enough to point out what I've missed? Because I'm
> stumped...
>
> Thanks in advance,
>
> Neil
>
> --
> Neil Conway <ne...@rogers.com>
> PGP Key ID: DB3C29FC
>
--
Chip Turner cturner@redhat.com
Red Hat Network