Commit 1f0b9ed1 authored by Clément OUDOT's avatar Clément OUDOT
Browse files

First implementation of Auth/UserDB/PasswordDB DBI

parent 4b6e7ec1
...@@ -77,6 +77,7 @@ example/skins/pastel/styles.css ...@@ -77,6 +77,7 @@ example/skins/pastel/styles.css
example/slavePortal.pl example/slavePortal.pl
lib/Lemonldap/NG/Portal.pm lib/Lemonldap/NG/Portal.pm
lib/Lemonldap/NG/Portal/_i18n.pm lib/Lemonldap/NG/Portal/_i18n.pm
lib/Lemonldap/NG/Portal/_DBI.pm
lib/Lemonldap/NG/Portal/_LDAP.pm lib/Lemonldap/NG/Portal/_LDAP.pm
lib/Lemonldap/NG/Portal/_Multi.pm lib/Lemonldap/NG/Portal/_Multi.pm
lib/Lemonldap/NG/Portal/_Proxy.pm lib/Lemonldap/NG/Portal/_Proxy.pm
...@@ -85,6 +86,7 @@ lib/Lemonldap/NG/Portal/_SAML.pm ...@@ -85,6 +86,7 @@ lib/Lemonldap/NG/Portal/_SAML.pm
lib/Lemonldap/NG/Portal/_SOAP.pm lib/Lemonldap/NG/Portal/_SOAP.pm
lib/Lemonldap/NG/Portal/_WebForm.pm lib/Lemonldap/NG/Portal/_WebForm.pm
lib/Lemonldap/NG/Portal/AuthApache.pm lib/Lemonldap/NG/Portal/AuthApache.pm
lib/Lemonldap/NG/Portal/AuthDBI.pm
lib/Lemonldap/NG/Portal/AuthCAS.pm lib/Lemonldap/NG/Portal/AuthCAS.pm
lib/Lemonldap/NG/Portal/AuthLA.pm lib/Lemonldap/NG/Portal/AuthLA.pm
lib/Lemonldap/NG/Portal/AuthLDAP.pm lib/Lemonldap/NG/Portal/AuthLDAP.pm
...@@ -98,10 +100,12 @@ lib/Lemonldap/NG/Portal/Menu.pm ...@@ -98,10 +100,12 @@ lib/Lemonldap/NG/Portal/Menu.pm
lib/Lemonldap/NG/Portal/Notification.pm lib/Lemonldap/NG/Portal/Notification.pm
lib/Lemonldap/NG/Portal/Notification/DBI.pm lib/Lemonldap/NG/Portal/Notification/DBI.pm
lib/Lemonldap/NG/Portal/Notification/File.pm lib/Lemonldap/NG/Portal/Notification/File.pm
lib/Lemonldap/NG/Portal/PasswordDBDBI.pm
lib/Lemonldap/NG/Portal/PasswordDBLDAP.pm lib/Lemonldap/NG/Portal/PasswordDBLDAP.pm
lib/Lemonldap/NG/Portal/SAMLIssuer.pm lib/Lemonldap/NG/Portal/SAMLIssuer.pm
lib/Lemonldap/NG/Portal/SharedConf.pm lib/Lemonldap/NG/Portal/SharedConf.pm
lib/Lemonldap/NG/Portal/Simple.pm lib/Lemonldap/NG/Portal/Simple.pm
lib/Lemonldap/NG/Portal/UserDBDBI.pm
lib/Lemonldap/NG/Portal/UserDBEnv.pm lib/Lemonldap/NG/Portal/UserDBEnv.pm
lib/Lemonldap/NG/Portal/UserDBLDAP.pm lib/Lemonldap/NG/Portal/UserDBLDAP.pm
lib/Lemonldap/NG/Portal/UserDBMulti.pm lib/Lemonldap/NG/Portal/UserDBMulti.pm
......
##@file
# DBI authentication backend file
##@class
# LDAP authentication backend class
package Lemonldap::NG::Portal::AuthDBI;
use Lemonldap::NG::Portal::Simple;
use base qw(Lemonldap::NG::Portal::_WebForm Lemonldap::NG::Portal::_DBI);
our $VERSION = '0.1';
## @apmethod int authInit()
# Check DBI paramaters
#@return Lemonldap::NG::Portal constant
sub authInit {
my $self = shift;
unless ( $self->{dbiAuthChain}
and $self->{dbiAuthTable}
and $self->{dbiAuthUser}
and $self->{dbiAuthPassword}
and $self->{dbiAuthLoginCol}
and $self->{dbiAuthPasswordCol}
) {
$self->lmLog("Missing configuration parameters for DBI authentication", 'error');
return PE_ERROR;
}
PE_OK;
}
## @apmethod int authenticate()
# Find row in DBI backend with user and password criterions
#@return Lemonldap::NG::Portal constant
sub authenticate {
my $self = shift;
# Connect
my $dbh = $self->dbh( $self->{dbiAuthChain}, $self->{dbiAuthUser}, $self->{dbiAuthPassword} );
return PE_ERROR unless $dbh;
# Check credentials
my $table = $self->{dbiAuthTable};
my $loginCol = $self->{dbiAuthLoginCol};
my $passwordCol = $self->{dbiAuthPasswordCol};
my $user = $self->{user};
my $password;
# Manage password hash
if ( $self->{dbiAuthPasswordHash} =~ /^(md5|sha|sha1)$/i ) {
$self->lmLog( "Using ".uc($self->{dbiAuthPasswordHash})." to hash password", 'debug' );
$password = uc($self->{dbiAuthPasswordHash})."('".$self->{password}."')";
} else {
$self->lmLog( "No valid password hash, using clear text for password", 'debug' );
$password = "'".$self->{password}."'";
}
my $sth = $dbh->prepare("SELECT $loginCol FROM $table WHERE $loginCol='$user' AND $passwordCol=$password");
$sth->execute();
my @rows = $sth->fetchrow_array();
if ($#rows eq 0) {
$self->lmLog( "One row returned by SQL query", 'debug' );
return PE_OK;
} else {
$self->lmLog( "Bad password for $user", 'error' );
return PE_BADCREDENTIALS;
}
}
1;
...@@ -9,18 +9,13 @@ use strict; ...@@ -9,18 +9,13 @@ use strict;
use warnings; use warnings;
require Lemonldap::NG::Common::CGI; require Lemonldap::NG::Common::CGI;
use Lemonldap::NG::Portal::SharedConf; use Lemonldap::NG::Portal::SharedConf;
use Lemonldap::NG::Portal::_LDAP 'ldap'; #link protected ldap Object used to change passwords only
use XML::LibXML; use XML::LibXML;
use Lemonldap::NG::Common::Safelib; #link protected safe Safe object use Lemonldap::NG::Common::Safelib; #link protected safe Safe object
use Safe; use Safe;
use Lemonldap::NG::Portal::PasswordDBLDAP; #inherits
#inherits Net::LDAP::Control::PasswordPolicy #inherits Net::LDAP::Control::PasswordPolicy
*_modifyPassword = *Lemonldap::NG::Portal::PasswordDBLDAP::modifyPassword; our $VERSION = '0.3';
*_passwordDBInit = *Lemonldap::NG::Portal::PasswordDBLDAP::passwordDBInit;
our $VERSION = '0.2';
### ACCESS CONTROL DISPLAY SYSTEM ### ACCESS CONTROL DISPLAY SYSTEM
...@@ -111,6 +106,21 @@ sub new { ...@@ -111,6 +106,21 @@ sub new {
$self->{portalObject}->{'user'} = $self->{portalObject}->{'user'} =
$self->{portalObject}->{sessionInfo}->{'_user'}; $self->{portalObject}->{sessionInfo}->{'_user'};
# Password modification functions (TODO merge Menu.pm in Simple.pm to inherits those functions)
if ( exists $self->{portalObject}->{passwordDB} and $self->{portalObject}->{passwordDB} =~ /DBI/i ) {
use Lemonldap::NG::Portal::PasswordDBDBI; #inherits
use Lemonldap::NG::Portal::_DBI; #link protected ldap Object used to change passwords only
*_modifyPassword = *Lemonldap::NG::Portal::PasswordDBDBI::modifyPassword;
*_passwordDBInit = *Lemonldap::NG::Portal::PasswordDBDBI::passwordDBInit;
} else {
# Default to LDAP
use Lemonldap::NG::Portal::PasswordDBLDAP; #inherits
use Lemonldap::NG::Portal::_LDAP 'ldap'; #link protected ldap Object used to change passwords only
*_modifyPassword = *Lemonldap::NG::Portal::PasswordDBLDAP::modifyPassword;
*_passwordDBInit = *Lemonldap::NG::Portal::PasswordDBLDAP::passwordDBInit;
}
# Change password (only if newpassword submitted) # Change password (only if newpassword submitted)
$self->{error} = &_passwordDBInit( $self->{portalObject} ) $self->{error} = &_passwordDBInit( $self->{portalObject} )
if $self->{portalObject}->{'newpassword'}; if $self->{portalObject}->{'newpassword'};
...@@ -181,6 +191,7 @@ sub displayTab { ...@@ -181,6 +191,7 @@ sub displayTab {
32, #PE_PP_GRACE 32, #PE_PP_GRACE
33, #PE_PP_EXP_WARNING 33, #PE_PP_EXP_WARNING
34, #PE_PASSWORD_MISMATCH 34, #PE_PASSWORD_MISMATCH
39, #PE_BADOLDPASSWORD
) )
) )
) )
......
##@file
# DBI password backend file
##@class
# DBI password backend class
package Lemonldap::NG::Portal::PasswordDBDBI;
use Lemonldap::NG::Portal::Simple;
use Lemonldap::NG::Portal::AuthDBI; #inherits
use base qw(Lemonldap::NG::Portal::_DBI);
our $VERSION = '0.1';
*passwordDBInit = *Lemonldap::NG::Portal::AuthDBI::authInit;
## @apmethod int modifyPassword()
# @return Lemonldap::NG::Portal constant
sub modifyPassword {
my $self = shift;
# Exit if no password change requested
return PE_OK unless ( $self->{newpassword} );
# Verify confirmation password matching
return PE_PASSWORD_MISMATCH unless ( $self->{newpassword} eq $self->{confirmpassword} );
# Connect
my $dbh = $self->dbh( $self->{dbiAuthChain}, $self->{dbiAuthUser}, $self->{dbiAuthPassword} );
return PE_ERROR unless $dbh;
my $table = $self->{dbiAuthTable};
my $loginCol = $self->{dbiAuthLoginCol};
my $passwordCol = $self->{dbiAuthPasswordCol};
my $user = $self->{sessionInfo}->{_user};
my $password;
# Check old passord
if ( $self->{oldpassword} ) {
# Manage password hash (TODO in _DBI.pm)
if ( $self->{dbiAuthPasswordHash} =~ /^(md5|sha|sha1)$/i ) {
$self->lmLog( "Using ".uc($self->{dbiAuthPasswordHash})." to hash password", 'debug' );
$password = uc($self->{dbiAuthPasswordHash})."('".$self->{oldpassword}."')";
} else {
$self->lmLog( "No valid password hash, using clear text for password", 'debug' );
$password = "'".$self->{oldpassword}."'";
}
my $sth = $dbh->prepare("SELECT $loginCol FROM $table WHERE $loginCol='$user' AND $passwordCol=$password");
$sth->execute();
my @rows = $sth->fetchrow_array();
if ($#rows eq 0) {
$self->lmLog( "One row returned by SQL query", 'debug' );
} else {
$self->lmLog( "Bad password for $user", 'error' );
return PE_BADOLDPASSWORD;
}
}
# Modify password
# Manage password hash (TODO in _DBI.pm)
if ( $self->{dbiAuthPasswordHash} =~ /^(md5|sha|sha1)$/i ) {
$self->lmLog( "Using ".uc($self->{dbiAuthPasswordHash})." to hash password", 'debug' );
$password = uc($self->{dbiAuthPasswordHash})."('".$self->{newpassword}."')";
} else {
$self->lmLog( "No valid password hash, using clear text for password", 'debug' );
$password = "'".$self->{newpassword}."'";
}
eval {
my $sth = $dbh->prepare("UPDATE $table SET $passwordCol=$password WHERE $loginCol='$user'");
$sth->execute();
};
if ($@) {
$self->lmLog( "DBI password modification error: $@", 'error' );
return PE_ERROR;
}
$self->lmLog( "Password changed for $user", 'debug' );
PE_PASSWORD_OK;
}
## @apmethod int resetPasswordByMail()
# Reset the password and send a mail.
# @return Lemonldap::NG::Portal constant
sub resetPasswordByMail {
my $self = shift;
# TODO
PE_OK;
}
1;
...@@ -236,8 +236,6 @@ sub setDefaultValues { ...@@ -236,8 +236,6 @@ sub setDefaultValues {
$self->{securedCookie} ||= 0; $self->{securedCookie} ||= 0;
$self->{cookieName} ||= "lemonldap"; $self->{cookieName} ||= "lemonldap";
$self->{authentication} ||= 'LDAP'; $self->{authentication} ||= 'LDAP';
$self->{userDB} ||= 'LDAP';
$self->{passwordDB} ||= 'LDAP';
$self->{authentication} =~ s/^ldap/LDAP/; $self->{authentication} =~ s/^ldap/LDAP/;
$self->{SMTPServer} ||= 'localhost'; $self->{SMTPServer} ||= 'localhost';
$self->{mailLDAPFilter} ||= '(&(mail=$mail)(objectClass=inetOrgPerson))'; $self->{mailLDAPFilter} ||= '(&(mail=$mail)(objectClass=inetOrgPerson))';
...@@ -245,6 +243,16 @@ sub setDefaultValues { ...@@ -245,6 +243,16 @@ sub setDefaultValues {
$self->{mailFrom} ||= "noreply@" . $self->{domain}; $self->{mailFrom} ||= "noreply@" . $self->{domain};
$self->{mailSubject} ||= "Change password request"; $self->{mailSubject} ||= "Change password request";
$self->{mailBody} ||= 'Your new password is $password'; $self->{mailBody} ||= 'Your new password is $password';
# Set default userDB and passwordDB to DBI if authentication is DBI
if ( $self->{authentication} =~ /DBI/i ) {
$self->{userDB} ||= "DBI";
$self->{passwordDB} ||= "DBI";
} else {
# Default to LDAP
$self->{userDB} ||= "LDAP";
$self->{passwordDB} ||= "LDAP";
}
} }
=begin WSDL =begin WSDL
......
## @file
# DBI userDB mechanism
## @class
# DBI userDB mechanism class
package Lemonldap::NG::Portal::UserDBDBI;
use strict;
use Lemonldap::NG::Portal::Simple;
our $VERSION = '0.1';
## @apmethod int userDBInit()
# Set default values
# @return Lemonldap::NG::Portal constant
sub userDBInit {
my $self = shift;
# DBI access to user is the same as authentication by default
$self->{dbiUserChain} ||= $self->{dbiAuthChain};
$self->{dbiUserUser} ||= $self->{dbiAuthUser};
$self->{dbiUserPassword} ||= $self->{dbiAuthPassword};
$self->{dbiUserTable} ||= $self->{dbiAuthTable};
$self->{userPivot} ||= $self->{dbiAuthLoginCol};
PE_OK;
}
## @apmethod int getUser()
# Do nothing
# @return Lemonldap::NG::Portal constant
sub getUser {
PE_OK;
}
## @apmethod int setSessionInfo()
# Get columns for each exportedVars
# @return Lemonldap::NG::Portal constant
sub setSessionInfo {
my $self = shift;
# Return if no data to collect
return PE_OK unless ( $self->{exportedVars} and ref( $self->{exportedVars} ) eq 'HASH' );
# Connect
my $dbh = $self->dbh( $self->{dbiUserChain}, $self->{dbiUserUser}, $self->{dbiUserPassword} );
return PE_ERROR unless $dbh;
my $table = $self->{dbiUserTable};
my $pivot = $self->{userPivot};
my $sth = $dbh->prepare("SELECT * FROM $table WHERE $pivot='".$self->{user}."'");
$sth->execute();
my $result = $sth->fetchrow_hashref();
foreach ( keys %{ $self->{exportedVars} } ) {
if ( exists $result->{ $self->{exportedVars}->{$_} } ) {
$self->{sessionInfo}->{$_} = $result->{ $self->{exportedVars}->{$_} };
}
}
PE_OK;
}
## @apmethod int setGroups()
# Do nothing
# @return Lemonldap::NG::Portal constant
sub setGroups {
PE_OK;
}
1;
##@file
# DBI common functions
##@class
# DBI common functions
package Lemonldap::NG::Portal::_DBI;
use DBI;
use base qw(Exporter);
use Lemonldap::NG::Portal::Simple;
use strict;
our @EXPORT = qw(dbh);
our $VERSION = '0.1';
## @method protected Lemonldap::NG::Portal::_DBI dbh()
# @param dbiChain
# @param dbiUser
# @param dbiPassword
# @return dbh object
sub dbh {
my $self = shift;
my $dbiChain = shift;
my $dbiUser = shift;
my $dbiPassword = shift;
my $dbh;
# Open connection to database
eval {
$dbh = DBI->connect_cached(
$dbiChain,
$dbiUser,
$dbiPassword,
{ RaiseError => 1, },
);
};
if ($@) {
$self->lmLog("DBI connection error: $@", 'error');
return 0;
}
return $dbh;
}
1;
...@@ -75,7 +75,7 @@ __END__ ...@@ -75,7 +75,7 @@ __END__
# * PE_NOTIFICATION 36 # * PE_NOTIFICATION 36
# * PE_BADURL 37 # * PE_BADURL 37
# * PE_NOSCHEME 38 # * PE_NOSCHEME 38
# * PE_BASOLDPASSWORD 39 # * PE_BADOLDPASSWORD 39
# Not used in errors: # Not used in errors:
# * PE_DONE -1 # * PE_DONE -1
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment