2019-02-03 14:43:44 +01:00
|
|
|
package Lemonldap::NG::Portal::2F::Mail2F;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use Mouse;
|
|
|
|
use Lemonldap::NG::Portal::Main::Constants qw(
|
2020-10-31 23:43:08 +01:00
|
|
|
PE_OK
|
2019-03-07 18:22:16 +01:00
|
|
|
PE_ERROR
|
2020-10-31 23:43:08 +01:00
|
|
|
PE_BADOTP
|
2019-03-07 18:22:16 +01:00
|
|
|
PE_FORMEMPTY
|
|
|
|
PE_SENDRESPONSE
|
|
|
|
PE_MUSTHAVEMAIL
|
2019-02-03 14:43:44 +01:00
|
|
|
);
|
|
|
|
|
2020-10-31 23:43:08 +01:00
|
|
|
our $VERSION = '2.0.10';
|
2019-02-03 14:43:44 +01:00
|
|
|
|
2020-10-31 23:43:08 +01:00
|
|
|
extends qw(
|
|
|
|
Lemonldap::NG::Portal::Main::SecondFactor
|
|
|
|
Lemonldap::NG::Portal::Lib::SMTP
|
|
|
|
);
|
2019-02-03 14:43:44 +01:00
|
|
|
|
|
|
|
# INITIALIZATION
|
|
|
|
|
2019-07-18 22:41:24 +02:00
|
|
|
has prefix => ( is => 'rw', default => 'mail' );
|
2019-02-03 14:43:44 +01:00
|
|
|
has random => (
|
|
|
|
is => 'rw',
|
|
|
|
default => sub {
|
2019-06-27 18:39:01 +02:00
|
|
|
return Lemonldap::NG::Common::Crypto::srandom();
|
2019-02-03 14:43:44 +01:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
has ott => (
|
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
default => sub {
|
2019-03-07 18:22:16 +01:00
|
|
|
my $ott =
|
|
|
|
$_[0]->{p}->loadModule('Lemonldap::NG::Portal::Lib::OneTimeToken');
|
2019-02-03 14:43:44 +01:00
|
|
|
$ott->timeout( $_[0]->{conf}->{mail2fTimeout}
|
2019-03-07 18:22:16 +01:00
|
|
|
|| $_[0]->{conf}->{formTimeout} );
|
2019-02-03 14:43:44 +01:00
|
|
|
return $ott;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2020-12-03 19:59:36 +01:00
|
|
|
has sessionKey => (
|
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
default => sub {
|
|
|
|
return $_[0]->{conf}->{mail2fSessionKey}
|
|
|
|
|| $_[0]->{conf}->{mailSessionKey};
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2019-02-03 14:43:44 +01:00
|
|
|
sub init {
|
|
|
|
my ($self) = @_;
|
2019-02-14 22:41:58 +01:00
|
|
|
$self->{conf}->{mail2fCodeRegex} ||= '\d{6}';
|
2020-12-03 19:59:36 +01:00
|
|
|
unless ( $self->sessionKey ) {
|
|
|
|
$self->error("Missing session key parameter, aborting");
|
2019-02-14 22:41:58 +01:00
|
|
|
return 0;
|
2019-02-03 14:43:44 +01:00
|
|
|
}
|
2019-07-18 22:41:24 +02:00
|
|
|
$self->prefix( $self->conf->{sfPrefix} )
|
|
|
|
if ( $self->conf->{sfPrefix} );
|
2019-02-03 14:43:44 +01:00
|
|
|
return $self->SUPER::init();
|
|
|
|
}
|
|
|
|
|
|
|
|
sub run {
|
|
|
|
my ( $self, $req, $token ) = @_;
|
|
|
|
|
|
|
|
my $checkLogins = $req->param('checkLogins');
|
2020-10-31 23:01:11 +01:00
|
|
|
$self->logger->debug("Mail2F: checkLogins set") if $checkLogins;
|
|
|
|
|
|
|
|
my $stayconnected = $req->param('stayconnected');
|
|
|
|
$self->logger->debug("Mail2F: stayconnected set") if $stayconnected;
|
2019-02-03 14:43:44 +01:00
|
|
|
|
|
|
|
my $code = $self->random->randregex( $self->conf->{mail2fCodeRegex} );
|
|
|
|
$self->logger->debug("Generated two-factor code: $code");
|
|
|
|
$self->ott->updateToken( $token, __mail2fcode => $code );
|
|
|
|
|
2020-12-03 19:59:36 +01:00
|
|
|
my $dest = $req->{sessionInfo}->{ $self->sessionKey };
|
2019-02-03 14:43:44 +01:00
|
|
|
unless ($dest) {
|
|
|
|
$self->logger->error( "Could not find mail attribute for login "
|
2019-03-07 18:22:16 +01:00
|
|
|
. $req->{sessionInfo}->{_user} );
|
2019-02-03 14:43:44 +01:00
|
|
|
return PE_MUSTHAVEMAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Build mail content
|
|
|
|
my $tr = $self->translate($req);
|
|
|
|
my $subject = $self->conf->{mail2fSubject};
|
|
|
|
|
|
|
|
unless ($subject) {
|
|
|
|
$subject = 'mail2fSubject';
|
|
|
|
$tr->( \$subject );
|
|
|
|
}
|
2019-02-14 22:41:58 +01:00
|
|
|
my ( $body, $html );
|
2019-02-03 14:43:44 +01:00
|
|
|
if ( $self->conf->{mail2fBody} ) {
|
|
|
|
|
|
|
|
# We use a specific text message, no html
|
|
|
|
$body = $self->conf->{mail2fBody};
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
# Use HTML template
|
2019-08-22 15:41:51 +02:00
|
|
|
$body = $self->loadMailTemplate(
|
2019-06-28 13:40:56 +02:00
|
|
|
$req,
|
2019-02-03 14:43:44 +01:00
|
|
|
'mail_2fcode',
|
|
|
|
filter => $tr,
|
2021-03-31 11:42:55 +02:00
|
|
|
params => {
|
2021-03-31 12:08:24 +02:00
|
|
|
code => $code,
|
2021-03-31 11:42:55 +02:00
|
|
|
},
|
2019-02-03 14:43:44 +01:00
|
|
|
);
|
|
|
|
$html = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Replace variables in body
|
2021-03-31 12:08:24 +02:00
|
|
|
# FIXME: kept for compatibility with 2.0.0 mail templates
|
|
|
|
# in future versions this should only happen for plaintext emails
|
2019-02-03 14:43:44 +01:00
|
|
|
$body =~ s/\$code/$code/g;
|
|
|
|
$body =~ s/\$(\w+)/$req->{sessionInfo}->{$1} || ''/ge;
|
|
|
|
|
|
|
|
# Send mail
|
|
|
|
unless ( $self->send_mail( $dest, $subject, $body, $html ) ) {
|
|
|
|
$self->logger->error( 'Unable to send 2F code mail to ' . $dest );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Prepare form
|
|
|
|
my $tmp = $self->p->sendHtml(
|
|
|
|
$req,
|
|
|
|
'ext2fcheck',
|
|
|
|
params => {
|
2019-09-03 11:56:48 +02:00
|
|
|
MAIN_LOGO => $self->conf->{portalMainLogo},
|
|
|
|
SKIN => $self->p->getSkin($req),
|
|
|
|
TOKEN => $token,
|
|
|
|
PREFIX => $self->prefix,
|
|
|
|
TARGET => '/'
|
|
|
|
. $self->prefix
|
|
|
|
. '2fcheck?skin='
|
|
|
|
. $self->p->getSkin($req),
|
2020-10-31 23:01:11 +01:00
|
|
|
LEGEND => 'enterMail2fCode',
|
|
|
|
CHECKLOGINS => $checkLogins,
|
|
|
|
STAYCONNECTED => $stayconnected
|
2019-02-03 14:43:44 +01:00
|
|
|
}
|
|
|
|
);
|
|
|
|
$req->response($tmp);
|
|
|
|
return PE_SENDRESPONSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub verify {
|
|
|
|
my ( $self, $req, $session ) = @_;
|
|
|
|
my $usercode;
|
|
|
|
unless ( $usercode = $req->param('code') ) {
|
|
|
|
$self->logger->error('Mail2F: no code');
|
|
|
|
return PE_FORMEMPTY;
|
|
|
|
}
|
|
|
|
my $savedcode = $session->{__mail2fcode};
|
|
|
|
|
|
|
|
unless ($savedcode) {
|
|
|
|
$self->logger->error(
|
|
|
|
'Unable to find generated 2F code in token session');
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
2019-02-10 22:47:56 +01:00
|
|
|
$self->logger->debug(
|
|
|
|
"Verifying Mail 2F code: $usercode against $savedcode");
|
2019-02-03 14:43:44 +01:00
|
|
|
|
2019-02-10 22:47:56 +01:00
|
|
|
return PE_OK if ( $usercode eq $savedcode );
|
|
|
|
|
|
|
|
$self->userLogger->warn( 'Second factor failed for '
|
2019-03-07 18:22:16 +01:00
|
|
|
. $session->{ $self->conf->{whatToTrace} } );
|
2019-11-13 11:46:30 +01:00
|
|
|
return PE_BADOTP;
|
2019-02-03 14:43:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
1;
|