Add Mail second factor plugin
This commit is contained in:
parent
af09943a7f
commit
faa748f68f
|
@ -15,9 +15,9 @@ sub defaultValues {
|
|||
'type' => 'category'
|
||||
}
|
||||
},
|
||||
'authChoiceParam' => 'lmAuth',
|
||||
'authentication' => 'Demo',
|
||||
'available2F' => 'UTOTP,TOTP,U2F,REST,Ext2F,Yubikey',
|
||||
'authChoiceParam' => 'lmAuth',
|
||||
'authentication' => 'Demo',
|
||||
'available2F' => 'UTOTP,TOTP,U2F,REST,Mail2F,Ext2F,Yubikey',
|
||||
'available2FSelfRegistration' => 'TOTP,U2F,Yubikey',
|
||||
'bruteForceProtectionMaxAge' => 300,
|
||||
'bruteForceProtectionMaxFailed' => 3,
|
||||
|
@ -119,6 +119,8 @@ sub defaultValues {
|
|||
},
|
||||
'logoutServices' => {},
|
||||
'macros' => {},
|
||||
'mail2fActivation' => 0,
|
||||
'mail2fCodeRegex' => '\\d\\d\\d\\d\\d\\d',
|
||||
'mailCharset' => 'utf-8',
|
||||
'mailFrom' => 'noreply@example.com',
|
||||
'mailSessionKey' => 'mail',
|
||||
|
|
|
@ -105,6 +105,7 @@ sub portalTab {
|
|||
85 => 'PE_RENEWSESSION',
|
||||
86 => 'PE_WAIT',
|
||||
87 => 'PE_MUSTAUTHN',
|
||||
88 => 'PE_MUSTHAVEMAIL',
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -600,7 +600,7 @@ sub attributes {
|
|||
'type' => 'keyTextContainer'
|
||||
},
|
||||
'available2F' => {
|
||||
'default' => 'UTOTP,TOTP,U2F,REST,Ext2F,Yubikey',
|
||||
'default' => 'UTOTP,TOTP,U2F,REST,Mail2F,Ext2F,Yubikey',
|
||||
'type' => 'text'
|
||||
},
|
||||
'available2FSelfRegistration' => {
|
||||
|
@ -1562,6 +1562,29 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
|
|||
},
|
||||
'type' => 'keyTextContainer'
|
||||
},
|
||||
'mail2fActivation' => {
|
||||
'default' => 0,
|
||||
'type' => 'boolOrExpr'
|
||||
},
|
||||
'mail2fAuthnLevel' => {
|
||||
'type' => 'int'
|
||||
},
|
||||
'mail2fBody' => {
|
||||
'type' => 'longtext'
|
||||
},
|
||||
'mail2fCodeRegex' => {
|
||||
'default' => '\\d\\d\\d\\d\\d\\d',
|
||||
'type' => 'pcre'
|
||||
},
|
||||
'mail2fLogo' => {
|
||||
'type' => 'text'
|
||||
},
|
||||
'mail2fSubject' => {
|
||||
'type' => 'text'
|
||||
},
|
||||
'mail2fTimeout' => {
|
||||
'type' => 'int'
|
||||
},
|
||||
'mailBody' => {
|
||||
'type' => 'longtext'
|
||||
},
|
||||
|
@ -3072,19 +3095,19 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
|
|||
'default' => 0,
|
||||
'select' => [
|
||||
{
|
||||
'k' => '0',
|
||||
'k' => 0,
|
||||
'v' => 'unsecuredCookie'
|
||||
},
|
||||
{
|
||||
'k' => '1',
|
||||
'k' => 1,
|
||||
'v' => 'securedCookie'
|
||||
},
|
||||
{
|
||||
'k' => '2',
|
||||
'k' => 2,
|
||||
'v' => 'doubleCookie'
|
||||
},
|
||||
{
|
||||
'k' => '3',
|
||||
'k' => 3,
|
||||
'v' => 'doubleCookieForSingleSession'
|
||||
}
|
||||
],
|
||||
|
|
|
@ -1303,6 +1303,39 @@ sub attributes {
|
|||
'Authentication level for users authentified by password+(U2F or TOTP)'
|
||||
},
|
||||
|
||||
# Mail second factor
|
||||
mail2fActivation => {
|
||||
type => 'boolOrExpr',
|
||||
default => 0,
|
||||
documentation => 'Mail second factor activation',
|
||||
},
|
||||
mail2fSubject => {
|
||||
type => 'text',
|
||||
documentation => 'Mail subject for second factor authentication',
|
||||
},
|
||||
mail2fBody => {
|
||||
type => 'longtext',
|
||||
documentation => 'Mail body for second factor authentication',
|
||||
},
|
||||
mail2fCodeRegex => {
|
||||
type => 'pcre',
|
||||
default => '\d\d\d\d\d\d',
|
||||
documentation => 'Regular expression to create a mail OTP code',
|
||||
},
|
||||
mail2fTimeout => {
|
||||
type => 'int',
|
||||
documentation => 'Second factor code timeout',
|
||||
},
|
||||
mail2fAuthnLevel => {
|
||||
type => 'int',
|
||||
documentation =>
|
||||
'Authentication level for users authenticated by Mail second factor'
|
||||
},
|
||||
mail2fLogo => {
|
||||
type => 'text',
|
||||
documentation => 'Custom logo for Mail 2F',
|
||||
},
|
||||
|
||||
# External second factor
|
||||
ext2fActivation => {
|
||||
type => 'boolOrExpr',
|
||||
|
@ -2380,7 +2413,7 @@ sub attributes {
|
|||
},
|
||||
available2F => {
|
||||
type => 'text',
|
||||
default => 'UTOTP,TOTP,U2F,REST,Ext2F,Yubikey',
|
||||
default => 'UTOTP,TOTP,U2F,REST,Mail2F,Ext2F,Yubikey',
|
||||
documentation => 'Available second factor modules',
|
||||
},
|
||||
available2FSelfRegistration => {
|
||||
|
|
|
@ -618,6 +618,19 @@ sub tree {
|
|||
'u2fUserCanRemoveKey',
|
||||
]
|
||||
},
|
||||
{ title => 'mail2f',
|
||||
help => 'mail2f.html',
|
||||
form => 'simpleInputContainer',
|
||||
nodes => [
|
||||
'mail2fActivation',
|
||||
'mail2fCodeRegex',
|
||||
'mail2fTimeout',
|
||||
'mail2fSubject',
|
||||
'mail2fBody',
|
||||
'mail2fAuthnLevel',
|
||||
'mail2fLogo',
|
||||
]
|
||||
},
|
||||
{ title => 'external2f',
|
||||
help => 'external2f.html',
|
||||
form => 'simpleInputContainer',
|
||||
|
|
|
@ -380,6 +380,14 @@
|
|||
"lwpOpts":"خيارات لطلبات الخادم",
|
||||
"lwpSslOpts":"خيارات سسل لطلبات الخادم",
|
||||
"macros":"ماكرو",
|
||||
"mail2f":"Mail second factor",
|
||||
"mail2fActivation":"Activation",
|
||||
"mail2fCodeRegex":"Code regex",
|
||||
"mail2fTimeout":"Code timeout",
|
||||
"mail2fSubject":"Mail subject",
|
||||
"mail2fBody":"Mail body",
|
||||
"mail2fAuthnLevel":"Authentication level",
|
||||
"mail2fLogo":"Logo",
|
||||
"mailBody":"محتوى البريد الناجح",
|
||||
"mailCharset":"charset",
|
||||
"mailConfirmBody":"تأكيد محتوى البريد",
|
||||
|
|
|
@ -380,6 +380,14 @@
|
|||
"lwpOpts":"Options for server requests",
|
||||
"lwpSslOpts":"SSL options for server requests",
|
||||
"macros":"Macros",
|
||||
"mail2f":"Mail second factor",
|
||||
"mail2fActivation":"Activation",
|
||||
"mail2fCodeRegex":"Code regex",
|
||||
"mail2fTimeout":"Code timeout",
|
||||
"mail2fSubject":"Mail subject",
|
||||
"mail2fBody":"Mail body",
|
||||
"mail2fAuthnLevel":"Authentication level",
|
||||
"mail2fLogo":"Logo",
|
||||
"mailBody":"Success mail content",
|
||||
"mailCharset":"Charset",
|
||||
"mailConfirmBody":"Confirmation mail content",
|
||||
|
|
|
@ -380,6 +380,14 @@
|
|||
"lwpOpts":"Options for server requests",
|
||||
"lwpSslOpts":"SSL options for server requests",
|
||||
"macros":"Macros",
|
||||
"mail2f":"Mail second factor",
|
||||
"mail2fActivation":"Activation",
|
||||
"mail2fCodeRegex":"Code regex",
|
||||
"mail2fTimeout":"Code timeout",
|
||||
"mail2fSubject":"Mail subject",
|
||||
"mail2fBody":"Mail body",
|
||||
"mail2fAuthnLevel":"Authentication level",
|
||||
"mail2fLogo":"Logo",
|
||||
"mailBody":"Success mail content",
|
||||
"mailCharset":"Charset",
|
||||
"mailConfirmBody":"Confirmation mail content",
|
||||
|
|
|
@ -380,6 +380,14 @@
|
|||
"lwpOpts":"Options pour les requêtes serveur",
|
||||
"lwpSslOpts":"Options SSL pour les requêtes serveur",
|
||||
"macros":"Macros",
|
||||
"mail2f":"Second facteur par mail",
|
||||
"mail2fActivation":"Activation",
|
||||
"mail2fCodeRegex":"Expression régulière pour la génération du code",
|
||||
"mail2fTimeout":"Délai d'expiration du code",
|
||||
"mail2fSubject":"Sujet du message d'envoi du code",
|
||||
"mail2fBody":"Contenu du message d'envoi du code",
|
||||
"mail2fAuthnLevel":"Niveau de l'authentification",
|
||||
"mail2fLogo":"Logo",
|
||||
"mailBody":"Contenu du message de succès",
|
||||
"mailCharset":"Charset",
|
||||
"mailConfirmBody":"Contenu du message de confirmation",
|
||||
|
|
|
@ -381,6 +381,14 @@
|
|||
"lwpSslOpts":"Opzioni SSL per le richieste del server",
|
||||
"macros":"Macro",
|
||||
"mailBody":"Successo contenuto di posta",
|
||||
"mail2f":"Mail second factor",
|
||||
"mail2fActivation":"Activation",
|
||||
"mail2fCodeRegex":"Code regex",
|
||||
"mail2fTimeout":"Code timeout",
|
||||
"mail2fSubject":"Mail subject",
|
||||
"mail2fBody":"Mail body",
|
||||
"mail2fAuthnLevel":"Authentication level",
|
||||
"mail2fLogo":"Logo",
|
||||
"mailCharset":"Charset",
|
||||
"mailConfirmBody":"Contenuto della mail di conferma",
|
||||
"mailConfirmSubject":"Soggetto della mail di conferma",
|
||||
|
|
|
@ -381,6 +381,14 @@
|
|||
"lwpSslOpts":"Tùy chọn SSL cho yêu cầu máy chủ",
|
||||
"macros":"Macros",
|
||||
"mailBody":"Nội dung thư thành công",
|
||||
"mail2f":"Mail second factor",
|
||||
"mail2fActivation":"Activation",
|
||||
"mail2fCodeRegex":"Code regex",
|
||||
"mail2fTimeout":"Code timeout",
|
||||
"mail2fSubject":"Mail subject",
|
||||
"mail2fBody":"Mail body",
|
||||
"mail2fAuthnLevel":"Authentication level",
|
||||
"mail2fLogo":"Logo",
|
||||
"mailCharset":"Charset",
|
||||
"mailConfirmBody":"Xác nhận nội dung thư",
|
||||
"mailConfirmSubject":"Xác nhận chủ đề thư",
|
||||
|
|
|
@ -380,6 +380,14 @@
|
|||
"lwpOpts":"Options for server requests",
|
||||
"lwpSslOpts":"SSL options for server requests",
|
||||
"macros":"Macros",
|
||||
"mail2f":"Mail second factor",
|
||||
"mail2fActivation":"Activation",
|
||||
"mail2fCodeRegex":"Code regex",
|
||||
"mail2fTimeout":"Code timeout",
|
||||
"mail2fSubject":"Mail subject",
|
||||
"mail2fBody":"Mail body",
|
||||
"mail2fAuthnLevel":"Authentication level",
|
||||
"mail2fLogo":"Logo",
|
||||
"mailBody":"Success mail content",
|
||||
"mailCharset":"Charset",
|
||||
"mailConfirmBody":"Confirmation mail content",
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -8,6 +8,7 @@ inc/LWP/Protocol/PSGI.pm
|
|||
lib/Lemonldap/NG/Portal.pm
|
||||
lib/Lemonldap/NG/Portal/2F/Engines/Default.pm
|
||||
lib/Lemonldap/NG/Portal/2F/Ext2F.pm
|
||||
lib/Lemonldap/NG/Portal/2F/Mail2F.pm
|
||||
lib/Lemonldap/NG/Portal/2F/Register/TOTP.pm
|
||||
lib/Lemonldap/NG/Portal/2F/Register/U2F.pm
|
||||
lib/Lemonldap/NG/Portal/2F/Register/Yubikey.pm
|
||||
|
@ -373,6 +374,7 @@ site/templates/common/mail/fr.json
|
|||
site/templates/common/mail/it.json
|
||||
site/templates/common/mail/vi.json
|
||||
site/templates/common/mail/zh_CN.json
|
||||
site/templates/common/mail_2fcode.tpl
|
||||
site/templates/common/mail_confirm.tpl
|
||||
site/templates/common/mail_footer.tpl
|
||||
site/templates/common/mail_header.tpl
|
||||
|
|
154
lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Mail2F.pm
Normal file
154
lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Mail2F.pm
Normal file
|
@ -0,0 +1,154 @@
|
|||
package Lemonldap::NG::Portal::2F::Mail2F;
|
||||
|
||||
use strict;
|
||||
use Mouse;
|
||||
use String::Random;
|
||||
use Lemonldap::NG::Portal::Main::Constants qw(
|
||||
PE_BADCREDENTIALS
|
||||
PE_ERROR
|
||||
PE_FORMEMPTY
|
||||
PE_OK
|
||||
PE_SENDRESPONSE
|
||||
PE_MUSTHAVEMAIL
|
||||
);
|
||||
|
||||
our $VERSION = '2.0.2';
|
||||
|
||||
extends 'Lemonldap::NG::Portal::Main::SecondFactor',
|
||||
'Lemonldap::NG::Portal::Lib::SMTP';
|
||||
|
||||
# INITIALIZATION
|
||||
|
||||
has prefix => ( is => 'ro', default => 'mail' );
|
||||
has random => (
|
||||
is => 'rw',
|
||||
default => sub {
|
||||
return String::Random->new;
|
||||
}
|
||||
);
|
||||
|
||||
has ott => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub {
|
||||
my $ott =
|
||||
$_[0]->{p}->loadModule('Lemonldap::NG::Portal::Lib::OneTimeToken');
|
||||
$ott->timeout( $_[0]->{conf}->{mail2fTimeout}
|
||||
|| $_[0]->{conf}->{formTimeout} );
|
||||
return $ott;
|
||||
}
|
||||
);
|
||||
|
||||
sub init {
|
||||
my ($self) = @_;
|
||||
foreach (qw(mail2fCodeRegex mailSessionKey)) {
|
||||
unless ( $self->conf->{$_} ) {
|
||||
$self->error("Missing $_ parameter, aborting");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
$self->logo( $self->conf->{mail2fLogo} )
|
||||
if ( $self->conf->{mail2fLogo} );
|
||||
return $self->SUPER::init();
|
||||
}
|
||||
|
||||
# RUNNING METHODS
|
||||
|
||||
sub run {
|
||||
my ( $self, $req, $token ) = @_;
|
||||
|
||||
my $checkLogins = $req->param('checkLogins');
|
||||
|
||||
my $code = $self->random->randregex( $self->conf->{mail2fCodeRegex} );
|
||||
$self->logger->debug("Generated two-factor code: $code");
|
||||
$self->ott->updateToken( $token, __mail2fcode => $code );
|
||||
|
||||
my $dest = $req->{sessionInfo}->{ $self->conf->{mailSessionKey} };
|
||||
unless ($dest) {
|
||||
$self->logger->error( "Could not find mail attribute for login "
|
||||
. $req->{sessionInfo}->{_user} );
|
||||
return PE_MUSTHAVEMAIL;
|
||||
}
|
||||
|
||||
# Build mail content
|
||||
my %tplPrms;
|
||||
$tplPrms{MAIN_LOGO} = $self->conf->{portalMainLogo};
|
||||
my $tr = $self->translate($req);
|
||||
my $subject = $self->conf->{mail2fSubject};
|
||||
|
||||
unless ($subject) {
|
||||
$subject = 'mail2fSubject';
|
||||
$tr->( \$subject );
|
||||
}
|
||||
my $body;
|
||||
my $html;
|
||||
if ( $self->conf->{mail2fBody} ) {
|
||||
|
||||
# We use a specific text message, no html
|
||||
$body = $self->conf->{mail2fBody};
|
||||
}
|
||||
else {
|
||||
|
||||
# Use HTML template
|
||||
$body = $self->loadTemplate(
|
||||
'mail_2fcode',
|
||||
filter => $tr,
|
||||
params => \%tplPrms
|
||||
);
|
||||
$html = 1;
|
||||
}
|
||||
|
||||
# Replace variables in body
|
||||
$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 => {
|
||||
MAIN_LOGO => $self->conf->{portalMainLogo},
|
||||
SKIN => $self->conf->{portalSkin},
|
||||
TOKEN => $token,
|
||||
TARGET => '/' . $self->prefix . '2fcheck',
|
||||
CHECKLOGINS => $checkLogins
|
||||
}
|
||||
);
|
||||
$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;
|
||||
}
|
||||
|
||||
$self->logger->debug("Verifying Mail 2F code: $usercode againt $savedcode");
|
||||
|
||||
if ( $usercode eq $savedcode ) {
|
||||
return PE_OK;
|
||||
}
|
||||
else {
|
||||
$self->userLogger->warn( 'Second factor failed for '
|
||||
. $session->{ $self->conf->{whatToTrace} } );
|
||||
return PE_BADCREDENTIALS;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
|
@ -3,7 +3,7 @@ package Lemonldap::NG::Portal::Main::Constants;
|
|||
use strict;
|
||||
use Exporter 'import';
|
||||
|
||||
our $VERSION = '2.0.0';
|
||||
our $VERSION = '2.0.2';
|
||||
|
||||
use constant HANDLER => 'Lemonldap::NG::Handler::PSGI::Main';
|
||||
use constant {
|
||||
|
@ -93,6 +93,7 @@ use constant {
|
|||
PE_RENEWSESSION => 85,
|
||||
PE_WAIT => 86,
|
||||
PE_MUSTAUTHN => 87,
|
||||
PE_MUSTHAVEMAIL => 88,
|
||||
};
|
||||
|
||||
# EXPORTER PARAMETERS
|
||||
|
@ -118,7 +119,8 @@ our @EXPORT_OK = qw( PE_SENDRESPONSE PE_INFO PE_REDIRECT PE_DONE PE_OK
|
|||
PE_RADIUSCONNECTFAILED PE_MUST_SUPPLY_OLD_PASSWORD PE_FORBIDDENIP
|
||||
PE_CAPTCHAERROR PE_CAPTCHAEMPTY PE_REGISTERFIRSTACCESS PE_REGISTERFORMEMPTY
|
||||
PE_REGISTERALREADYEXISTS PE_NOTOKEN PE_TOKENEXPIRED HANDLER PE_U2FFAILED
|
||||
PE_UNAUTHORIZEDPARTNER PE_RENEWSESSION PE_IDPCHOICE PE_WAIT PE_MUSTAUTHN
|
||||
PE_UNAUTHORIZEDPARTNER PE_RENEWSESSION PE_IDPCHOICE PE_WAIT PE_MUSTAUTHN
|
||||
PE_MUSTHAVEMAIL
|
||||
);
|
||||
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK, 'import' ], );
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
"PE85":" الموقع البعيد يطلب جلسة جديدة (ولم يتم تحميل برنامج ترقية الجلسة).\nسجل الخروج و أعد المحاولة",
|
||||
"PE86":"Your account is locked. You must wait 30s before authenticate again",
|
||||
"PE87":"You must authenticate again to access to Portal",
|
||||
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
|
||||
"2fRegRequired":"This service requires a double factor authentication. Register a device now, then go back to the portal.",
|
||||
"accept":"قبول",
|
||||
"accessDenied":"ليس لديك إذن بالدخول لهذا التطبيق",
|
||||
|
@ -240,4 +241,4 @@
|
|||
"yourPhone":"رقم هاتفك",
|
||||
"yourProfile":"ملفك الشخصي",
|
||||
"yourTotpKey":"Your TOTP key"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
"PE85":"Die Gegenseite fragt nach einer neueren Sitzung (und das UpgradeSession-Plugin wurde nicht geladen). Abmelden und erneut versuchen",
|
||||
"PE86":"Your account is locked. You must wait 30s before authenticate again",
|
||||
"PE87":"You must authenticate again to access to Portal",
|
||||
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
|
||||
"2fRegRequired":"Dieser Dienst benötigt Zwei-Faktor-Authentifizierung. Bitte legen Sie ein Gerät an und gehen dann zum Portal zurück.",
|
||||
"accept":"Akzeptieren",
|
||||
"accessDenied":"Sie haben keine Zugriffsberechtigung für diese Anwendung",
|
||||
|
@ -240,4 +241,4 @@
|
|||
"yourPhone":"Ihre Telefonnummer",
|
||||
"yourProfile":"Ihr Profil",
|
||||
"yourTotpKey":"Your TOTP key"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
"PE85":"The remote site ask for a newer session (and UpgradeSession plugin isn't loaded). Logout and retry",
|
||||
"PE86":"Your account is locked. You must wait 30s before authenticate again",
|
||||
"PE87":"You must authenticate again to access to Portal",
|
||||
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
|
||||
"2fRegRequired":"This service requires a double factor authentication. Register a device now, then go back to the portal.",
|
||||
"accept":"Accept",
|
||||
"accessDenied":"You have no access authorization for this application",
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
"PE85":"The remote site ask for a newer session (and UpgradeSession plugin isn't loaded). Logout and retry",
|
||||
"PE86":"Your account is locked. You must wait 30s before authenticate again",
|
||||
"PE87":"You must authenticate again to access to Portal",
|
||||
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
|
||||
"2fRegRequired":"This service requires a double factor authentication. Register a device now, then go back to the portal.",
|
||||
"accept":"Accept",
|
||||
"accessDenied":"You have no access authorization for this application",
|
||||
|
@ -240,4 +241,4 @@
|
|||
"yourPhone":"Your phone number",
|
||||
"yourProfile":"Your profile",
|
||||
"yourTotpKey":"Your TOTP key"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
"PE85":"Le site souhaite une authentification plus récente (et le plugin UpgradeSession n'est pas chargé). Déconnectez-vous et réessayez",
|
||||
"PE86":"Votre compte est verrouillé. Vous devez attendre 30s avant de vous ré-authentifier.",
|
||||
"PE87":"Vous devez vous ré-authentifier pour pouvoir accéder au Portail",
|
||||
"PE88":"Votre compte doit avoir une addresse email pour pouvoir utiliser l'authentification à deux facteurs",
|
||||
"2fRegRequired":"Ce service requiert une authentification à deux facteurs. Enregistrez un équipement ici et retournez au portail.",
|
||||
"accept":"Accepter",
|
||||
"accessDenied":"Vous n'avez pas les droits d'accès à cette application",
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
"PE85":"Il sito remoto richiede una sessione più recente (e il plug-in di UpgradeSession non viene caricato). Disconnetti e riprova",
|
||||
"PE86":"Il tuo account è bloccato. Devi attendere 30 secondi prima di autenticarti di nuovo",
|
||||
"PE87":"È necessario eseguire nuovamente l'autenticazione per accedere al Portale",
|
||||
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
|
||||
"2fRegRequired":"Questo servizio richiede un'autenticazione a doppio fattore. Registrare un dispositivo ora, quindi tornare al portale.",
|
||||
"accept":"Accetta",
|
||||
"accessDenied":"Non hai un'autorizzazione di accesso per questa applicazione",
|
||||
|
@ -240,4 +241,4 @@
|
|||
"yourPhone":"Numero di telefono",
|
||||
"yourProfile":"Il tuo profilo",
|
||||
"yourTotpKey":"La tua chiave TOTP"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
"PE85":"The remote site ask for a newer session (and UpgradeSession plugin isn't loaded). Logout and retry",
|
||||
"PE86":"Your account is locked. You must wait 30s before authenticate again",
|
||||
"PE87":"You must authenticate again to access to Portal",
|
||||
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
|
||||
"2fRegRequired":"This service requires a double factor authentication. Register a device now, then go back to the portal.",
|
||||
"accept":"Accept",
|
||||
"accessDenied":"You have no access authorization for this application",
|
||||
|
@ -240,4 +241,4 @@
|
|||
"yourPhone":"Your phone number",
|
||||
"yourProfile":"Your profile",
|
||||
"yourTotpKey":"Your TOTP key"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
"PE85":"The remote site ask for a newer session (and UpgradeSession plugin isn't loaded). Logout and retry",
|
||||
"PE86":"Your account is locked. You must wait 30s before authenticate again",
|
||||
"PE87":"You must authenticate again to access to Portal",
|
||||
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
|
||||
"2fRegRequired":"This service requires a double factor authentication. Register a device now, then go back to the portal.",
|
||||
"accept":"Accept",
|
||||
"accessDenied":"You have no access authorization for this application",
|
||||
|
@ -240,4 +241,4 @@
|
|||
"yourPhone":"Your phone number",
|
||||
"yourProfile":"Your profile",
|
||||
"yourTotpKey":"Your TOTP key"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
"PE85":"The remote site ask for a newer session (and UpgradeSession plugin isn't loaded). Logout and retry",
|
||||
"PE86":"Your account is locked. You must wait 30s before authenticate again",
|
||||
"PE87":"You must authenticate again to access to Portal",
|
||||
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
|
||||
"2fRegRequired":"This service requires a double factor authentication. Register a device now, then go back to the portal.",
|
||||
"accept":"Accept",
|
||||
"accessDenied":"You have no access authorization for this application",
|
||||
|
@ -240,4 +241,4 @@
|
|||
"yourPhone":"Your phone number",
|
||||
"yourProfile":"Your profile",
|
||||
"yourTotpKey":"Your TOTP key"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
"PE85":"Trang web từ xa yêu cầu một phiên mới (và plugin UpgradeSession không được tải). Đăng xuất và thử lại ",
|
||||
"PE86":"Your account is locked. You must wait 30s before authenticate again",
|
||||
"PE87":"You must authenticate again to access to Portal",
|
||||
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
|
||||
"2fRegRequired":"This service requires a double factor authentication. Register a device now, then go back to the portal.",
|
||||
"accept":"Chấp nhận",
|
||||
"accessDenied":"Bạn không có quyền truy cập vào ứng dụng này",
|
||||
|
@ -240,4 +241,4 @@
|
|||
"yourPhone":"Số điện thoại của bạn",
|
||||
"yourProfile":"Profile của bạn",
|
||||
"yourTotpKey":"Your TOTP key"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
"PE85":"The remote site ask for a newer session (and UpgradeSession plugin isn't loaded). Logout and retry",
|
||||
"PE86":"Your account is locked. You must wait 30s before authenticate again",
|
||||
"PE87":"You must authenticate again to access to Portal",
|
||||
"PE88":"Your account must have an e-mail address in order to use double factor authentication",
|
||||
"2fRegRequired":"This service requires a double factor authentication. Register a device now, then go back to the portal.",
|
||||
"accept":"Accept 方法",
|
||||
"accessDenied":"您无权访问此应用",
|
||||
|
@ -240,4 +241,4 @@
|
|||
"yourPhone":"您的电话号码",
|
||||
"yourProfile":"您的档案",
|
||||
"yourTotpKey":"Your TOTP key"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"click2Register":"انقر هنا لتأكيد تسجيل حسابك",
|
||||
"click2Reset":"انقر هنا لإعادة تعيين كلمة المرور",
|
||||
"hello":"مرحبا ",
|
||||
"mail2fSubject":"[LemonLDAP::NG] Your login code",
|
||||
"mailConfirmSubject":"تأكيد إعادة تعيين كلمة المرور[LemonLDAP::NG]",
|
||||
"mailSubject":"كلمة المرور الجديدة [LemonLDAP::NG]",
|
||||
"newPwdIs":"كلمة المرور الجديدة هي",
|
||||
|
@ -12,5 +13,6 @@
|
|||
"registerConfirmSubject":"تأكيد تسجيل الحساب[LemonLDAP::NG] ",
|
||||
"registerDoneSubject":"حسابك الجديد[LemonLDAP::NG]",
|
||||
"requestIssuedFromIP":"الطلب قد أرسل من عنوان الآي بي",
|
||||
"yourLoginCodeIs":"Your login code is",
|
||||
"yourLoginIs":"تسجيل الدخول الخاص بك هو"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"click2Register":"Click here to confirm your account registration",
|
||||
"click2Reset":"Click here to reset your password",
|
||||
"hello":"Hello",
|
||||
"mail2fSubject":"[LemonLDAP::NG] Your login code",
|
||||
"mailConfirmSubject": "[LemonLDAP::NG] Password reset confirmation",
|
||||
"mailSubject": "[LemonLDAP::NG] Your new password",
|
||||
"newPwdIs":"Your new password is",
|
||||
|
@ -12,5 +13,6 @@
|
|||
"registerConfirmSubject": "[LemonLDAP::NG] Account register confirmation",
|
||||
"registerDoneSubject": "[LemonLDAP::NG] Your new account",
|
||||
"requestIssuedFromIP":"The request was issued from IP",
|
||||
"yourLoginCodeIs":"Your login code is",
|
||||
"yourLoginIs":"Your login is"
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"click2Register":"Cliquez ici pour confirmer l'enregistrement de votre compte",
|
||||
"click2Reset":"Cliquez ici pour réinitialiser votre mot de passe",
|
||||
"hello":"Bonjour",
|
||||
"mail2fSubject":"[LemonLDAP::NG] Votre code de connexion",
|
||||
"mailConfirmSubject": "[LemonLDAP::NG] Confirmation de réinitialisation de mot de passe",
|
||||
"mailSubject": "[LemonLDAP::NG] Votre nouveau mot-de-passe",
|
||||
"newPwdIs":"Votre nouveau mot de passe est",
|
||||
|
@ -12,5 +13,6 @@
|
|||
"registerConfirmSubject": "[LemonLDAP::NG] Confirmation d'enregistrement de compte",
|
||||
"registerDoneSubject": "[LemonLDAP::NG] Votre nouveau compte",
|
||||
"requestIssuedFromIP":"La demande provient de l'IP",
|
||||
"yourLoginCodeIs":"Votre code de connexion est",
|
||||
"yourLoginIs":"Votre identifiant est"
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"click2Register":"Clicca qui per confermare la registrazione del tuo account",
|
||||
"click2Reset":"Clicca qui per reimpostare la password",
|
||||
"hello":"Salve",
|
||||
"mail2fSubject":"[LemonLDAP::NG] Your login code",
|
||||
"mailConfirmSubject":"Conferma reimpostazione password [LemonLDAP::NG] ",
|
||||
"mailSubject":"[LemonLDAP::NG] La tua nuova password",
|
||||
"newPwdIs":"La tua nuova password é",
|
||||
|
@ -12,5 +13,6 @@
|
|||
"registerConfirmSubject":"[LemonLDAP :: NG] Conferma registro account",
|
||||
"registerDoneSubject":"[LemonLDAP::NG] Il tuo nuovo account",
|
||||
"requestIssuedFromIP":"La richiesta è stata emessa da IP",
|
||||
"yourLoginCodeIs":"Your login code is",
|
||||
"yourLoginIs":"Il tuo login é"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"click2Register":"Nhấn ở đây để xác nhận việc đăng ký tài khoản của bạn",
|
||||
"click2Reset":"Nhấn ở đây để thiết lập lại mật khẩu của bạn",
|
||||
"hello":"Xin chào",
|
||||
"mail2fSubject":"[LemonLDAP::NG] Your login code",
|
||||
"mailConfirmSubject":"[LemonLDAP::NG] Xác nhận thiết lập lại mật khẩu",
|
||||
"mailSubject":"[LemonLDAP::NG] Mật khẩu mới của bạn",
|
||||
"newPwdIs":"Mật khẩu mới của bạn là",
|
||||
|
@ -12,5 +13,6 @@
|
|||
"registerConfirmSubject":"[LemonLDAP::NG] Xác nhận đăng ký tài khoản",
|
||||
"registerDoneSubject":"[LemonLDAP::NG] Tài khoản mới của bạn",
|
||||
"requestIssuedFromIP":"Yêu cầu được gửi đi từ địa chỉ IP",
|
||||
"yourLoginCodeIs":"Your login code is",
|
||||
"yourLoginIs":"Đăng nhập của bạn là"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"click2Register":"请点击此处已确认您的账户注册",
|
||||
"click2Reset":"请点击此处充值您的密码",
|
||||
"hello":"您好",
|
||||
"mail2fSubject":"[LemonLDAP::NG] Your login code",
|
||||
"mailConfirmSubject":"[LemonLDAP::NG] 密码重置确认",
|
||||
"mailSubject":"[LemonLDAP::NG] 您的新密码",
|
||||
"newPwdIs":"您的新密码是",
|
||||
|
@ -12,5 +13,6 @@
|
|||
"registerConfirmSubject":"[LemonLDAP::NG] 账号注册确认",
|
||||
"registerDoneSubject":"[LemonLDAP::NG] 您的新账号",
|
||||
"requestIssuedFromIP":"此请求来自IP地址",
|
||||
"yourLoginCodeIs":"Your login code is",
|
||||
"yourLoginIs":"您登陆的账户是"
|
||||
}
|
||||
}
|
||||
|
|
11
lemonldap-ng-portal/site/templates/common/mail_2fcode.tpl
Normal file
11
lemonldap-ng-portal/site/templates/common/mail_2fcode.tpl
Normal file
|
@ -0,0 +1,11 @@
|
|||
<TMPL_INCLUDE NAME="mail_header.tpl">
|
||||
|
||||
<p>
|
||||
<span trspan="hello">Hello</span> $cn,<br />
|
||||
<br />
|
||||
<span trspan="yourLoginCodeIs">Your login code is</span>
|
||||
<b>$code</b>
|
||||
</p>
|
||||
|
||||
<TMPL_INCLUDE NAME="mail_footer.tpl">
|
||||
|
70
lemonldap-ng-portal/t/77-Mail-2F.t
Normal file
70
lemonldap-ng-portal/t/77-Mail-2F.t
Normal file
|
@ -0,0 +1,70 @@
|
|||
use Test::More;
|
||||
use strict;
|
||||
use IO::String;
|
||||
use Data::Dumper;
|
||||
|
||||
require 't/test-lib.pm';
|
||||
require 't/smtp.pm';
|
||||
|
||||
use_ok('Lemonldap::NG::Common::FormEncode');
|
||||
count(1);
|
||||
|
||||
my $client = LLNG::Manager::Test->new(
|
||||
{
|
||||
ini => {
|
||||
logLevel => 'error',
|
||||
mail2fActivation => 1,
|
||||
mail2fCodeRegex => '\d\d\d\d',
|
||||
authentication => 'Demo',
|
||||
userDB => 'Same',
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
# Try to authenticate
|
||||
# -------------------
|
||||
ok(
|
||||
my $res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=dwho'),
|
||||
length => 23,
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Auth query'
|
||||
);
|
||||
count(1);
|
||||
|
||||
my ( $host, $url, $query ) =
|
||||
expectForm( $res, undef, '/mail2fcheck', 'token', 'code' );
|
||||
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
qr%<input name="code" value="" class="form-control" id="extcode" trplaceholder="code" autocomplete="off" />%,
|
||||
'Found EXTCODE input'
|
||||
) or print STDERR Dumper( $res->[2]->[0] );
|
||||
count(1);
|
||||
|
||||
ok( mail() =~ m%<b>(\d\d\d\d)</b>%, 'Found 2F code in mail' )
|
||||
or print STDERR Dumper( mail() );
|
||||
|
||||
my $code = $1;
|
||||
count(1);
|
||||
|
||||
$query =~ s/code=/code=${code}/;
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/mail2fcheck',
|
||||
IO::String->new($query),
|
||||
length => length($query),
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Post code'
|
||||
);
|
||||
count(1);
|
||||
my $id = expectCookie($res);
|
||||
$client->logout($id);
|
||||
|
||||
clean_sessions();
|
||||
|
||||
done_testing( count() );
|
||||
|
Loading…
Reference in New Issue
Block a user