[LON-CAPA-cvs] cvs: loncom / lond /interface domainprefs.pm resetpw.pm /lonnet/perl lonnet.pm

raeburn raeburn at source.lon-capa.org
Fri Apr 26 16:22:28 EDT 2019


raeburn		Fri Apr 26 20:22:28 2019 EDT

  Modified files:              
    /loncom	lond 
    /loncom/interface	domainprefs.pm resetpw.pm 
    /loncom/lonnet/perl	lonnet.pm 
  Log:
  - Domain Configuration for Passwords for internally authenticated users.
    - Rules for LON-CAPA passwords can include: number of user's previous
      passwords to save (with reuser by that user disallowed).
  
  
-------------- next part --------------
Index: loncom/lond
diff -u loncom/lond:1.557 loncom/lond:1.558
--- loncom/lond:1.557	Mon Feb 11 17:01:34 2019
+++ loncom/lond	Fri Apr 26 20:22:10 2019
@@ -2,7 +2,7 @@
 # The LearningOnline Network
 # lond "LON Daemon" Server (port "LOND" 5663)
 #
-# $Id: lond,v 1.557 2019/02/11 17:01:34 raeburn Exp $
+# $Id: lond,v 1.558 2019/04/26 20:22:10 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -65,7 +65,7 @@
 my $status='';
 my $lastlog='';
 
-my $VERSION='$Revision: 1.557 $'; #' stupid emacs
+my $VERSION='$Revision: 1.558 $'; #' stupid emacs
 my $remoteVERSION;
 my $currenthostid="default";
 my $currentdomainid;
