Commit 75c1f0fe authored by Clément OUDOT's avatar Clément OUDOT

LEMONLDAP::NG : Reset password by mail (new functionnality)

parent da49976a
......@@ -15,6 +15,7 @@ use constant USER_CAN_CHANGE_PASSWORD => 1;
use constant REQUIRE_OLDPASSWORD => 0;
use constant DISPLAY_LOGOUT => 1;
use constant AUTOCOMPLETE => "on";
use constant DISPLAY_RESETPASSWORD => "1";
my $portal = Lemonldap::NG::Portal::SharedConf->new(
{
......@@ -66,6 +67,22 @@ my $portal = Lemonldap::NG::Portal::SharedConf->new(
# (beware of compatibility with LDAP Password Policy)
#ldapSetPassword => 1,
# RESET PASSWORD BY MAIL
# SMTP server (default to localhost), set to '' to use default mail service
#SMTPServer => "localhost",
# Mail From address
#mailFrom => "noreply@test.com",
# Mail subject
#mailSubject => "Password reset",
# LDAP filter to use
#mailLDAPFilter => '(&(mail=$mail)(objectClass=inetOrgPerson))',
# Random regexp
#randomPasswordRegexp => '[A-Z]{3}[a-z]{5}.\d{2}',
# LDAP GROUPS
# Set the base DN of your groups branch
#ldapGroupBase => 'ou=groups,dc=example,dc=com',
......@@ -196,7 +213,8 @@ else {
$template->param( DISPLAY_PASSWORD => 1 );
}
else {
$template->param( DISPLAY_FORM => 1 );
$template->param( DISPLAY_FORM => 1 );
$template->param( DISPLAY_RESETPASSWORD => 1 );
}
print $portal->header('text/html; charset=utf-8');
......
......@@ -34,6 +34,28 @@
</form>
</TMPL_IF>
<TMPL_IF NAME="DISPLAY_RESETPASSWORD">
<form action="#" method="post" class="login">
<h3><lang en="Forgot your password?" fr="Mot de passe oubli&eacute; ?"/></h3>
<table>
<tr><th><lang en="Mail" fr="Adresse mail"/></th>
<td><input name="mail" type="text"/></td>
</tr>
<tr><td colspan="2">
<div class="buttons">
<button type="submit" class="positive">
<img src="skins/cqappli/accept.png" alt="" />
<lang en="Send me a new password" fr="Envoyez-moi un nouveau mot de passe" />
</button>
</div></td></tr>
</table>
</form>
</TMPL_IF>
<TMPL_INCLUDE NAME="password.tpl">
<TMPL_IF NAME="LOGOUT_URL">
......
......@@ -146,6 +146,11 @@ background:#FFFFFF url("../common/key.png") 5px 5px no-repeat;
padding-left: 25px;
}
form input[name=mail] {
background:#FFFFFF url("../common/email.png") 5px 5px no-repeat;
padding-left: 25px;
}
/* BUTTONS */
/* See http://particletree.com/features/rediscovering-the-button-element/ */
......
......@@ -49,4 +49,81 @@ sub modifyPassword {
PE_OK;
}
## @apmethod int resetPasswordByMail()
# Reset the password and send a mail.
# @return Lemonldap::NG::Portal constant
sub resetPasswordByMail {
my $self = shift;
# Exit method if no mail
return PE_OK unless ( $self->{mail} );
unless ( $self->ldap ) {
return PE_LDAPCONNECTFAILED;
}
# Set the dn unless done before
unless ( $self->{dn} ) {
my $tmp = $self->_subProcess(qw(_formateFilter _search));
return $tmp if ($tmp);
}
$self->lmLog("Reset password request for ".$self->{dn},'debug');
# Check the required modules before changing password
eval {require String::Random};
if ($@) {
$self->lmLog("Module String::Random not found in @INC",'error' );
return PE_ERROR;
}
eval {require MIME::Lite};
if ($@) {
$self->lmLog("Module MIME::Lite not found in @INC",'error' );
return PE_ERROR;
}
# Generate a complex password
my $password_regexp = $self->{randomPasswordRegexp} || "[A-Z]{3}[a-z]{5}.\d{2}";
my $random = new String::Random;
my $password = $random->randregex($password_regexp);
$self->lmLog("Generated password: ".$password,'debug');
# Call the modify password method
my $pe_error = $self->ldap->userModifyPassword( $self->{dn}, $password, $password );
return $pe_error unless $pe_error = PE_PASSWORD_OK;
# If Password Policy, set the PwdReset flag
if ( $self->{ldapPpolicyControl} ) {
my $result = $self->ldap->modify( $self->{dn}, replace => { 'pwdReset' => 'TRUE' } );
unless ( $result->code == 0) {
$self->lmLog("LDAP modify pwdReset error: ".$result->code,'error');
return PE_LDAPERROR;
}
$self->lmLog("pwdReset set to TRUE",'debug');
}
# Send new password by mail
eval {
my $message = MIME::Lite->new(
From => $self->{mailFrom},
To => $self->{mail},
Subject => $self->{mailSubject},
Type => "TEXT",
Data => "Your new password: $password\n",
);
$self->{SMTPServer} ? $message->send("smtp",$self->{SMTPServer}) : $message->send();
};
if ($@) {
$self->lmLog("Send message failed: $@",'error');
return PE_ERROR;
}
$self->lmLog("New password sent to ".$self->{mail},'debug');
PE_PASSWORD_OK;
}
1;
......@@ -119,6 +119,7 @@ sub new {
$self->abort( "Configuration error",
"You've to indicate a domain for cookies" )
unless ( $self->{domain} );
my $domain = $self->{domain};
$self->{domain} =~ s/^([^\.])/.$1/;
$self->{securedCookie} ||= 0;
$self->{cookieName} ||= "lemonldap";
......@@ -130,6 +131,11 @@ sub new {
( $ENV{REQUEST_METHOD} eq 'POST' and not $self->param('newpassword') )
or $self->param('logout')
) ? 1 : 0;
$self->{SMTPServer} ||= 'localhost';
$self->{mailLDAPFilter} ||= '(&(mail=$mail)(objectClass=inetOrgPerson))';
$self->{randomPasswordRegexp} ||= '[A-Z]{3}[a-z]{5}.\d{2}';
$self->{mailFrom} ||= "noreply@".$domain;
$self->{mailSubject} ||= "Change password request";
# Authentication and userDB module are required and have to be in @ISA
foreach (qw(authentication userDB passwordDB)) {
......@@ -523,7 +529,7 @@ sub _deleteSession {
# - itself : controlUrlOrigin, controlExistingSession, setMacros, setGroups, store, buildCookie, log, autoredirect
# - authentication module : extractFormInfo, setAuthSessionInfo, authenticate
# - user database module : getUser, setSessionInfo
# - password database module : modifyPassword
# - password database module : modifyPassword, resetPasswordByMail
#@return 1 if user is all is OK, 0 if session isn't created or a notification has to be done
sub process {
my ($self) = @_;
......@@ -531,9 +537,9 @@ sub process {
$self->{error} = $self->_subProcess(
qw(controlUrlOrigin checkNotifBack controlExistingSession
SAMLForUnAuthUser authInit extractFormInfo userDBInit getUser
setAuthSessionInfo passwordDBInit modifyPassword setSessionInfo
setMacros setGroups authenticate store buildCookie checkNotification
SAMLForAuthUser autoRedirect)
setAuthSessionInfo passwordDBInit modifyPassword resetPasswordByMail
setSessionInfo setMacros setGroups authenticate store buildCookie
checkNotification SAMLForAuthUser autoRedirect)
);
$self->updateStatus;
return ( ( $self->{error} > 0 ) ? 0 : 1 );
......@@ -688,6 +694,8 @@ sub existingSession {
# . modifyPassword() : must be implemented in PasswordDB* module
# . resetPasswordByMail() : must be implemented in PasswordDB* module
##@apmethod int setSessionInfo()
# 9) Call setSessionInfo() in User* module and set ipAddr and startTime
#@return Lemonldap::NG::Portal constant
......
......@@ -31,12 +31,15 @@ sub getUser {
# @return Lemonldap::NG::Portal constant
sub formateFilter {
my $self = shift;
$self->{LDAPFilter} =
$self->{LDAPFilter} = $self->{mail} ?
$self->{mailLDAPFilter} :
$self->{AuthLDAPFilter}
|| $self->{LDAPFilter};
$self->lmLog( "LDAP submitted filter: ".$self->{LDAPFilter}, 'debug' );
$self->{LDAPFilter} ||= '(&(uid=$user)(objectClass=inetOrgPerson))';
$self->{LDAPFilter} =~ s/\$(user|_?password)/$self->{$1}/g;
$self->{LDAPFilter} =~ s/\$(user|_?password|mail)/$self->{$1}/g;
$self->{LDAPFilter} =~ s/\$(\w+)/$self->{sessionInfo}->{$1}/g;
$self->lmLog( "LDAP transformed filter: ".$self->{LDAPFilter}, 'debug' );
PE_OK;
}
......@@ -53,8 +56,9 @@ sub search {
scope => 'sub',
filter => $self->{LDAPFilter},
);
$self->lmLog( "LDAP Search with base: ".$self->{ldapBase}." and filter: ".$self->{LDAPFilter}, 'debug' );
if ( $mesg->code() != 0 ) {
$self->lmLog( $mesg->error, 'error' );
$self->lmLog( "LDAP Search error: ".$mesg->error, 'error' );
return PE_LDAPERROR;
}
unless ( $self->{entry} = $mesg->entry(0) ) {
......
......@@ -21,11 +21,12 @@ sub authInit {
sub extractFormInfo {
my $self = shift;
return PE_FIRSTACCESS
unless ( $self->param('user') );
unless ( $self->param('user') || $self->param('mail') );
return PE_FORMEMPTY
unless ( length( $self->{'user'} = $self->param('user') ) > 0
&& ( ( length( $self->{'password'} = $self->param('password') ) > 0 )
|| ( length( $self->{'newpassword'} = $self->param('newpassword') ) > 0 ) ) );
unless ( ( ( length( $self->{'user'} = $self->param('user') ) > 0 )
&& ( ( length( $self->{'password'} = $self->param('password') ) > 0 )
|| ( length( $self->{'newpassword'} = $self->param('newpassword') ) > 0 ) ) )
|| ( length( $self->{'mail'} = $self->param('mail') ) > 0 ) );
$self->{'oldpassword'} = $self->param('oldpassword');
$self->{'confirmpassword'} = $self->param('confirmpassword');
PE_OK;
......
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