Pwd reset in progress (#595)

This commit is contained in:
Xavier Guimard 2017-01-29 09:11:27 +00:00
parent 2582fc21f1
commit 7a3725db9d
10 changed files with 258 additions and 52 deletions

View File

@ -111,7 +111,7 @@ sub defaultValues {
'mailSessionKey' => 'mail',
'mailSubject' => '[LemonLDAP::NG] Your new password',
'mailTimeout' => 0,
'mailUrl' => 'http://auth.example.com/mail.pl',
'mailUrl' => 'http://auth.example.com/resetpwd',
'managerDn' => '',
'managerPassword' => '',
'multiValuesSeparator' => '; ',
@ -177,7 +177,7 @@ sub defaultValues {
'remoteGlobalStorageOptions' => {
'ns' =>
'http://auth.example.com/Lemonldap/NG/Common/CGI/SOAPService',
'proxy' => 'http://auth.example.com/index.pl/sessions'
'proxy' => 'http://auth.example.com/sessions'
},
'requireToken' => 1,
'samlAttributeAuthorityDescriptorAttributeServiceSOAP' =>

View File

@ -1367,7 +1367,7 @@ qr/^(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-
'type' => 'int'
},
'mailUrl' => {
'default' => 'http://auth.example.com/mail.pl',
'default' => 'http://auth.example.com/resetpwd',
'type' => 'url'
},
'maintenance' => {
@ -2084,7 +2084,7 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'default' => {
'ns' =>
'http://auth.example.com/Lemonldap/NG/Common/CGI/SOAPService',
'proxy' => 'http://auth.example.com/index.pl/sessions'
'proxy' => 'http://auth.example.com/sessions'
},
'type' => 'keyTextContainer'
},

View File

@ -903,7 +903,7 @@ sub attributes {
},
mailUrl => {
type => 'url',
default => 'http://auth.example.com/mail.pl',
default => 'http://auth.example.com/resetpwd',
documentation => 'URL of password reset page',
},
SMTPServer => {
@ -2044,7 +2044,7 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
remoteGlobalStorageOptions => {
type => 'keyTextContainer',
default => {
proxy => 'http://auth.example.com/index.pl/sessions',
proxy => 'http://auth.example.com/sessions',
ns =>
'http://auth.example.com/Lemonldap/NG/Common/CGI/SOAPService',
},

File diff suppressed because one or more lines are too long

View File

@ -155,7 +155,7 @@ sub getMailSession {
foreach my $id ( keys %$sessions ) {
my $mailSession = $self->p->getApacheSession($id);
next unless ($mailSession);
return $id if ( $mailSession->data->{_type} =~ /^mail$/ );
return $mailSession if ( $mailSession->data->{_type} =~ /^mail$/ );
}
# No mail session found, return empty string

View File

@ -39,13 +39,16 @@ sub enabledPlugins {
push @res, '::Plugins::Register'
if ( $self->conf->{registerDB} and $self->conf->{registerDB} ne 'Null' );
push @res, '::Plugins::MailReset'
if ( $self->conf->{portalDisplayResetPassword} );
# Check if SOAP is enabled
push @res, '::Plugins::SOAPServer'
if ( $self->conf->{soapSessionServer}
or $self->conf->{soapConfigServer} );
# Check if portal status is enabled
push @res, '::Plugins::Status' if($self->conf->{portalStatus});
push @res, '::Plugins::Status' if ( $self->conf->{portalStatus} );
# Add REST (check is done by it)
push @res, '::Plugins::RESTServer';
@ -72,6 +75,7 @@ sub enabledPlugins {
}
# Check if custom plugins are required
# TODO: change this name
if ( $self->conf->{plugins} ) {
$self->lmLog( 'Custom plugins: ' . $self->conf->{plugins}, 'debug' );
push @res, grep ( /\w/, split( /,\s*/, $self->conf->{plugins} ) );

View File

@ -1,4 +1,4 @@
package Lemonldap::NG::Portal::Plugins::Register;
package Lemonldap::NG::Portal::Plugins::MailReset;
use strict;
use Encode;
@ -9,10 +9,12 @@ use Lemonldap::NG::Portal::Main::Constants qw(
PE_BADMAILTOKEN
PE_CAPTCHAEMPTY
PE_CAPTCHAERROR
PE_MAILCONFIRMATION_ALREADY_SENT
PE_MAILCONFIRMOK
PE_MAILERROR
PE_MAILFIRSTACCESS
PE_MAILFORMEMPTY
PE_MAILNOTFOUND
PE_MAILOK
PE_MALFORMEDUSER
PE_NOTOKEN
@ -90,7 +92,7 @@ sub _reset {
my ( $mailToken, $newPwd, $confirmPwd );
# Check for first access
$mailToken = $req->param('mail_token');
$mailToken = $req->datas->{mailToken} = $req->param('mail_token');
unless ( $req->param('mail') || $mailToken ) {
$self->setSecurity($req);
return PE_MAILFIRSTACCESS if ( $req->method eq 'GET' );
@ -112,7 +114,7 @@ sub _reset {
$req->{mail} = $mailSession->{user};
$req->datas->{mailAddress} =
$mailSession->{ $self->conf->{mailSessionKey} };
$self->lmLog( 'User associated to: ' . $req->{mail} . 'debug' );
$self->lmLog( 'User associated to: ' . $req->{mail}, 'debug' );
}
# Check for values posted
@ -168,7 +170,7 @@ sub _reset {
}
# Search user in database
$req->user( $req->{mail} );
#$req->user( $req->{mail} );
$req->steps(
[
'getUser', 'setSessionInfo',
@ -188,10 +190,8 @@ sub _reset {
}
# Build temporary session
my $mailSession;
unless ( ( $mailSession = $self->getMailSession( $req->{mail} ) )
or $mailToken )
{
my $mailSession = $self->getMailSession( $req->{mail} );
unless ( $mailSession or $mailToken ) {
# Create a new session
@ -226,32 +226,39 @@ sub _reset {
# Update session
$mailSession->update($infos);
$req->id($mailSession->id);
}
elsif($mailSession) {
$self->lmLog( 'Mail session found: ' . $mailSession->id, 'debug' );
$req->datas->{mailAlreadySent} = 1;
}
# Send confirmation mail
unless ($mailToken) {
my $mailAlreadySent = ( $mailSession->{id} and !$req->id ) ? 1 : 0;
$req->{id} ||= $mailSession->{id};
$self->lmLog( 'Mail session found: ' . $mailSession->id, 'debug' );
# Mail session expiration date
my $expTimestamp = $mailSession->data->{mailSessionTimeoutTimestamp};
$self->lmLog( "Mail expiration timestamp: $expTimestamp", 'debug' );
my $expMailDate = strftime( "%d/%m/%Y", localtime $expTimestamp );
my $expMailTime = strftime( "%H:%M", localtime $expTimestamp );
$req->datas->{expMailDate} =
strftime( "%d/%m/%Y", localtime $expTimestamp );
$req->datas->{expMailTime} =
strftime( "%H:%M", localtime $expTimestamp );
# Mail session start date
my $startTimestamp = $mailSession->data->{mailSessionStartTimestamp};
$self->lmLog( "Mail start timestamp: $startTimestamp", 'debug' );
my $startMailDate = strftime( "%d/%m/%Y", localtime $startTimestamp );
my $startMailTime = strftime( "%H:%M", localtime $startTimestamp );
$req->datas->{startMailDate} =
strftime( "%d/%m/%Y", localtime $startTimestamp );
$req->datas->{startMailTime} =
strftime( "%H:%M", localtime $startTimestamp );
# Ask if user want another confirmation email
if ( $self->mailAlreadySent and !$req->param('resendconfirmation') ) {
if ( $req->datas->{mailAlreadySent}
and !$req->param('resendconfirmation') )
{
$self->p->userNotice(
'Reset mail already sent to ' . $req->{mail} );
@ -263,6 +270,7 @@ sub _reset {
$req->datas->{mailAddress} ||=
$self->p->getFirstValue(
$req->{sessionInfo}->{ $self->conf->{mailSessionKey} } );
return PE_MAILERROR unless($req->datas->{mailAddress});
# Build confirmation url
my $url =
@ -270,7 +278,7 @@ sub _reset {
. "?mail_token="
. $req->{id}
. '&skin='
. $self->p->getSkin;
. $self->p->getSkin($req);
$url .= '&'
. $self->conf->{authChoiceParam} . '='
. $req->datas->{_authChoice}
@ -300,14 +308,14 @@ sub _reset {
}
# Replace variables in body
$body =~ s/\$expMailDate/$expMailDate/g;
$body =~ s/\$expMailTime/$expMailTime/g;
$body =~ s/\$expMailDate/$req->datas->{expMailDate}/ge;
$body =~ s/\$expMailTime/$req->datas->{expMailTime}/ge;
$body =~ s/\$url/$url/g;
$body =~ s/\$(\w+)/decode("utf8",$req->{sessionInfo}->{$1})/ge;
# Send mail
unless (
$self->send_mail( $self->{mailAddress}, $subject, $body, $html ) )
$self->send_mail( $req->datas->{mailAddress}, $subject, $body, $html ) )
{
$self->lmLog( 'Unable to send reset mail', 'debug' );
@ -404,4 +412,98 @@ sub setSecurity {
}
}
sub display {
my ( $self, $req ) = @_;
my %tplPrm = (
PORTAL_URL => $self->conf->{portal},
SKIN_PATH => '/static',
SKIN => $self->conf->{portalSkin},
SKIN_BG => $self->conf->{portalSkinBackground},
AUTH_ERROR => $req->error,
AUTH_ERROR_TYPE => $req->error_type,
CHOICE_PARAM => $self->conf->{authChoiceParam},
CHOICE_VALUE => $req->{_authChoice},
EXPMAILDATE => $req->datas->{expMailDate},
EXPMAILTIME => $req->datas->{expMailTime},
STARTMAILDATE => $req->datas->{startMailDate},
STARTMAILTIME => $req->datas->{startMailTime},
MAILALREADYSENT => $req->datas->{mailAlreadySent},
MAIL => (
$self->p->checkXSSAttack( 'mail', $req->{mail} ) ? ""
: $self->{mail}
),
MAIL_TOKEN => (
$self->p->checkXSSAttack( 'mail_token', $req->datas->{mailToken} )
? ""
: $req->datas->{mailToken}
),
DISPLAY_FORM => 0,
DISPLAY_RESEND_FORM => 0,
DISPLAY_CONFIRMMAILSENT => 0,
DISPLAY_MAILSENT => 0,
DISPLAY_PASSWORD_FORM => 0,
);
# Display captcha if it's enabled
if ( $req->captcha ) {
$tplPrm{CAPTCHA_SRC} = $req->captcha;
$tplPrm{CAPTCHA_SIZE} = $self->conf->{captcha_size};
}
if ( $req->token ) {
$tplPrm{TOKEN} = $req->token;
}
# Display form the first time
if (
(
$req->error == PE_MAILFORMEMPTY
or $req->error == PE_MAILFIRSTACCESS
or $req->error == PE_MAILNOTFOUND
or $req->error == PE_CAPTCHAERROR
or $req->error == PE_CAPTCHAEMPTY
)
and !$req->datas->{mailToken}
)
{
$self->lmLog('Display form','debug');
$tplPrm{DISPLAY_FORM} = 1;
}
# Display mail confirmation resent form
elsif ( $req->error == PE_MAILCONFIRMATION_ALREADY_SENT ) {
$self->lmLog('Display resend form','debug');
$tplPrm{DISPLAY_RESEND_FORM} = 1;
}
# Display confirmation mail sent
elsif ( $req->error == PE_MAILCONFIRMOK ) {
$self->lmLog('Display "confirm mail sent"','debug');
$tplPrm{DISPLAY_CONFIRMMAILSENT} = 1;
}
# Display mail sent
elsif ( $req->error == PE_MAILOK ) {
$self->lmLog('Display "mail sent"','debug');
$tplPrm{DISPLAY_MAILSENT} = 1;
}
# Display password change form
elsif ( $req->datas->{mailToken}
and $req->error != PE_MAILERROR
and $req->error != PE_BADMAILTOKEN
and $req->error != PE_MAILOK )
{
$self->lmLog('Display password form','debug');
$tplPrm{DISPLAY_PASSWORD_FORM} = 1;
}
# Custom template parameters
if ( my $customParams = $self->p->getCustomTemplateParameters() ) {
foreach ( keys %$customParams ) {
$tplPrm{$_} = $customParams->{$_};
}
}
return 'mail', \%tplPrm;
}
1;

View File

@ -13,24 +13,29 @@ extends 'Lemonldap::NG::Common::Module';
our $VERSION = '2.0.0';
# Sample accounts from Doctor Who characters
has demoAccounts => (is=>'rw',default=>sub{{
'rtyler' => {
'uid' => 'rtyler',
'cn' => 'Rose Tyler',
'mail' => 'rtyler@badwolf.org',
},
'msmith' => {
'uid' => 'msmith',
'cn' => 'Mickey Smith',
'mail' => 'msmith@badwolf.org',
},
'dwho' => {
'uid' => 'dwho',
'cn' => 'Doctor Who',
'mail' => 'dwho@badwolf.org',
},
}});
# Sample accounts from Doctor Who characters
has demoAccounts => (
is => 'rw',
default => sub {
{
'rtyler' => {
'uid' => 'rtyler',
'cn' => 'Rose Tyler',
'mail' => 'rtyler@badwolf.org',
},
'msmith' => {
'uid' => 'msmith',
'cn' => 'Mickey Smith',
'mail' => 'msmith@badwolf.org',
},
'dwho' => {
'uid' => 'dwho',
'cn' => 'Doctor Who',
'mail' => 'dwho@badwolf.org',
},
};
}
);
# INITIALIZATION
@ -63,7 +68,7 @@ sub getUser {
if ( $req->{mail} ) {
return PE_OK
if (
my $req->{user} =
( $req->{user} ) =
grep { $self->demoAccounts->{$_}->{mail} eq $req->{mail} }
keys %{ $self->demoAccounts }
);
@ -81,8 +86,7 @@ sub setSessionInfo {
my %vars = ( %{ $self->conf->{exportedVars} },
%{ $self->conf->{demoExportedVars} } );
while ( my ( $k, $v ) = each %vars ) {
$req->{sessionInfo}->{$k} =
$self->demoAccounts->{ $req->{user} }->{$v}
$req->{sessionInfo}->{$k} = $self->demoAccounts->{ $req->{user} }->{$v}
|| "";
}

View File

@ -0,0 +1,95 @@
use Test::More;
use strict;
use IO::String;
BEGIN {
require MIME::Lite;
require 't/test-lib.pm';
}
my ( $res, $user, $pwd );
my $mailSend = 0;
my $mail2 = 0;
my $client = LLNG::Manager::Test->new(
{
ini => {
logLevel => 'debug',
useSafeJail => 1,
portalDisplayRegister => 1,
authentication => 'Demo',
userDB => 'Demo',
passwordDB => 'Demo',
captcha_mail_enabled => 0,
portalDisplayResetPassword => 1,
}
}
);
# Test form
# ------------------------
ok( $res = $client->_get( '/resetpwd', accept => 'text/html' ), 'Reset form', );
count(1);
my ( $host, $url, $query ) = expectForm( $res, '#', undef, 'mail' );
$query = 'mail=dwho%40badwolf.org';
# Post email
ok(
$res = $client->_post(
'/resetpwd', IO::String->new($query),
length => length($query),
accept => 'text/html'
),
'Post email'
);
count(1);
# $query has been set by MIME::Lite::send
ok(
$res = $client->_get( '/resetpwd', query => $query, accept => 'text/html' ),
'Post mail token'
);
count(1);
( $host, $url, $query ) = expectForm( $res, '#', undef, 'mail_token' );
ok($res->[2]->[0]=~/newpassword/s,' Ask for a new password');
count(1);
#print STDERR Dumper($query);
clean_sessions();
done_testing( count() );
no warnings 'redefine';
sub MIME::Lite::send {
my ($mail) = @_;
pass('----- Mail given to MIME::Lite -----');
ok( $mail->header_as_string =~ /dwho\@badwolf.org/s, 'Found dest' )
or explain( $mail->header_as_string, 'To: dwho@badwolf.org' );
count(2);
unless ($mail2) {
$mailSend = 1;
ok(
$mail->body_as_string =~
m#a href="http://auth.example.com/resetpwd\?(.*?)"#,
'Found link'
);
count(1);
$query = $1;
$mail2++;
}
else {
$mailSend = 2;
ok(
$mail->body_as_string =~
m#yourLoginIs.+?<b>(\w+)</b>.*?pwdIs.+?<b>(.*?)</b>#s,
'Get login/pwd'
);
( $user, $pwd ) = ( $1, $2 );
count(1);
}
}

View File

@ -21,7 +21,8 @@
}
},
"exportedVars": {
"UA": "HTTP_USER_AGENT"
"mail": "mail",
"cn": "cn"
},
"globalStorage": "Apache::Session::File",
"globalStorageOptions": {