use strict;
use Mouse;
PE_OK
PE_ERROR
PE_PP_PASSWORD_TOO_LONG
PE_PP_PASSWORD_TOO_SHORT
PE_PP_NOT_ALLOWED_CHARACTER
PE_PP_NOT_ALLOWED_CHARACTERS
PE_PP_INSUFFICIENT_PASSWORD_QUALITY
);
our $VERSION = '2.20.0';
use constant hook => { passwordBeforeChange => 'checkPasswordQuality', };
has pwdPolicyRule => ( is => 'rw' );
sub init {
my ($self) = @_;
my $pwdPolicyRule = $self->p->buildRule(
$self->conf->{passwordPolicyActivation},
"Password policy activation rule"
);
$self->pwdPolicyRule($pwdPolicyRule);
return 0 unless $pwdPolicyRule;
$self->p->addPasswordPolicyDisplay(
'ppolicy-minsize',
{
condition => $self->conf->{passwordPolicyMinSize},
value => $self->conf->{passwordPolicyMinSize},
label => "passwordPolicyMinSize",
order => 101,
}
);
$self->p->addPasswordPolicyDisplay(
'ppolicy-minlower',
{
condition => $self->conf->{passwordPolicyMinLower},
value => $self->conf->{passwordPolicyMinLower},
label => "passwordPolicyMinLower",
order => 102,
}
);
$self->p->addPasswordPolicyDisplay(
'ppolicy-minupper',
{
condition => $self->conf->{passwordPolicyMinUpper},
value => $self->conf->{passwordPolicyMinUpper},
label => "passwordPolicyMinUpper",
order => 103,
}
);
$self->p->addPasswordPolicyDisplay(
'ppolicy-mindigit',
{
condition => $self->conf->{passwordPolicyMinDigit},
value => $self->conf->{passwordPolicyMinDigit},
label => "passwordPolicyMinDigit",
order => 104,
}
);
$self->p->addPasswordPolicyDisplay(
'ppolicy-minspechar',
{
condition => (
$self->conf->{passwordPolicyMinSpeChar}
&& $self->conf->{passwordPolicySpecialChar}
),
value => $self->conf->{passwordPolicyMinSpeChar},
label => "passwordPolicyMinSpeChar",
order => 105,
}
);
$self->p->addPasswordPolicyDisplay(
'ppolicy-allowedspechar',
{
condition => (
$self->conf->{passwordPolicyMinSpeChar} && $self->p->speChars()
),
value => $self->p->speChars(),
label => "passwordPolicySpecialChar",
order => 106,
}
);
$self->p->addPasswordPolicyDisplay(
'ppolicy-maxsize',
{
condition => $self->conf->{passwordPolicyMaxSize},
value => $self->conf->{passwordPolicyMaxSize},
label => "passwordPolicyMaxSize",
order => 107,
}
);
return 1;
}
sub checkPasswordQuality {
my ( $self, $req, $user, $password, $old ) = @_;
if ( $self->pwdPolicyRule->( $req, $req->userData ) ) {
$self->logger->debug("Checking basic password policy for $user");
return $self->checkBasicPolicy($password);
}
else {
$self->logger->debug("Skipping basic password policy for $user");
return PE_OK;
}
}
sub checkBasicPolicy {
my ( $self, $password, $old ) = @_;
# Min size
if ( $self->conf->{passwordPolicyMinSize}
and length($password) < $self->conf->{passwordPolicyMinSize} )
{
$self->logger->error("Password too short");
return PE_PP_PASSWORD_TOO_SHORT;
}
# Max size
if ( $self->conf->{passwordPolicyMaxSize}
and length($password) > $self->conf->{passwordPolicyMaxSize} )
{
$self->logger->error("Password too long");
return PE_PP_PASSWORD_TOO_LONG;
}
# Min lower
if ( $self->conf->{passwordPolicyMinLower} ) {
my $lower = 0;
$lower++ while ( $password =~ m/\p{lowercase}/g );
if ( $lower < $self->conf->{passwordPolicyMinLower} ) {
$self->logger->error("Password has not enough lower characters");
return PE_PP_INSUFFICIENT_PASSWORD_QUALITY;
}
}
# Min upper
if ( $self->conf->{passwordPolicyMinUpper} ) {
my $upper = 0;
$upper++ while ( $password =~ m/\p{uppercase}/g );
if ( $upper < $self->conf->{passwordPolicyMinUpper} ) {
$self->logger->error("Password has not enough upper characters");
return PE_PP_INSUFFICIENT_PASSWORD_QUALITY;
}
}
# Min digit
if ( $self->conf->{passwordPolicyMinDigit} ) {
my $digit = 0;
$digit++ while ( $password =~ m/\d/g );
if ( $digit < $self->conf->{passwordPolicyMinDigit} ) {
$self->logger->error("Password has not enough digit characters");
return PE_PP_INSUFFICIENT_PASSWORD_QUALITY;
}
}
### Special characters policy
my $speChars = $self->conf->{passwordPolicySpecialChar};
## Min special characters
# Just number of special characters must be checked
if ( $self->conf->{passwordPolicyMinSpeChar} && $speChars eq '__ALL__' ) {
my $spe = $password =~ s/[\W_]//g;
if ( $spe < $self->conf->{passwordPolicyMinSpeChar} ) {
$self->logger->error("Password has not enough special characters");
return PE_PP_INSUFFICIENT_PASSWORD_QUALITY;
}
return PE_OK;
}
# Check number of special characters
if ( $self->conf->{passwordPolicyMinSpeChar} && $speChars ) {
my $test = $password;
my $spe = $test =~ s/[\Q$speChars\E]//g;
if ( $spe < $self->conf->{passwordPolicyMinSpeChar} ) {
$self->logger->error("Password has not enough special characters");
return PE_PP_INSUFFICIENT_PASSWORD_QUALITY;
}
}
## Fobidden special characters
unless ( $speChars eq '__ALL__' ) {
$password =~ s/[\Q$speChars\E\w]//g;
if ($password) {
$self->logger->error( 'Password contains '
. length($password)
. " forbidden character(s): $password" );
return length($password) > 1
? PE_PP_NOT_ALLOWED_CHARACTERS
: PE_PP_NOT_ALLOWED_CHARACTER;
}
}
return PE_OK;
}
1;