Merge branch '2733' into 'v2.0'
Fix __ALL__ special characters with password reset by mail See merge request lemonldap-ng/lemonldap-ng!264
This commit is contained in:
commit
3d10995b0b
|
@ -58,7 +58,7 @@ As *root:*
|
|||
|
||||
apt install aptitude
|
||||
aptitude install vim make devscripts yui-compressor git git-gui libjs-uglify coffeescript cpanminus autopkgtest pkg-perl-autopkgtest
|
||||
aptitude install libauth-yubikey-webclient-perl libnet-smtp-server-perl libtime-fake-perl libtest-output-perl libtest-pod-perl libtest-leaktrace-perl libtest-mockobject-perl uglifyjs
|
||||
aptitude install libauth-yubikey-webclient-perl libnet-smtp-server-perl libtime-fake-perl libtest-output-perl libtest-pod-perl libtest-leaktrace-perl libtest-mockobject-perl uglifyjs libdbd-sqlite3-perl libauthen-webauthn-perl libauthen-oath-perl
|
||||
|
||||
cpanm Authen::U2F Authen::U2F::Tester Crypt::U2F::Server::Simple
|
||||
|
||||
|
|
|
@ -95,6 +95,8 @@ Second factor
|
|||
|
||||
- Crypt::U2F::Server::Simple (U2F keys)
|
||||
- Convert::Base32 (TOTP)
|
||||
- Authen::WebAuthn (FIDO2 WebAuthen)
|
||||
- Authen::OATH (OTP)
|
||||
|
||||
Specific authentication backends
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -138,6 +140,7 @@ Unit tests
|
|||
- Authen::U2F::Tester
|
||||
- Crypt::U2F::Server
|
||||
- Test::MockObject
|
||||
- DBD::SQLite
|
||||
- Test::Output
|
||||
- Test::POD
|
||||
- Time::Fake
|
||||
|
|
|
@ -84,8 +84,6 @@ Then go in Manager, ``General Parameters`` » ``Plugins`` »
|
|||
- **Display generate password box**: display a checkbox to allow
|
||||
user to generate a new password instead of choosing one (default:
|
||||
disabled)
|
||||
|
||||
::
|
||||
|
||||
* **Regexp for password generation**: Regular expression used to generate the password (default: [A-Z]{3}[a-z]{5}.\d{2})
|
||||
- **Regexp for password generation**: Regular expression used to generate the password. Set a blank value to use
|
||||
password policy if enabled or default regexp will be employed: [A-Z]{3}[a-z]{5}.\d{2}
|
||||
|
||||
|
|
|
@ -10,11 +10,12 @@ use Mouse;
|
|||
use JSON;
|
||||
use URI;
|
||||
|
||||
has isPP => ( is => 'rw' );
|
||||
has speChars => ( is => 'rw' );
|
||||
has skinRules => ( is => 'rw' );
|
||||
has stayConnected => ( is => 'rw', default => sub { 0 } );
|
||||
has requireOldPwd => ( is => 'rw', default => sub { 1 } );
|
||||
has isPP => ( is => 'rw' );
|
||||
has speChars => ( is => 'rw' );
|
||||
has skinRules => ( is => 'rw' );
|
||||
has stayConnected => ( is => 'rw', default => sub { 0 } );
|
||||
has requireOldPwd => ( is => 'rw', default => sub { 1 } );
|
||||
has passwordPolicyActivation => ( is => 'rw', default => sub { 0 } );
|
||||
|
||||
sub displayInit {
|
||||
my ($self) = @_;
|
||||
|
@ -48,6 +49,14 @@ sub displayInit {
|
|||
$self->logger->error("Bad stayConnected rule: $error");
|
||||
}
|
||||
$self->stayConnected($rule);
|
||||
$rule =
|
||||
HANDLER->buildSub(
|
||||
HANDLER->substitute( $self->conf->{passwordPolicyActivation} ) );
|
||||
unless ($rule) {
|
||||
my $error = HANDLER->tsv->{jail}->error || 'Unable to compile rule';
|
||||
$self->logger->error("Bad passwordPolicyActivation rule: $error");
|
||||
}
|
||||
$self->passwordPolicyActivation($rule);
|
||||
|
||||
my $speChars =
|
||||
$self->conf->{passwordPolicySpecialChar} eq '__ALL__'
|
||||
|
@ -474,7 +483,7 @@ sub display {
|
|||
CHOICE_PARAM => $self->conf->{authChoiceParam},
|
||||
CHOICE_VALUE => $req->data->{_authChoice},
|
||||
OLDPASSWORD => $self->checkXSSAttack( 'oldpassword',
|
||||
$req->data->{oldpassword} ) ? ""
|
||||
$req->data->{oldpassword} ) ? ''
|
||||
: $req->data->{oldpassword},
|
||||
HIDE_OLDPASSWORD => $self->conf->{hideOldPassword},
|
||||
DONT_STORE_PASSWORD => $self->conf->{browsersDontStorePassword},
|
||||
|
|
|
@ -17,7 +17,7 @@ use Lemonldap::NG::Portal::Main::Constants qw(
|
|||
|
||||
extends 'Lemonldap::NG::Portal::Main::Plugin';
|
||||
|
||||
our $VERSION = '2.0.12';
|
||||
our $VERSION = '2.0.14';
|
||||
|
||||
# INITIALIZATION
|
||||
|
||||
|
@ -59,7 +59,8 @@ sub _modifyPassword {
|
|||
)
|
||||
);
|
||||
unless ($oldPwdRule) {
|
||||
my $error = $self->p->HANDLER->tsv->{jail}->error || '???';
|
||||
my $error =
|
||||
$self->p->HANDLER->tsv->{jail}->error || 'Unable to compile rule';
|
||||
}
|
||||
|
||||
my $pwdPolicyRule = $self->p->HANDLER->buildSub(
|
||||
|
@ -68,7 +69,8 @@ sub _modifyPassword {
|
|||
)
|
||||
);
|
||||
unless ($pwdPolicyRule) {
|
||||
my $error = $self->p->HANDLER->tsv->{jail}->error || '???';
|
||||
my $error =
|
||||
$self->p->HANDLER->tsv->{jail}->error || 'Unable to compile rule';
|
||||
}
|
||||
|
||||
# Check if portal require old password
|
||||
|
|
|
@ -32,7 +32,7 @@ use Lemonldap::NG::Portal::Main::Constants qw(
|
|||
PE_PP_INSUFFICIENT_PASSWORD_QUALITY
|
||||
);
|
||||
|
||||
our $VERSION = '2.0.12';
|
||||
our $VERSION = '2.0.14';
|
||||
|
||||
extends qw(
|
||||
Lemonldap::NG::Portal::Lib::SMTP
|
||||
|
@ -58,6 +58,9 @@ has ott => (
|
|||
# Captcha generator
|
||||
has captcha => ( is => 'rw' );
|
||||
|
||||
# Password policy activation rule
|
||||
has passwordPolicyActivationRule => ( is => 'rw', default => sub { 0 } );
|
||||
|
||||
# INITIALIZATION
|
||||
|
||||
sub init {
|
||||
|
@ -70,6 +73,15 @@ sub init {
|
|||
if ( $self->conf->{captcha_mail_enabled} ) {
|
||||
$self->captcha( $self->p->loadModule('::Lib::Captcha') ) or return 0;
|
||||
}
|
||||
|
||||
# Parse password policy activation rule
|
||||
$self->passwordPolicyActivationRule(
|
||||
$self->p->buildRule(
|
||||
$self->conf->{passwordPolicyActivation},
|
||||
'passwordPolicyActivation'
|
||||
)
|
||||
);
|
||||
return 0 unless $self->passwordPolicyActivationRule;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -442,8 +454,32 @@ sub changePwd {
|
|||
"Reset password request for $req->{sessionInfo}->{_user}");
|
||||
|
||||
# Generate a complex password
|
||||
my $password =
|
||||
$self->gen_password( $self->conf->{randomPasswordRegexp} );
|
||||
my $pwdRegEx;
|
||||
if ( $self->passwordPolicyActivationRule->( $req, $req->sessionInfo )
|
||||
&& !$self->conf->{randomPasswordRegexp} )
|
||||
{
|
||||
my $uppers = $self->conf->{passwordPolicyMinUpper} || 3;
|
||||
my $lowers = $self->conf->{passwordPolicyMinLower} || 5;
|
||||
my $digits = $self->conf->{passwordPolicyMinDigit} || 2;
|
||||
my $chars =
|
||||
$self->conf->{passwordPolicyMinSize} -
|
||||
$self->conf->{passwordPolicyMinUpper} -
|
||||
$self->conf->{passwordPolicyMinLower} -
|
||||
$self->conf->{passwordPolicyMinDigit};
|
||||
$chars = 1 if $chars < 1;
|
||||
$pwdRegEx = "[A-Z]{$uppers}[a-z]{$lowers}\\d{$digits}";
|
||||
$pwdRegEx .=
|
||||
$self->conf->{passwordPolicySpecialChar} eq '__ALL__'
|
||||
? "\\W{$chars}"
|
||||
: "[$self->{conf}->{passwordPolicySpecialChar}]{$chars}";
|
||||
$self->logger->debug("Generated password RegEx: $pwdRegEx");
|
||||
}
|
||||
else {
|
||||
$pwdRegEx =
|
||||
$self->conf->{randomPasswordRegexp} || '[A-Z]{3}[a-z]{5}.\d{2}';
|
||||
$self->logger->debug("Used password RegEx: $pwdRegEx");
|
||||
}
|
||||
my $password = $self->gen_password($pwdRegEx);
|
||||
$self->logger->debug("Generated password: $password");
|
||||
$req->data->{newpassword} = $password;
|
||||
$req->data->{confirmpassword} = $password;
|
||||
|
@ -467,11 +503,13 @@ sub changePwd {
|
|||
}
|
||||
}
|
||||
|
||||
# Check password quality
|
||||
# Check password quality if enabled
|
||||
require Lemonldap::NG::Portal::Password::Base;
|
||||
my $cpq =
|
||||
$self->Lemonldap::NG::Portal::Password::Base::checkPasswordQuality(
|
||||
$req->data->{newpassword} );
|
||||
$self->passwordPolicyActivationRule->( $req, $req->sessionInfo )
|
||||
? $self->Lemonldap::NG::Portal::Password::Base::checkPasswordQuality(
|
||||
$req->data->{newpassword} )
|
||||
: PE_OK;
|
||||
unless ( $cpq == PE_OK ) {
|
||||
$self->ott->setToken( $req, $req->sessionInfo );
|
||||
return $cpq;
|
||||
|
@ -555,9 +593,19 @@ sub setSecurity {
|
|||
|
||||
sub display {
|
||||
my ( $self, $req ) = @_;
|
||||
my $speChars = $self->conf->{passwordPolicySpecialChar};
|
||||
my $speChars =
|
||||
$self->conf->{passwordPolicySpecialChar} eq '__ALL__'
|
||||
? ''
|
||||
: $self->conf->{passwordPolicySpecialChar};
|
||||
$speChars =~ s/\s+/ /g;
|
||||
$speChars =~ s/(?:^\s|\s$)//g;
|
||||
my $isPP =
|
||||
$self->conf->{passwordPolicyMinSize}
|
||||
|| $self->conf->{passwordPolicyMinLower}
|
||||
|| $self->conf->{passwordPolicyMinUpper}
|
||||
|| $self->conf->{passwordPolicyMinDigit}
|
||||
|| $self->conf->{passwordPolicyMinSpeChar}
|
||||
|| $speChars;
|
||||
$self->logger->debug( 'Display called with code: ' . $req->error );
|
||||
|
||||
my %tplPrm = (
|
||||
|
@ -576,7 +624,8 @@ sub display {
|
|||
STARTMAILTIME => $req->data->{startMailTime},
|
||||
MAILALREADYSENT => $req->data->{mailAlreadySent},
|
||||
MAIL => (
|
||||
$self->p->checkXSSAttack( 'mail', $req->{user} ) ? ''
|
||||
$self->p->checkXSSAttack( 'mail', $req->{user} )
|
||||
? ''
|
||||
: $req->{user}
|
||||
),
|
||||
DISPLAY_FORM => 0,
|
||||
|
@ -584,17 +633,13 @@ sub display {
|
|||
DISPLAY_CONFIRMMAILSENT => 0,
|
||||
DISPLAY_MAILSENT => 0,
|
||||
DISPLAY_PASSWORD_FORM => 0,
|
||||
DISPLAY_PPOLICY => $self->conf->{portalDisplayPasswordPolicy},
|
||||
PPOLICY_MINSIZE => $self->conf->{passwordPolicyMinSize},
|
||||
PPOLICY_MINLOWER => $self->conf->{passwordPolicyMinLower},
|
||||
PPOLICY_MINUPPER => $self->conf->{passwordPolicyMinUpper},
|
||||
PPOLICY_MINDIGIT => $self->conf->{passwordPolicyMinDigit},
|
||||
PPOLICY_ALLOWEDSPECHAR => $speChars,
|
||||
(
|
||||
$speChars
|
||||
? ( PPOLICY_MINSPECHAR => $self->conf->{passwordPolicyMinSpeChar} )
|
||||
: ()
|
||||
),
|
||||
DISPLAY_PPOLICY => $self->conf->{portalDisplayPasswordPolicy} && $isPP,
|
||||
PPOLICY_MINSIZE => $self->conf->{passwordPolicyMinSize},
|
||||
PPOLICY_MINLOWER => $self->conf->{passwordPolicyMinLower},
|
||||
PPOLICY_MINUPPER => $self->conf->{passwordPolicyMinUpper},
|
||||
PPOLICY_MINDIGIT => $self->conf->{passwordPolicyMinDigit},
|
||||
PPOLICY_MINSPECHAR => $self->conf->{passwordPolicyMinSpeChar},
|
||||
PPOLICY_ALLOWEDSPECHAR => $speChars,
|
||||
DISPLAY_GENERATE_PASSWORD =>
|
||||
$self->conf->{portalDisplayGeneratePassword},
|
||||
);
|
||||
|
|
|
@ -13,7 +13,7 @@ BEGIN {
|
|||
}
|
||||
|
||||
my ( $res, $user, $pwd );
|
||||
my $maintests = 17;
|
||||
my $maintests = 19;
|
||||
my $mailSend = 0;
|
||||
|
||||
my $mail2 = 0;
|
||||
|
@ -54,7 +54,12 @@ SKIP: {
|
|||
dbiAuthPasswordHash => '',
|
||||
dbiDynamicHashEnabled => 0,
|
||||
dbiMailCol => 'mail',
|
||||
portalDisplayPasswordPolicy => 1,
|
||||
passwordPolicyActivation => 0,
|
||||
passwordResetAllowedRetries => 4,
|
||||
passwordPolicyMinDigit => 2,
|
||||
passwordPolicyMinSpeChar => 1,
|
||||
passwordPolicySpecialChar => '__ALL__'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -141,8 +146,16 @@ SKIP: {
|
|||
# Post new password
|
||||
( $host, $url, $query ) = expectForm( $res, '#', undef, 'token' );
|
||||
ok( $res->[2]->[0] =~ /newpassword/s, ' Ask for a new password #4' );
|
||||
|
||||
$query .= '&newpassword=zz&confirmpassword=zz';
|
||||
ok(
|
||||
$res->[2]->[0] !~ /passwordPolicySpecialChar/,
|
||||
' Password special char list not found'
|
||||
);
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
/<span trspan="passwordPolicyMinDigit">Minimal digit characters:<\/span> 2/,
|
||||
' Found password policy min digit == 2'
|
||||
);
|
||||
$query .= '&newpassword=zz11#&confirmpassword=zz11#';
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/resetpwd', IO::String->new($query),
|
||||
|
@ -157,8 +170,8 @@ SKIP: {
|
|||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=zz'),
|
||||
length => 21
|
||||
IO::String->new('user=dwho&password=zz11#'),
|
||||
length => 24
|
||||
),
|
||||
'Auth query'
|
||||
);
|
||||
|
|
|
@ -10,7 +10,7 @@ BEGIN {
|
|||
}
|
||||
|
||||
my ( $res, $host, $url, $query );
|
||||
my $maintests = 16;
|
||||
my $maintests = 18;
|
||||
my $mailSend = 0;
|
||||
my $mail2 = 0;
|
||||
|
||||
|
@ -33,6 +33,13 @@ SKIP: {
|
|||
requireToken => 1,
|
||||
portalDisplayResetPassword => 1,
|
||||
portalMainLogo => 'common/logos/logo_llng_old.png',
|
||||
passwordPolicyActivation => 1,
|
||||
passwordPolicyMinUpper => 1,
|
||||
passwordPolicyMinLower => 1,
|
||||
passwordPolicyMinDigit => 2,
|
||||
passwordPolicyMinSpeChar => 1,
|
||||
randomPasswordRegexp => '',
|
||||
passwordPolicySpecialChar => '*#@'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -104,7 +111,7 @@ m#<img class="renewcaptchaclick" src="/static/common/icons/arrow_refresh.png"#,
|
|||
( $host, $url, $query ) = expectForm( $res, '#', undef, 'token' );
|
||||
ok( $res->[2]->[0] =~ /newpassword/s, ' Ask for a new password' );
|
||||
|
||||
$query .= '&newpassword=zz&confirmpassword=zz';
|
||||
$query .= '&reset=1';
|
||||
|
||||
# Post new password
|
||||
ok(
|
||||
|
@ -115,7 +122,9 @@ m#<img class="renewcaptchaclick" src="/static/common/icons/arrow_refresh.png"#,
|
|||
),
|
||||
'Post new password'
|
||||
);
|
||||
ok( mail() =~ /Your password was changed/, 'Password was changed' );
|
||||
ok( mail() =~ /<span>Your new password is<\/span>/, 'New password sent' );
|
||||
ok( mail() =~ /<b>(.+?)<\/b>/s, 'New generated password found' );
|
||||
ok( $1 =~ /[A-Z]{1}[a-z]{1}\d{2}[*#@]{1}/, 'New generated password matches' );
|
||||
|
||||
#print STDERR Dumper($query);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ BEGIN {
|
|||
}
|
||||
|
||||
my ( $res, $user, $pwd );
|
||||
my $maintests = 12;
|
||||
my $maintests = 18;
|
||||
|
||||
SKIP: {
|
||||
eval
|
||||
|
@ -21,15 +21,22 @@ SKIP: {
|
|||
|
||||
my $client = LLNG::Manager::Test->new( {
|
||||
ini => {
|
||||
logLevel => 'error',
|
||||
useSafeJail => 1,
|
||||
portalDisplayRegister => 1,
|
||||
authentication => 'Demo',
|
||||
userDB => 'Same',
|
||||
passwordDB => 'Demo',
|
||||
captcha_mail_enabled => 0,
|
||||
portalDisplayResetPassword => 1,
|
||||
portalMainLogo => 'common/logos/logo_llng_old.png',
|
||||
logLevel => 'error',
|
||||
useSafeJail => 1,
|
||||
portalDisplayRegister => 1,
|
||||
authentication => 'Demo',
|
||||
userDB => 'Same',
|
||||
passwordDB => 'Demo',
|
||||
captcha_mail_enabled => 0,
|
||||
portalDisplayResetPassword => 1,
|
||||
portalMainLogo => 'common/logos/logo_llng_old.png',
|
||||
portalDisplayPasswordPolicy => 1,
|
||||
passwordPolicyActivation => 1,
|
||||
passwordPolicyMinUpper => 1,
|
||||
passwordPolicyMinLower => 1,
|
||||
passwordPolicyMinDigit => 2,
|
||||
passwordPolicyMinSpeChar => 1,
|
||||
passwordPolicySpecialChar => '&%#'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -87,8 +94,34 @@ SKIP: {
|
|||
);
|
||||
( $host, $url, $query ) = expectForm( $res, '#', undef, 'token' );
|
||||
ok( $res->[2]->[0] =~ /newpassword/s, ' Ask for a new password' );
|
||||
|
||||
$query .= '&newpassword=zz&confirmpassword=zz';
|
||||
ok( $res->[2]->[0] =~ /<span trspan="passwordPolicy">/,
|
||||
' Found password policy' );
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
/<span trspan="passwordPolicyMinLower">Minimal lower characters:<\/span> 1/,
|
||||
' Found password policy min lower == 1'
|
||||
);
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
/<span trspan="passwordPolicyMinUpper">Minimal upper characters:<\/span> 1/,
|
||||
' Found password policy min upper == 1'
|
||||
);
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
/<span trspan="passwordPolicyMinDigit">Minimal digit characters:<\/span> 2/,
|
||||
' Found password policy min digit == 2'
|
||||
);
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
/<span trspan="passwordPolicyMinSpeChar">Minimal special characters:<\/span> 1/,
|
||||
' Found password policy min speChar == 1'
|
||||
);
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
/<span trspan="passwordPolicySpecialChar">Allowed special characters:<\/span> &%#/,
|
||||
' Found password special char list'
|
||||
);
|
||||
$query .= '&newpassword=zZ11#&confirmpassword=zZ11#';
|
||||
|
||||
# Post new password
|
||||
ok(
|
||||
|
|
Loading…
Reference in New Issue