RT#38973: Bill for time worked on ticket resolution [validate queueids]
[freeside.git] / FS / FS / Password_Mixin.pm
index f07f772..2e400ec 100644 (file)
@@ -16,6 +16,8 @@ FS::UID->install_callback( sub {
     #eval "use Authen::Passphrase::BlowfishCrypt;";
 });
 
+our @pw_set;
+
 our $me = '[' . __PACKAGE__ . ']';
 
 our $BLOWFISH_COST = 10;
@@ -52,12 +54,13 @@ sub is_password_allowed {
     my $cust_pkg = FS::cust_pkg->by_key($self->get('pkgnum'));
     $cust_main = $cust_pkg->cust_main if $cust_pkg;
   }
+  # selfservice signup invokes this without customer, but it checks this conf separately
   warn "is_password_allowed: no customer could be identified" if !$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
+  $DICTIONARY = 0;   # minimum length of disallowed words, false value disables dictionary checking
   $MINLEN = $conf->config('passwordmin') || 6;
   $MAXLEN = $conf->config('passwordmax') || 8;
   $GROUPS = 4;       # must have all 4 'character groups': numbers, symbols, uppercase, lowercase
@@ -67,9 +70,23 @@ sub is_password_allowed {
   # # lists of disallowed words
   # @DICTIONARIES = qw( /usr/share/dict/web2 /usr/share/dict/words /usr/share/dict/linux.words );
 
+  # first, no dictionary checking but require 4 char groups
   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
+
+  # but they can get away with 3 char groups, so long as they're not using a word
+  if ($error eq 'contains less than 4 character groups') {
+    $DICTIONARY = 4; # default from Data::Password is 5
+    $GROUPS = 3;
+    $error = IsBadPassword($password);
+    # take note--we never actually report dictionary word errors;
+    # 4 char groups is the rule, 3 char groups and no dictionary words is an acceptable exception
+    $error = 'should contain at least one each of numbers, symbols, lowercase and uppercase letters'
+      if $error;
+  }
+
+  # maybe also at some point add an exception for any passwords of sufficient length,
+  # see https://xkcd.com/936/
+
   $error = 'Invalid password - ' . $error if $error;
   return $error if $error;
 
@@ -253,6 +270,37 @@ sub _blowfishcrypt {
 
 =back
 
+=head1 CLASS METHODS
+
+=over 4
+
+=item pw_set
+
+Returns the list of characters allowed in random passwords (from the
+C<password-generated-characters> config).
+
+=cut
+
+sub pw_set {
+  my $class = shift;
+  if (!@pw_set) {
+    my $pw_set = $conf->config('password-generated-characters');
+    $pw_set =~ s/\s//g; # don't ever allow whitespace
+    if ( $pw_set =~ /[[:lower:]]/
+      && $pw_set =~ /[[:upper:]]/
+      && $pw_set =~ /[[:digit:]]/
+      && $pw_set =~ /[[:punct:]]/ ) {
+      @pw_set = split('', $pw_set);
+    } else {
+      warn "password-generated-characters set is insufficient; using default.";
+      @pw_set = split('', 'abcdefghijkmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ23456789()#.,');
+    }
+  }
+  return @pw_set;
+}
+
+=back
+
 =head1 SEE ALSO
 
 L<FS::password_history>