http://www.perlmonks.org?node_id=540986

jimbus has asked for the wisdom of the Perl Monks concerning the following question:

UPDATE I solved the issue, I was setting the path and domain incorrectly. It came down to old fashioned debugging and once I had the tools I needed, I was able to get it done. The tools were the liveHTTPheaders plugin listed below and FireFox's cookie viewer. Between the two, I was able to see the cookie hitting the header, then being saved to the browser and finally check the values to make sure it was what I needed. Many thanks to bart and eric256 for spoon feeding me the blatantly obvious... now to move it to https and add some digesting to the password.

Alright, I'm struggling a bit here and need a sanity check as well as an answer...

I'm using Apache2/mod_perl2/Mason I've been happy with mason, building my business logic and db layer stuff in perl modules, testing them with perl test scripts and then plugging them into the display page, it's all coming together quickly and elegantly... atleast compared the the JSP stuff I'm replacing. Now, I'm trying to do authentication and authorization and I'm starting to stumble.

Based on roles, I want to adjust what a user see on a page, though there will be some redirecting or limiting access. The user authentication and roll information come out of sepparate mysql tables (though not particularly relevant, this will be switch to the corporate LDAP at some point). I'm not currently interested in sessions for tracking or page customization, but again I have to temper this with the fact I am in a corporate setting and I don't have the final say.

I've been basing much of my design philosophy on masonbook.com's aprentice.perl.org example, but they seem to have left out a lot of the logic, or it is baked into the strange OO db they use, so I've been wandering off on my own. There's an autohandler that loads with every page that looks for a user cookie. If it finds the cookie, it digests the user info to see if it matches the digest stored in the cookie at login. If it does, it creates a user object with methods to look up roll information when needed. Otherwise, it assumes you are "Guest" and gives you guest privledges. The user object is in a perl module that has subs to validate the username and password againdst the DB and I will put subs to assess roles and such.

Where this is breaking down, is I can't seem to set or perhaps read the cookies I'm setting and the cookie mechanism seems very "black box"-ish, or at least I can't find any good debuging ideas on Apache2::cookie on cpan or google.

I'd also like to know if I'm approaching this in a sane manner to build things. I've tried googling and rifling the monastary and haven't come up with a good standard or even acceptable practices for this sort of thing. I find things that give specifics on this sort of thing, but not anything that helps me sort out what I want and whats a good way to do it.

Code:

Auth::User
#! /usr/local/perl package User; use strict; sub validate { my $self = (); shift; $self->{dbh} = shift; $self->{username} = shift; $self->{passwd} = shift; $self->{qstr} = "select count(user_name) from users where user_name = + \'$self->{username}\' and user_pass = \'$self->{passwd}\'"; $self->{error_msg} = "Invalid Login"; $self->{res} = undef; bless($self); my $q_stmt = $self->{dbh}->prepare($self->{qstr}); $q_stmt->execute(); my @data = $q_stmt->fetchrow_array(); if (@data[0] == 1) { $self->{res} = 1; } return($self); } sub guest { my $self = (); shift; $self->{dbh} = shift; $self->{username} = "Guest"; $self->{logged_in} = undef; $self->{passwd} = ""; bless($self); return($self); } sub is_logged_in { my $self = shift; return $self->{logged_in}; } 1;
autohandler
<%once> $AuthDBH = DBI->connect('dbi:mysql:authority:10.33.8.159', 'appadmin', + 'f00tbal l') or die "poop sandwich"; $RepDBH = DBI->connect('dbi:mysql:reports:10.33.8.159', 'appadmin', 'f +00tball') or die "poop sandwich"; use Auth::User; use Digest::SHA1; </%once> <%init> my %cookies = Apache2::Cookie->fetch($r); my $guest = User->guest; my $user; if (exists $cookies{user_login}) { my %user_info = $cookies{user_login}->value; if ( $user_info{used_id} && $user_info{MAC}) { my $MAC = Digest::SHA1::sha1_hex($user_info{user_id}, "Get the S1 +gnal!"); if ( $user_info{MAC} eq $MAC ) { $user = User->new($user_info{used_id}); } } } local $User = $user || $guest; $m->call_next </%init> <%flags> inherit=>undef </%flags>
Login
<%init> my $item; my $date; my @line; #Yes, I am sending a plain text password here... I'll digest it in SHA +1 in the next step my $res = User->validate($AuthDBH, $ARGS{username}, $ARGS{password}); my $url; if (length($ARGS{ret_url}) <= 1) { $url = "/index.html"; } if ($res->{res}) { my $MAC = Digest::SHA1::sha1_hex($ARGS{username}, "Get the S1gnal!"); Apache2::Cookie->new ( $r, -name => 'user_login', -value => { user_id => $ARGS{username}, MAC => $MAC }, -path => '/', -domain => 'ruth.dobson.net', -expires => '+1M', )->bake($r); } else { if (index($ARGS{ret_url}, '?') >= 0) { $url .= "&login_error=$res->{error_msg}"; } else { $url .= "?login_error=$res->{error_msg}"; } } $url= "/test.html"; $m->redirect($url); </%init> <%flags> inherit=> '/syshandler' </%flags>

--Jimbus aka Jim Babcock
Wireless Data Engineer and Geek Wannabe
jim-dot-babcock-at-usa-dot-com