This MUST NOT be called from check(). It should be called by the office UI,
self-service ClientAPI, or other I<user-interactive> 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
# options for Data::Password
$DICTIONARY = 4; # minimum length of disallowed words
$MINLEN = $conf->config('passwordmin') || 6;
- $MAXLEN = $conf->config('passwordmax') || 8;
+ $MAXLEN = $conf->config('passwordmax') || 12;
$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)
$error = 'Invalid password - ' . $error if $error;
return $error if $error;
- #check against known usernames
- my @disallowed_names = $self->password_disallowed_names;
- foreach my $noname (@disallowed_names) {
- if ($password =~ /$noname/i) {
- #keeping message ambiguous to avoid leaking personal info
- return 'Password contains a disallowed word';
- }
- }
+ #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
+ my $cust_main = $self->cust_main;
+ 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));
+ }
+ }
+ # words from cust_contact & contact_phone
+ foreach my $contact (map { $_->contact } $cust_main->cust_contact) {
+ foreach my $field ( qw(last first) ) {
+ push @words, split(/\W/,$contact->get($field));
+ }
+ # not hugely useful right now, hyphenless stored values longer than password max,
+ # but max will probably be increased eventually...
+ foreach my $phone ( qsearch('contact_phone', {'contactnum' => $contact->contactnum}) ) {
+ push @words, split(/\W/,$phone->get('phonenum'));
+ }
+ }
+ # do the actual checking
+ foreach my $word (@words) {
+ next unless length($word) > 2;
+ if ($password =~ /$word/i) {
+ return qq(Password contains account information '$word');
+ }
+ }
+ }
+
my $no_reuse = 3;
# allow override here if we really must
'';
}
-=item password_disallowed_names
+=item password_svc_check
-Override to return a list additional words (eg usernames) not
-to be used by passwords on this service.
+Override to run additional service-specific password checks.
=cut
-sub password_disallowed_names {
- return ();
+sub password_svc_check {
+ my ($self, $password) = @_;
+ return '';
}
=item password_history_key