package CGI::Lazy::Authn;
use strict;
use CGI::Lazy::Globals;
use Digest::MD5;
#----------------------------------------------------------------------------------------
sub activeField {
my $self = shift;
return $self->{_activeField};
}
#----------------------------------------------------------------------------------------
sub authenticate {
my $self = shift;
my $extraFields = $self->extraFields;
my @extraFields;
my @binds;
my $username = $self->q->param($self->userField);
my $passwd = $self->q->param($self->passwdField);
return unless $username && $passwd;
$passwd = $self->passwdhash($username, $passwd);
push @binds, $username;
push @binds, $passwd;
#$self->q->util->debug->edump($passwd);
foreach my $webfield (keys %$extraFields) {
push @extraFields, $extraFields->{$webfield};
push @binds, $self->q->param($webfield);
}
my $query = 'select * from '. $self->table. ' where '. $self->userField . ' = ? and '. $self->passwdField . ' = ? and '. $self->activeField .' = 1 ';
foreach (@extraFields) {
$query .= " and $_ = ?";
}
my $result = $self->q->db->gethashlist($query, @binds);
if ($result->[0]) {
$self->q->session->data->authn({username => $username, authenticated => 1, id => $result->[0]->{$self->primarykey}});
return 1;
} else {
return 0;
}
}
#----------------------------------------------------------------------------------------
sub check {
my $self = shift;
my $session = $self->q->session;
if (!$session->expired && $session->data->authn && $session->data->authn->{username} && $session->data->authn->{authenticated}) {
return 1;
} else {
if ($self->authenticate) {
return $self->authenticate;
} else {
return $self->redirectLogin;
}
}
}
#----------------------------------------------------------------------------------------
sub extraFields {
my $self = shift;
return $self->{_extraFields};
}
#----------------------------------------------------------------------------------------
sub q {
my $self = shift;
return $self->{_q};
}
#----------------------------------------------------------------------------------------
sub new {
my $class = shift;
my $q = shift;
my $self = {
_q => $q,
};
$self->{_table} = $q->plugin->authn->{table};
$self->{_template} = $q->plugin->authn->{template};
$self->{_primarykey} = $q->plugin->authn->{primarykey};
$self->{_salt} = $q->plugin->authn->{salt};
$self->{_extraFields} = $q->plugin->authn->{extraFields};
$self->{_userField} = $q->plugin->authn->{userField} || 'username';
$self->{_passwdField} = $q->plugin->authn->{passwdField} || $q->plugin->authn->{passwordField} || 'password';
$self->{_activeField} = $q->plugin->authn->{activeField} || 'active';
bless $self, $class;
die "Cannot use Authn without Session. Please enable Session plugin" unless $self->q->session;
return $self;
}
#----------------------------------------------------------------------------------------
sub passwdField {
my $self = shift;
return $self->{_passwdField};
}
#----------------------------------------------------------------------------------------
sub passwdhash {
my $self = shift;
my $username = shift;
my $passwd = shift;
return Digest::MD5::md5_base64($username.$passwd.$self->salt);
}
#----------------------------------------------------------------------------------------
sub primarykey {
my $self = shift;
return $self->{_primarykey};
}
#----------------------------------------------------------------------------------------
sub redirectLogin {
my $self = shift;
my $tmplvars = {};
print $self->q->template($self->template)->process($tmplvars);
return;
}
#----------------------------------------------------------------------------------------
sub salt {
my $self = shift;
return $self->{_salt};
}
#----------------------------------------------------------------------------------------
sub table {
my $self = shift;
return $self->{_table};
}
#----------------------------------------------------------------------------------------
sub template {
my $self = shift;
return $self->{_template};
}
#----------------------------------------------------------------------------------------
sub userField {
my $self = shift;
return $self->{_userField};
}
1
__END__
=head1 LEGAL
#===========================================================================
Copyright (C) 2008 by Nik Ogura. All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
Bug reports and comments to nik.ogura@gmail.com.
#===========================================================================
=head1 NAME
CGI::Lazy::Authn
=head1 SYNOPSIS
use CGI::Lazy;
my $q = CGI::Lazy->new({
tmplDir => '/templates',
jsDir => '/js',
cssDir => '/css',
imgDir => '/css',
buildDir => '/tmp',
plugins => {
dbh => {
dbDatasource => 'dbi:mysql:somedb:localhost',
dbUser => 'luser',
dbPasswd => 's3cr3t',
dbArgs => {RaiseError => 1},
},
session => {
sessionTable => 'session',
sessionCookie => 'frobnitz',
saveOnDestroy => 1,
expires => '+15m',
},
authn => {
table => 'user',
primarykey => 'user_id',
template => 'login.tmpl',
salt => '234998fhgsldkj#$^',
userField => 'username',
passwdField => 'password',
activeField => 'active',
extraFields => {
country => country,
}
},
},
});
return unless $q->authn->check;
=head1 DESCRIPTION
CGI::Lazy Authentication module. Draws much of its inspiration from CGI::Auth. Put the $q->authn->check call in your CGI, if theres a current authenticated session, it will return true. If not, it will print the login template specified and return false.
The intended minimum database structure is as follows:
create table user (user_id int(10) unsigned not null auto_increment primary key, username varchar(50), password(varchar(25), active bool); #mysql
=head2 CONFIGURATION
Required Arguments:
table => 'table_name', #name of user table
primarykey => 'field_name', #name of primary key field on above table.
template => 'login.tmpl', #name of template for logins
salt => 'asdf9234ml@#4234', #unique identifying string for this application. Passwords are stored as md5 hashes of $username.$passwd.$salt .
userField => 'username', #name of username field. Defaults to 'username'
passwdField => 'password', #name of password field. Defaults to 'password' needs to be varchar and at least 22 characters wide.
activeField => 'active', #name of field that flags a user as active. Defaults to 'active'. Assumes '1' means active.
Optional Arguments:
extraFields => { #any other fields you want to authenticate on. If set, will authenticate on username, passwd, and every other field set here.
webname => fieldname, #first value is the name of the web control, second is the name of the field in the db
webname2 => fieldname2,
}
=head1 METHODS
=head2 check
Call this in your cgi to check if an authenticated session is present. Returns 1 if session is valid, and authenticated. Returns 0 otherwise; If authentication fails, prints the login template.
=head2 passwdhash (username, password)
Takes username, password, and salt from config and generates hashed value for storage in the db.
=head3 username
The username
=head3 password
The cleartext password.
=cut