Add Mail second factor plugin

This commit is contained in:
Maxime Besson 2019-02-03 14:43:44 +01:00 committed by Clément OUDOT
parent af09943a7f
commit faa748f68f
36 changed files with 416 additions and 26 deletions

View File

@ -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',

View File

@ -105,6 +105,7 @@ sub portalTab {
85 => 'PE_RENEWSESSION',
86 => 'PE_WAIT',
87 => 'PE_MUSTAUTHN',
88 => 'PE_MUSTHAVEMAIL',
};
}

View File

@ -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'
}
],

View File

@ -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 => {

View File

@ -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',

View File

@ -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":"تأكيد محتوى البريد",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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ư",

View File

@ -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

View File

@ -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

View 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;

View File

@ -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' ], );

View File

@ -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"
}
}

View File

@ -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"
}
}

View File

@ -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",

View File

@ -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"
}
}

View File

@ -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",

View File

@ -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"
}
}

View File

@ -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"
}
}

View File

@ -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"
}
}

View File

@ -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"
}
}

View File

@ -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"
}
}

View File

@ -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"
}
}

View File

@ -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":"تسجيل الدخول الخاص بك هو"
}
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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 é"
}
}

View File

@ -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à"
}
}

View File

@ -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":"您登陆的账户是"
}
}

View 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">

View 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() );