#!/bin/perl use CGI; use CGI::Carp qw(warningsToBrowser fatalsToBrowser); use CGI::Session qw(-ip-match); use CGI::Cookie; #$CGI::Session::IP_MATCH=1; package auth; use warnings "all"; use strict; use Data::Dumper; use Authen::Passphrase::BlowfishCrypt; use time; require Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw(get_user login logout crypt_password); our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] ); my $defaultExpiration=60; my $tmp_dir='/var/tmp/'; my $debug=0; sub debug; sub get_user{ my $cgi=shift; my $config=shift; my %parms=$cgi->Vars(); my $parms=\%parms; debug("get_user")if ($debug); # login or logout on action if (defined $parms->{action}){ if ($parms->{action} eq 'login'){ my $user=login($cgi, $config, $parms->{user}, $parms->{password}); $cgi->delete('user','password','uri','action'); return $user; }elsif($parms->{action} eq 'logout'){ logout($cgi); $cgi->delete('user','password','uri','action'); return undef; } } # read session id from cookie my $session_id=read_cookie($cgi); # login if no cookie found return show_login_form($parms->{user}, 'Please login') unless defined $session_id; # read session my $session=read_session($session_id); # login if user not found return show_login_form($parms->{user}, 'unknown User') unless defined $session; $parms->{user} = $session->{user}; $parms->{expires} = $session->{expires}; debug($parms->{expires}); return $session->{user}, $session->{expires}; } sub crypt_password{ my $password=shift; my $ppr = Authen::Passphrase::BlowfishCrypt->new( cost => 8, salt_random => 1, passphrase => $password ); return{ salt => $ppr->salt_base64, crypt => $ppr->as_crypt }; } sub login{ my $cgi=shift; my $config=shift; my $user=shift; my $password=shift; debug("login")if ($debug); #print STDERR "login $user $password\n"; my $result = authenticate($config, $user, $password); #print STDERR Dumper($result); return show_login_form($user,'Could not authenticate you') unless defined $result; return unless defined $result->{login}eq '1'; my $timeout=$result->{timeout} || $defaultExpiration; $timeout='+'.$timeout.'m'; my $session_id=create_session($user, $password, $timeout); return $user if(create_cookie($cgi, $session_id, $timeout)); return undef; } sub logout{ my $cgi=shift; my $session_id=read_cookie($cgi); debug("logout")if ($debug); unless(delete_session($session_id)){ return show_login_form('Cant delete session', 'logged out'); }; unless(delete_cookie($cgi)){ return show_login_form('Cant remove cookie', 'logged out'); } my $uri=$ENV{HTTP_REFERER}||''; $uri=~s/action=logout//g; print $cgi->redirect($uri); # return show_login_form('', 'logged out'); } #read and write data from browser, http://perldoc.perl.org/CGI/Cookie.html sub create_cookie{ my $cgi=shift; my $session_id=shift; my $timeout=shift; #debug("create_cookie")if ($debug); my $cookie = CGI::Cookie->new( -name => 'sessionID', -value => $session_id, -expires => $timeout, # -domain => '.capricorn.com', # -path => '/agenda/admin/', -secure => 1 ); print "Set-Cookie: ",$cookie->as_string,"\n"; print STDERR "#Set-Cookie: ",$cookie->as_string,"\n"; # print $cgi->header( -cookie => $cookie ); return 1; } sub read_cookie{ my $cgi=shift; debug("read_cookie")if ($debug); my %cookie = CGI::Cookie->fetch; debug("cookies: ".Dumper(\%cookie))if ($debug); my $cookie=$cookie{'sessionID'}; debug("cookie: ".$cookie)if ($debug); return undef unless (defined $cookie); my $session_id= $cookie->value || undef; debug("sid: ".$session_id)if ($debug); return $session_id; #return $cgi->cookie('sessionID') || undef; }; sub delete_cookie{ my $cgi=shift; debug("delete_cookie")if ($debug); my $cookie = $cgi->cookie( -name => 'sessionID', -value => '', -expires => '+1s' ); print $cgi->header( -cookie => $cookie ); return 1; } #read and write server-side session data sub create_session{ my $user=shift; my $password=shift; my $expiration=shift; debug("create_session")if ($debug); my $session = new CGI::Session(undef, undef, {Directory=>$tmp_dir}); $session->expire($expiration); $session->param("user", $user); $session->param("pid", $$); # $session->param("password", $password); return $session->id(); } sub read_session{ my $session_id=shift; debug("read_session")if $debug; return undef unless(defined $session_id); debug("read_session2")if $debug; my $session = new CGI::Session(undef, $session_id, {Directory=>$tmp_dir}); return undef unless defined $session; debug("read_session3")if $debug; my $user = $session->param("user") || undef; return undef unless defined $user; my $expires = time::time_to_datetime($session->param("_SESSION_ATIME")+$session->param("_SESSION_ETIME")); return { user => $user, expires => $expires } } sub delete_session{ my $session_id=shift; debug("delete_session")if ($debug); return undef unless(defined $session_id); my $session = new CGI::Session(undef, $session_id, {Directory=>$tmp_dir}); $session->delete(); return 1; } #check user authentication sub authenticate{ my $config=shift; my $user=shift; my $password=shift; $config->{access}->{write}=0; my $dbh = db::connect($config); my $query = qq{ select * from calcms_users where name=? }; my $bind_values = [$user]; #print STDERR "query:".Dumper($query).Dumper($bind_values); my $users = db::get($dbh,$query,$bind_values); #print STDERR "result:".Dumper($users); if (scalar(@$users) != 1){ print STDERR "auth: did not find user '$user'\n"; return undef; } #print STDERR Dumper($users); my $salt=$users->[0]->{salt}; my $ppr = Authen::Passphrase::BlowfishCrypt->from_crypt( $users->[0]->{pass}, $users->[0]->{salt} ); return undef unless $ppr->match($password); if($users->[0]->{disabled} == 1){ print STDERR "user '$user' is disabled\n"; return undef; } my $timeout = $users->[0]->{session_timeout} || 120; $timeout =10 if $timeout < 10; $timeout =12*60 if $timeout > 12*60; return { timeout => $timeout, login => 1 } } sub show_login_form{ my $user=shift||''; my $uri=$ENV{HTTP_REFERER}||''; my $message=shift||''; debug("show_login_form")if ($debug); print qq{Content-type:text/html
$message

user

password

}; return undef; } sub debug{ my $message=shift; print STDERR "$message\n" if $debug>0; } #do not delete last line! 1;