X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;ds=sidebyside;f=FS%2FFS%2FPassword_Mixin.pm;h=a27dd54534ad724e83fcc982c1c656f8c531504f;hb=c90a529450dd85902449788fd83940471be50377;hp=4ecf4c6116607a393986f607a7110d804004c5d4;hpb=2e1e59ea99e9672310b59f57cfade4626c33190f;p=freeside.git diff --git a/FS/FS/Password_Mixin.pm b/FS/FS/Password_Mixin.pm index 4ecf4c611..a27dd5453 100644 --- a/FS/FS/Password_Mixin.pm +++ b/FS/FS/Password_Mixin.pm @@ -6,6 +6,7 @@ use FS::password_history; use Authen::Passphrase; use Authen::Passphrase::BlowfishCrypt; # https://rt.cpan.org/Ticket/Display.html?id=72743 +use Data::Password qw(:all); our $DEBUG = 0; our $conf; @@ -36,7 +37,7 @@ message on failure, an empty string on success. This MUST NOT be called from check(). It should be called by the office UI, self-service ClientAPI, or other I code that processes a password change, and only if the user has taken some action with the intent -of changing the password. +of setting the password. =cut @@ -44,7 +45,54 @@ sub is_password_allowed { my $self = shift; my $password = shift; - # check length and complexity here + my $cust_main = $self->cust_main; + return '' if $cust_main && $conf->config_bool('password-insecure', $cust_main->agentnum); + + # basic checks using Data::Password; + # options for Data::Password + $DICTIONARY = 4; # minimum length of disallowed words + $MINLEN = $conf->config('passwordmin') || 6; + $MAXLEN = $conf->config('passwordmax') || 8; + $GROUPS = 4; # must have all 4 'character groups': numbers, symbols, uppercase, lowercase + # other options use the defaults listed below: + # $FOLLOWING = 3; # disallows more than 3 chars in a row, by alphabet or keyboard (ie abcd or asdf) + # $SKIPCHAR = undef; # set to true to skip checking for bad characters + # # lists of disallowed words + # @DICTIONARIES = qw( /usr/share/dict/web2 /usr/share/dict/words /usr/share/dict/linux.words ); + + my $error = IsBadPassword($password); + $error = 'must contain at least one each of numbers, symbols, and lowercase and uppercase letters' + if $error eq 'contains less than 4 character groups'; # avoid confusion + $error = 'Invalid password - ' . $error if $error; + return $error if $error; + + #check against service fields + $error = $self->password_svc_check($password); + return $error if $error; + + return '' unless $self->get($self->primary_key); # for validating new passwords pre-insert + + #check against customer fields + if ($cust_main) { + my @words; + # words from cust_main + foreach my $field ( qw( last first daytime night fax mobile ) ) { + push @words, split(/\W/,$cust_main->get($field)); + } + # words from cust_location + foreach my $loc ($cust_main->cust_location) { + foreach my $field ( qw(address1 address2 city county state zip) ) { + push @words, split(/\W/,$loc->get($field)); + } + } + # do the actual checking + foreach my $word (@words) { + next unless length($word) > 2; + if ($password =~ /$word/i) { + return qq(Password contains account information '$word'); + } + } + } if ( $conf->config('password-no_reuse') =~ /^(\d+)$/ ) { @@ -80,6 +128,17 @@ sub is_password_allowed { ''; } +=item password_svc_check + +Override to run additional service-specific password checks. + +=cut + +sub password_svc_check { + my ($self, $password) = @_; + return ''; +} + =item password_history_key Returns the name of the field in L that's the foreign