2010-07-22 11:06:50 +02:00
|
|
|
## @file
|
2010-01-21 18:38:55 +01:00
|
|
|
# Module for password reset by mail
|
|
|
|
|
2010-07-22 11:06:50 +02:00
|
|
|
## @class Lemonldap::NG::Portal::MailReset
|
2010-01-21 18:38:55 +01:00
|
|
|
# Module for password reset by mail
|
|
|
|
package Lemonldap::NG::Portal::MailReset;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings;
|
|
|
|
|
2011-05-19 17:49:11 +02:00
|
|
|
our $VERSION = '1.1.0';
|
2010-01-21 18:38:55 +01:00
|
|
|
|
|
|
|
use Lemonldap::NG::Portal::Simple qw(:all);
|
|
|
|
use base qw(Lemonldap::NG::Portal::SharedConf Exporter);
|
2010-01-22 12:25:37 +01:00
|
|
|
use HTML::Template;
|
2011-05-27 16:08:49 +02:00
|
|
|
use Encode;
|
2011-06-01 12:22:28 +02:00
|
|
|
use POSIX;
|
2010-01-21 18:38:55 +01:00
|
|
|
|
2010-10-02 17:45:10 +02:00
|
|
|
#inherits Lemonldap::NG::Portal::_SMTP
|
|
|
|
|
2010-01-21 18:38:55 +01:00
|
|
|
*EXPORT_OK = *Lemonldap::NG::Portal::Simple::EXPORT_OK;
|
|
|
|
*EXPORT_TAGS = *Lemonldap::NG::Portal::Simple::EXPORT_TAGS;
|
|
|
|
*EXPORT = *Lemonldap::NG::Portal::Simple::EXPORT;
|
|
|
|
|
2010-07-22 11:06:50 +02:00
|
|
|
## @method boolean process()
|
2010-01-21 18:38:55 +01:00
|
|
|
# Call functions to handle password reset by mail issued from
|
|
|
|
# - itself:
|
|
|
|
# - smtpInit
|
|
|
|
# - extractMailInfo
|
|
|
|
# - storeMailSession
|
|
|
|
# - sendConfirmationMail
|
2011-05-30 17:45:56 +02:00
|
|
|
# - changePassword
|
2010-01-22 12:25:37 +01:00
|
|
|
# - sendPasswordMail
|
2010-01-21 18:38:55 +01:00
|
|
|
# - portal core module:
|
|
|
|
# - setMacros
|
|
|
|
# - setLocalGroups
|
|
|
|
# - setGroups
|
|
|
|
# - userDB module:
|
|
|
|
# - userDBInit
|
|
|
|
# - getUser
|
|
|
|
# - setSessionInfo
|
|
|
|
# - passwordDB module:
|
|
|
|
# - passwordDBInit
|
2010-07-22 11:06:50 +02:00
|
|
|
# @return 1 if all is OK
|
2010-01-21 18:38:55 +01:00
|
|
|
sub process {
|
2010-07-22 11:06:50 +02:00
|
|
|
my ($self) = splice @_;
|
2010-01-21 18:38:55 +01:00
|
|
|
|
|
|
|
# Process subroutines
|
|
|
|
$self->{error} = PE_OK;
|
2010-07-22 11:06:50 +02:00
|
|
|
|
2010-01-21 18:38:55 +01:00
|
|
|
$self->{error} = $self->_subProcess(
|
|
|
|
qw(smtpInit userDBInit passwordDBInit extractMailInfo
|
2010-10-21 12:28:47 +02:00
|
|
|
getUser setSessionInfo setMacros setLocalGroups setGroups setPersistentSessionInfo
|
2011-05-30 17:45:56 +02:00
|
|
|
storeMailSession sendConfirmationMail changePassword sendPasswordMail)
|
2010-01-21 18:38:55 +01:00
|
|
|
);
|
2010-07-22 11:06:50 +02:00
|
|
|
|
2010-01-21 18:38:55 +01:00
|
|
|
return (
|
|
|
|
(
|
|
|
|
$self->{error} <= 0
|
|
|
|
or $self->{error} == PE_PASSWORD_OK
|
|
|
|
or $self->{error} == PE_MAILOK
|
|
|
|
) ? 0 : 1
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2010-07-22 11:06:50 +02:00
|
|
|
## @method int smtpInit()
|
2010-01-21 18:38:55 +01:00
|
|
|
# Load SMTP methods
|
2010-07-22 11:06:50 +02:00
|
|
|
# @return Lemonldap::NG::Portal constant
|
2010-01-21 18:38:55 +01:00
|
|
|
sub smtpInit {
|
2010-07-22 11:06:50 +02:00
|
|
|
my ($self) = splice @_;
|
|
|
|
|
2010-01-21 18:38:55 +01:00
|
|
|
eval { use base qw(Lemonldap::NG::Portal::_SMTP) };
|
2010-07-22 11:06:50 +02:00
|
|
|
|
2010-01-21 18:38:55 +01:00
|
|
|
if ($@) {
|
|
|
|
$self->lmLog( "Unable to load SMTP functions ($@)", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
2010-07-22 11:06:50 +02:00
|
|
|
## @method int extractMailInfo
|
2010-01-21 18:38:55 +01:00
|
|
|
# Get mail from form or from mail_token
|
2010-07-22 11:06:50 +02:00
|
|
|
# @return Lemonldap::NG::Portal constant
|
2010-01-21 18:38:55 +01:00
|
|
|
sub extractMailInfo {
|
2010-07-22 11:06:50 +02:00
|
|
|
my ($self) = splice @_;
|
2010-01-21 18:38:55 +01:00
|
|
|
|
|
|
|
return PE_MAILFORMEMPTY
|
|
|
|
unless ( $self->param('mail') || $self->param('mail_token') );
|
|
|
|
|
2011-05-30 17:45:56 +02:00
|
|
|
$self->{mail_token} = $self->param('mail_token');
|
|
|
|
$self->{newpassword} = $self->param('newpassword');
|
|
|
|
$self->{confirmpassword} = $self->param('confirmpassword');
|
2010-01-21 18:38:55 +01:00
|
|
|
|
|
|
|
# If a mail token is present, find the corresponding mail
|
|
|
|
if ( $self->{mail_token} ) {
|
|
|
|
|
|
|
|
$self->lmLog( "Token given for password reset: " . $self->{mail_token},
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
# Get the corresponding session
|
|
|
|
my $h = $self->getApacheSession( $self->{mail_token} );
|
|
|
|
|
|
|
|
if ( ref $h ) {
|
2011-05-20 14:36:42 +02:00
|
|
|
$self->{mail} = $h->{user};
|
|
|
|
$self->{mailAddress} = $h->{ $self->{mailSessionKey} };
|
|
|
|
$self->lmLog( "User associated to token: " . $self->{mail},
|
2010-01-21 18:38:55 +01:00
|
|
|
'debug' );
|
|
|
|
}
|
|
|
|
|
2011-05-30 17:45:56 +02:00
|
|
|
# Close session, it will be deleted after password change success
|
|
|
|
untie %$h;
|
2010-01-21 18:38:55 +01:00
|
|
|
|
|
|
|
return PE_BADMAILTOKEN unless ( $self->{mail} );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
# Use submitted value
|
|
|
|
$self->{mail} = $self->param('mail');
|
|
|
|
}
|
|
|
|
|
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
2010-07-22 11:06:50 +02:00
|
|
|
## @method int storeMailSession
|
|
|
|
# Create mail session and store token
|
|
|
|
# @return Lemonldap::NG::Portal constant
|
2010-01-21 18:38:55 +01:00
|
|
|
sub storeMailSession {
|
2010-07-22 11:06:50 +02:00
|
|
|
my ($self) = splice @_;
|
2010-01-21 18:38:55 +01:00
|
|
|
|
|
|
|
# Skip this step if confirmation was already sent
|
2011-05-20 16:30:21 +02:00
|
|
|
return PE_OK
|
|
|
|
if ( $self->{mail_token} or $self->getMailSession( $self->{mail} ) );
|
2010-01-21 18:38:55 +01:00
|
|
|
|
|
|
|
# Create a new session
|
|
|
|
my $h = $self->getApacheSession();
|
|
|
|
|
|
|
|
# Set _utime for session autoremove
|
2011-06-01 12:22:28 +02:00
|
|
|
# Use default session timeout and mail session timeout to compute it
|
|
|
|
my $time = time();
|
|
|
|
my $timeout = $self->{timeout};
|
|
|
|
my $mailTimeout = $self->{mailTimeout} || $timeout;
|
|
|
|
|
|
|
|
$h->{_utime} = $time + ( $mailTimeout - $timeout );
|
|
|
|
|
|
|
|
# Store expiration timestamp for further use
|
|
|
|
$h->{mailSessionTimeoutTimestamp} = $time + $mailTimeout;
|
|
|
|
$self->{mailSessionTimeoutTimestamp} = $time + $mailTimeout;
|
2010-01-21 18:38:55 +01:00
|
|
|
|
|
|
|
# Store mail
|
2011-05-20 14:36:42 +02:00
|
|
|
$h->{ $self->{mailSessionKey} } =
|
|
|
|
$self->getFirstValue( $self->{sessionInfo}->{ $self->{mailSessionKey} } );
|
|
|
|
|
|
|
|
# Store user
|
|
|
|
$h->{user} = $self->{mail};
|
2010-01-21 18:38:55 +01:00
|
|
|
|
2011-05-20 16:30:21 +02:00
|
|
|
# Store type
|
|
|
|
$h->{_type} = "mail";
|
|
|
|
|
2010-01-21 18:38:55 +01:00
|
|
|
# Untie session
|
|
|
|
untie %$h;
|
|
|
|
|
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
2010-07-22 11:06:50 +02:00
|
|
|
## @method int sendConfirmationMail
|
|
|
|
# Send confirmation mail
|
|
|
|
# @return Lemonldap::NG::Portal constant
|
2010-01-21 18:38:55 +01:00
|
|
|
sub sendConfirmationMail {
|
2010-07-22 11:06:50 +02:00
|
|
|
my ($self) = splice @_;
|
2010-01-21 18:38:55 +01:00
|
|
|
|
2011-05-20 16:30:21 +02:00
|
|
|
# Skip this step if user clicked on the confirmation link
|
2010-01-21 18:38:55 +01:00
|
|
|
return PE_OK if $self->{mail_token};
|
|
|
|
|
2011-05-20 16:30:21 +02:00
|
|
|
# Check if confirmation mail has already been sent
|
|
|
|
my $mail_session = $self->getMailSession( $self->{mail} );
|
|
|
|
my $mail_already_sent = ( $mail_session and !$self->{id} ) ? 1 : 0;
|
|
|
|
|
|
|
|
# Ask if user want another confirmation email
|
|
|
|
if ( $mail_already_sent and !$self->param('resendconfirmation') ) {
|
|
|
|
return PE_MAILCONFIRMATION_ALREADY_SENT;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$self->{id} = $mail_session unless $self->{id};
|
2011-06-01 12:22:28 +02:00
|
|
|
|
|
|
|
my $h = $self->getApacheSession( $mail_session, 1 );
|
|
|
|
$self->{mailSessionTimeoutTimestamp} =
|
|
|
|
$h->{mailSessionTimeoutTimestamp};
|
|
|
|
untie %$h;
|
2011-05-20 16:30:21 +02:00
|
|
|
}
|
|
|
|
|
2011-05-20 14:36:42 +02:00
|
|
|
# Get mail address
|
|
|
|
unless ( $self->{mailAddress} ) {
|
|
|
|
$self->{mailAddress} =
|
|
|
|
$self->getFirstValue(
|
|
|
|
$self->{sessionInfo}->{ $self->{mailSessionKey} } );
|
|
|
|
}
|
|
|
|
|
2010-01-21 18:38:55 +01:00
|
|
|
# Build confirmation url
|
|
|
|
my $url = $self->{mailUrl} . "?mail_token=" . $self->{id};
|
2011-01-25 11:57:45 +01:00
|
|
|
$url .= '&' . $self->{authChoiceParam} . '=' . $self->{_authChoice}
|
|
|
|
if ( $self->{_authChoice} );
|
2010-01-21 18:38:55 +01:00
|
|
|
|
2010-01-22 12:25:37 +01:00
|
|
|
# Build mail content
|
|
|
|
my $subject = $self->{mailConfirmSubject};
|
|
|
|
my $body;
|
|
|
|
my $html;
|
|
|
|
if ( $self->{mailConfirmBody} ) {
|
|
|
|
|
|
|
|
# We use a specific text message, no html
|
|
|
|
$body = $self->{mailConfirmBody};
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
# Use HTML template
|
2011-05-20 17:17:57 +02:00
|
|
|
my $tplfile =
|
|
|
|
( -e $self->getApacheHtdocsPath()
|
|
|
|
. "skins/"
|
|
|
|
. $self->{portalSkin}
|
|
|
|
. "/mail_confirm.tpl" )
|
|
|
|
? $self->getApacheHtdocsPath()
|
|
|
|
. "skins/"
|
|
|
|
. $self->{portalSkin}
|
|
|
|
. "/mail_confirm.tpl"
|
|
|
|
: $self->getApacheHtdocsPath() . "skins/common/mail_confirm.tpl";
|
2010-01-22 12:25:37 +01:00
|
|
|
my $template = HTML::Template->new(
|
2011-05-20 17:17:57 +02:00
|
|
|
filename => $tplfile,
|
|
|
|
filter => sub { $self->translate_template(@_) }
|
2010-01-22 12:25:37 +01:00
|
|
|
);
|
|
|
|
$body = $template->output();
|
|
|
|
$html = 1;
|
|
|
|
}
|
|
|
|
|
2011-06-01 12:22:28 +02:00
|
|
|
# Mail date expiration
|
|
|
|
my $expTimestamp = $self->{mailSessionTimeoutTimestamp};
|
|
|
|
|
|
|
|
$self->lmLog( "Mail expiration timestamp: $expTimestamp", 'debug' );
|
|
|
|
|
|
|
|
my $expMailDate = &POSIX::strftime( "%d/%m/%Y", localtime $expTimestamp );
|
|
|
|
my $expMailTime = &POSIX::strftime( "%H:%M", localtime $expTimestamp );
|
|
|
|
|
2010-01-22 12:25:37 +01:00
|
|
|
# Replace variables in body
|
2011-06-01 12:22:28 +02:00
|
|
|
$body =~ s/\$expMailDate/$expMailDate/g;
|
|
|
|
$body =~ s/\$expMailTime/$expMailTime/g;
|
2010-01-22 12:25:37 +01:00
|
|
|
$body =~ s/\$url/$url/g;
|
2011-05-27 16:08:49 +02:00
|
|
|
$body =~ s/\$(\w+)/decode("utf8",$self->{sessionInfo}->{$1})/ge;
|
2010-01-21 18:38:55 +01:00
|
|
|
|
|
|
|
# Send mail
|
2010-01-22 12:25:37 +01:00
|
|
|
return PE_MAILERROR
|
2011-05-20 14:36:42 +02:00
|
|
|
unless $self->send_mail( $self->{mailAddress}, $subject, $body, $html );
|
2010-01-21 18:38:55 +01:00
|
|
|
|
|
|
|
PE_MAILOK;
|
|
|
|
}
|
|
|
|
|
2011-05-30 17:45:56 +02:00
|
|
|
## @method int changePassword
|
|
|
|
# Change the password or generate a new password
|
|
|
|
# @return Lemonldap::NG::Portal constant
|
|
|
|
sub changePassword {
|
|
|
|
my ($self) = splice @_;
|
|
|
|
|
|
|
|
# Check if user wants to generate the new password
|
|
|
|
if ( $self->param('reset') ) {
|
|
|
|
|
|
|
|
$self->lmLog(
|
|
|
|
"Reset password request for " . $self->{sessionInfo}->{_user},
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
# Generate a complex password
|
|
|
|
my $password = $self->gen_password( $self->{randomPasswordRegexp} );
|
|
|
|
|
|
|
|
$self->lmLog( "Generated password: " . $password, 'debug' );
|
|
|
|
|
|
|
|
$self->{newpassword} = $password;
|
|
|
|
$self->{confirmpassword} = $password;
|
2011-05-30 22:53:03 +02:00
|
|
|
$self->{forceReset} = 1;
|
2011-05-30 17:45:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# Else a password is required
|
|
|
|
else {
|
2011-07-07 12:35:04 +02:00
|
|
|
return PE_PASSWORDFORMEMPTY
|
2011-05-30 17:45:56 +02:00
|
|
|
unless ( $self->{newpassword} && $self->{confirmpassword} );
|
|
|
|
}
|
|
|
|
|
|
|
|
# Modify the password
|
2011-05-30 22:53:03 +02:00
|
|
|
my $result = $self->modifyPassword();
|
2011-05-30 17:45:56 +02:00
|
|
|
|
|
|
|
# Mail token can be used only one time, delete the session if all is ok
|
|
|
|
if ( $result == PE_PASSWORD_OK ) {
|
|
|
|
|
|
|
|
# Get the corresponding session
|
|
|
|
my $h = $self->getApacheSession( $self->{mail_token} );
|
|
|
|
|
|
|
|
# Delete it
|
|
|
|
tied(%$h)->delete() if ref $h;
|
|
|
|
|
|
|
|
# Force result to PE_OK to continue the process
|
|
|
|
$result = PE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2010-07-22 11:06:50 +02:00
|
|
|
## @method int sendPasswordMail
|
|
|
|
# Send mail containing the new password
|
|
|
|
# @return Lemonldap::NG::Portal constant
|
2010-01-22 12:25:37 +01:00
|
|
|
sub sendPasswordMail {
|
2010-07-22 11:06:50 +02:00
|
|
|
my ($self) = splice @_;
|
2010-01-22 12:25:37 +01:00
|
|
|
|
2011-05-20 14:36:42 +02:00
|
|
|
# Get mail address
|
|
|
|
unless ( $self->{mailAddress} ) {
|
|
|
|
$self->{mailAddress} =
|
|
|
|
$self->getFirstValue(
|
|
|
|
$self->{sessionInfo}->{ $self->{mailSessionKey} } );
|
|
|
|
}
|
|
|
|
|
2010-01-22 12:25:37 +01:00
|
|
|
# Build mail content
|
|
|
|
my $subject = $self->{mailSubject};
|
|
|
|
my $body;
|
|
|
|
my $html;
|
|
|
|
if ( $self->{mailBody} ) {
|
|
|
|
|
|
|
|
# We use a specific text message, no html
|
|
|
|
$body = $self->{mailBody};
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
# Use HTML template
|
2011-05-20 17:17:57 +02:00
|
|
|
my $tplfile =
|
|
|
|
( -e $self->getApacheHtdocsPath()
|
|
|
|
. "skins/"
|
|
|
|
. $self->{portalSkin}
|
|
|
|
. "/mail_password.tpl" )
|
|
|
|
? $self->getApacheHtdocsPath()
|
|
|
|
. "skins/"
|
|
|
|
. $self->{portalSkin}
|
|
|
|
. "/mail_password.tpl"
|
|
|
|
: $self->getApacheHtdocsPath() . "skins/common/mail_password.tpl";
|
2010-01-22 12:25:37 +01:00
|
|
|
my $template = HTML::Template->new(
|
2011-05-20 17:17:57 +02:00
|
|
|
filename => $tplfile,
|
|
|
|
filter => sub { $self->translate_template(@_) }
|
2010-01-22 12:25:37 +01:00
|
|
|
);
|
|
|
|
$body = $template->output();
|
|
|
|
$html = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Replace variables in body
|
2011-05-30 17:45:56 +02:00
|
|
|
my $password = $self->{newpassword};
|
2010-01-22 12:25:37 +01:00
|
|
|
$body =~ s/\$password/$password/g;
|
2011-05-27 16:08:49 +02:00
|
|
|
$body =~ s/\$(\w+)/decode("utf8",$self->{sessionInfo}->{$1})/ge;
|
2010-01-22 12:25:37 +01:00
|
|
|
|
|
|
|
# Send mail
|
|
|
|
return PE_MAILERROR
|
2011-05-20 14:36:42 +02:00
|
|
|
unless $self->send_mail( $self->{mailAddress}, $subject, $body, $html );
|
2010-01-22 12:25:37 +01:00
|
|
|
|
|
|
|
PE_MAILOK;
|
|
|
|
}
|
2010-07-22 11:06:50 +02:00
|
|
|
|
2010-01-21 18:38:55 +01:00
|
|
|
1;
|
|
|
|
|
|
|
|
__END__
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
|
|
|
=encoding utf8
|
|
|
|
|
|
|
|
Lemonldap::NG::Portal::MailReset - Manage password reset by mail
|
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
|
|
|
|
use Lemonldap::NG::Portal::MailReset;
|
|
|
|
|
2010-07-22 11:06:50 +02:00
|
|
|
my $portal = new Lemonldap::NG::Portal::MailReset();
|
2010-01-21 18:38:55 +01:00
|
|
|
|
|
|
|
$portal->process();
|
|
|
|
|
|
|
|
# Write here HTML to manage errors and confirmation messages
|
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
|
|
|
Lemonldap::NG::Portal::MailReset enables password reset by mail
|
|
|
|
|
|
|
|
See L<Lemonldap::NG::Portal::SharedConf> for a complete example of use of
|
|
|
|
Lemonldap::Portal::* libraries.
|
|
|
|
|
|
|
|
=head1 METHODS
|
|
|
|
|
|
|
|
=head3 process
|
|
|
|
|
|
|
|
Main method.
|
|
|
|
|
|
|
|
=head1 SEE ALSO
|
|
|
|
|
|
|
|
L<Lemonldap::NG::Handler>, L<Lemonldap::NG::Portal::SharedConf>, L<CGI>,
|
2010-10-26 08:08:16 +02:00
|
|
|
L<http://lemonldap-ng.org/>
|
2010-01-21 18:38:55 +01:00
|
|
|
|
|
|
|
=head1 AUTHOR
|
|
|
|
|
|
|
|
Clement Oudot, E<lt>clement@oodo.netE<gt>
|
|
|
|
|
|
|
|
=head1 BUG REPORT
|
|
|
|
|
|
|
|
Use OW2 system to report bug or ask for features:
|
2010-10-26 08:08:16 +02:00
|
|
|
L<http://jira.ow2.org>
|
2010-01-21 18:38:55 +01:00
|
|
|
|
|
|
|
=head1 DOWNLOAD
|
|
|
|
|
|
|
|
Lemonldap::NG is available at
|
|
|
|
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
|
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE
|
|
|
|
|
2010-10-23 10:35:38 +02:00
|
|
|
Copyright (C) 2005, 2009, 2010 by Xavier Guimard E<lt>x.guimard@free.frE<gt> and
|
2010-01-21 18:38:55 +01:00
|
|
|
Clement Oudot, E<lt>clement@oodo.netE<gt>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify
|
2010-10-24 09:25:44 +02:00
|
|
|
it under the same terms as Perl itself, either Perl version 5.10.0 or,
|
2010-01-21 18:38:55 +01:00
|
|
|
at your option, any later version of Perl 5 you may have available.
|
|
|
|
|
|
|
|
=cut
|