@@ -2348,12 +2348,84 @@
     }
     if($validated) {
 	my $realpasswd  = &get_auth_type($udom, $uname); # Defined since authd.
-	
 	my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
+        my $notunique;
 	if ($howpwd eq 'internal') {
 	    &Debug("internal auth");
             my $ncpass = &hash_passwd($udom,$npass);
-	    if(&rewrite_password_file($udom, $uname, "internal:$ncpass")) {
+            my (undef,$method, at rest) = split(/!/,$contentpwd);
+            if ($method eq 'bcrypt') {
+                my %passwdconf = &Apache::lonnet::get_passwdconf($udom);
+                if (($passwdconf{'numsaved'}) && ($passwdconf{'numsaved'} =~ /^\d+$/)) {
+                    my @oldpasswds;
+                    my $userpath = &propath($udom,$uname);
+                    my $fullpath = $userpath.'/oldpasswds';
+                    if (-d $userpath) {
+                        my @oldfiles;
+                        if (-e $fullpath) {
+                            if (opendir(my $dir,$fullpath)) {
+                                (@oldfiles) = grep(/^\d+$/,readdir($dir));
+                                closedir($dir);
+                            }
+                            if (@oldfiles) {
+                                @oldfiles = sort { $b <=> $a } (@oldfiles);
+                                my $numremoved = 0;
+                                for (my $i=0; $i<@oldfiles; $i++) {
+                                    if ($i>=$passwdconf{'numsaved'}) {
+                                        if (-f "$fullpath/$oldfiles[$i]") {
+                                            if (unlink("$fullpath/$oldfiles[$i]")) {
+                                                $numremoved ++;
+                                            }
+                                        }
+                                    } elsif (open(my $fh,'<',"$fullpath/$oldfiles[$i]")) {
+                                        while (my $line = <$fh>) {
+                                            push(@oldpasswds,$line);
+                                        }
+                                        close($fh);
+                                    }
+                                }
+                                if ($numremoved) {
+                                    &logthis("unlinked $numremoved old password files for $uname:$udom");
+                                }
+                            }
+                        }
+                        push(@oldpasswds,$contentpwd);
+                        foreach my $item (@oldpasswds) {
+                            my (undef,$method, at rest) = split(/!/,$item);
+                            if ($method eq 'bcrypt') {
+                                my $result = &hash_passwd($udom,$npass, at rest);
+                                if ($result eq $item) {
+                                    $notunique = 1;
+                                    last;
+                                }
+                            }
+                        }
+                        unless ($notunique) {
+                            unless (-e $fullpath) {
+                                if (&mkpath("$fullpath/")) {
+                                    chmod(0700,$fullpath);
+                                }
+                            }
+                            if (-d $fullpath) {
+                                my $now = time;
+                                if (open(my $fh,'>',"$fullpath/$now")) {
+                                    print $fh $contentpwd;
+                                    close($fh);
+                                    chmod(0400,"$fullpath/$now");
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            if ($notunique) {
+                my $msg="Result of password change for $uname:$udom - password matches one used before";
+                if ($lonhost) {
+                    $msg .= " - request originated from: $lonhost";
+                }
+                &logthis($msg);
+                &Reply($client, "prioruse\n", $userinput);
+	    } elsif (&rewrite_password_file($udom, $uname, "internal:$ncpass")) {
 		my $msg="Result of password change for $uname: pwchange_success";
                 if ($lonhost) {
                     $msg .= " - request originated from: $lonhost";
@@ -2381,7 +2453,6 @@
 	    #
 	    &Failure( $client, "auth_mode_error\n", $userinput);
 	}  
-	
     } else {
 	if ($failure eq '') {
 	    $failure = 'non_authorized';
Index: loncom/interface/domainprefs.pm
diff -u loncom/interface/domainprefs.pm:1.355 loncom/interface/domainprefs.pm:1.356
--- loncom/interface/domainprefs.pm:1.355	Fri Apr 26 20:15:30 2019
+++ loncom/interface/domainprefs.pm	Fri Apr 26 20:22:18 2019
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set domain-wide configuration settings
 #
-# $Id: domainprefs.pm,v 1.355 2019/04/26 20:15:30 raeburn Exp $
+# $Id: domainprefs.pm,v 1.356 2019/04/26 20:22:18 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -5822,6 +5822,7 @@
         max            => 'Maximum password length',
         chars          => 'Required characters',
         expire         => 'Password expiration (days)',
+        numsaved       => 'Number of previous passwords to save and disallow reuse',
     );
     if ($position eq 'top') {
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
@@ -6085,7 +6086,7 @@
             $itemcount ++;
         }
     } elsif ($position eq 'lower') {
-        my ($min,$max,%chars,$expire);
+        my ($min,$max,%chars,$expire,$numsaved);
         if (ref($settings) eq 'HASH') {
             if ($settings->{min}) {
                 $min = $settings->{min};
@@ -6099,6 +6100,9 @@
             if ($settings->{expire}) {
                 $expire = $settings->{expire};
             }
+            if ($settings->(numsaved}) {
+                $numsaved = $settings->(numsaved};
+            }
         } else {
             $min = '7';
         }
@@ -6161,6 +6165,13 @@
                       '<input type="text" name="passwords_expire" value="'.$expire.'" size="4" />'.
                       '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no expiration)').'</span>'.
                       '</span></td></tr>';
+        $itemcount ++;
+        $css_class = $itemcount%2?' class="LC_odd_row"':'';
+        $datatable .= '<tr'.$css_class.'><td>'.$titles{'numsaved'}.'</td>'.
+                      '<td class="LC_left_item"><span class="LC_nobreak">'.
+                      '<input type="text" name="passwords_numsaved" value="'.$numsaved.'" size="3" />'.
+                      '<span class="LC_fontsize_small"> '.&mt('(Leave blank to not save previous passwords)').'</span>'.
+                      '</span></td></tr>';
     } else {
         my $checkedon;
         my $checkedoff = ' checked="checked"';
@@ -13984,6 +13995,7 @@
         max            => 'Maximum password length',
         chars          => 'Required characters',
         expire         => 'Password expiration (days)',
+        numsaved       => 'Number of previous passwords to save',
         reset          => 'Resetting Forgotten Password',
         intauth        => 'Encryption of Stored Passwords (Internal Auth)',
         rules          => 'Rules for LON-CAPA Passwords',
@@ -14191,9 +14203,17 @@
             $updatedefaults = 1;
         }
     }
-    foreach my $rule ('min','max','expire') {
+    foreach my $rule ('min','max','expire','numsaved') {
         $env{'form.passwords_'.$rule} =~ s/^\s+|\s+$//g;
-        if ($env{'form.passwords_'.$rule} =~ /^(|\d+(|\.\d*))$/) {
+        my $ruleok;
+        if ($rule eq 'expire') {
+            if ($env{'form.passwords_'.$rule} =~ /^\d+(|\.\d*)$/) {
+                $ruleok = 1; 
+            }
+        } elsif ($env{'form.passwords_'.$rule} =~ /^\d+$/) {
+            $ruleok = 1;
+        }
+        if ($ruleok) {
             $newvalues{$rule} = $env{'form.passwords_'.$rule};
             if (exists($current{$rule})) {
                 if ($newvalues{$rule} ne $current{$rule}) {
@@ -14373,13 +14393,14 @@
                             $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$titles{$key.'_'.$item},$value).'</li>';
                         }
                     } elsif ($key eq 'rules') {
-                        foreach my $rule ('min','max','expire') {
+                        foreach my $rule ('min','max','expire','numsaved') {
                             if ($confighash{'passwords'}{$rule} eq '') {
-                                $resulttext .= '<li>'.&mt('[_1] not set.',$titles{$rule});
                                 if ($rule eq 'min') {
-                                   $resulttext .= ' '.&mt('Default of 7 will be used');
+                                    $resulttext .= '<li>'.&mt('[_1] not set.',$titles{$rule});
+                                                   ' '.&mt('Default of 7 will be used').'</li>';
+                                } else {
+                                    $resulttext .= '<li>'.&mt('[_1] set to none',$titles{$rule}).'</li>';
                                 }
-                                $resulttext .= '</li>';
                             } else {
                                 $resulttext .= '<li>'.&mt('[_1] set to [_2]',$titles{$rule},$confighash{'passwords'}{$rule}).'</li>';
                             }
Index: loncom/interface/resetpw.pm
diff -u loncom/interface/resetpw.pm:1.44 loncom/interface/resetpw.pm:1.45
--- loncom/interface/resetpw.pm:1.44	Wed Apr 24 01:44:30 2019
+++ loncom/interface/resetpw.pm	Fri Apr 26 20:22:18 2019
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Allow access to password changing via a token sent to user's e-mail. 
 #
-# $Id: resetpw.pm,v 1.44 2019/04/24 01:44:30 raeburn Exp $
+# $Id: resetpw.pm,v 1.45 2019/04/26 20:22:18 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -720,6 +720,15 @@
                            .'</p>'
                         );
                     }
+                } elsif (($change_failed eq 'prioruse') && ($passwdconf->{'numsaved'})) {
+                    my $domdesc =
+                        &Apache::lonnet::domain($data{'domain'},'description');
+                    $r->print(
+                          '<p class="LC_warning">'
+                         .&mt('Please enter a password that you have not used recently.')
+                         .'</p>'
+                         .&display_actions($contact_email,$domdesc)
+                    );
                 } else {
                     $r->print(&generic_failure_msg($contact_name,$contact_email));
                 }
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1407 loncom/lonnet/perl/lonnet.pm:1.1408
--- loncom/lonnet/perl/lonnet.pm:1.1407	Wed Apr 24 01:44:46 2019
+++ loncom/lonnet/perl/lonnet.pm	Fri Apr 26 20:22:27 2019
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.1407 2019/04/24 01:44:46 raeburn Exp $
+# $Id: lonnet.pm,v 1.1408 2019/04/26 20:22:27 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -1252,6 +1252,9 @@
     } elsif ($answer =~ "invalid_client") {
         &logthis("$server refused to change $uname in $udom password because ".
                  "it was a reset by e-mail originating from an invalid server.");
+    } elsif ($answer =~ "^prioruse") {
+       &logthis("$server refused to change $uname in $udom password because ".
+                "the password had been used before");
     }
     return $answer;
 }


More information about the LON-CAPA-cvs mailing list