[LON-CAPA-cvs] cvs: loncom / lond /auth lonauth.pm londes.js lonlogin.pm /interface createaccount.pm loncommon.pm loncreateuser.pm lonpreferences.pm

raeburn raeburn at source.lon-capa.org
Wed Feb 17 14:15:49 EST 2016


raeburn		Wed Feb 17 19:15:49 2016 EDT

  Modified files:              
    /loncom/auth	lonlogin.pm lonauth.pm londes.js 
    /loncom	lond 
    /loncom/interface	lonpreferences.pm createaccount.pm 
                     	loncreateuser.pm loncommon.pm 
  Log:
  - Bug 5679
  
  
-------------- next part --------------
Index: loncom/auth/lonlogin.pm
diff -u loncom/auth/lonlogin.pm:1.164 loncom/auth/lonlogin.pm:1.165
--- loncom/auth/lonlogin.pm:1.164	Sat Jun  6 14:39:42 2015
+++ loncom/auth/lonlogin.pm	Wed Feb 17 19:15:39 2016
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Login Screen
 #
-# $Id: lonlogin.pm,v 1.164 2015/06/06 14:39:42 raeburn Exp $
+# $Id: lonlogin.pm,v 1.165 2016/02/17 19:15:39 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -352,18 +352,9 @@
 lextkey=this.document.client.elements.lextkey.value;
 initkeys();
 
-this.document.server.elements.upass0.value
-    =this.document.client.elements.upass$now.value.substr(0,15);
-this.document.server.elements.upass1.value
-    =this.document.client.elements.upass$now.value.substr(15,15);
-this.document.server.elements.upass2.value
-    =this.document.client.elements.upass$now.value.substr(30,15);
-
 if(this.document.server.action.substr(0,5) === 'http:'){
-    for (var idx in [1,2,3]){
-        this.document.server.elements['upass' + idx].value = 
-            crypted(this.document.server.elements['upass' + idx].value);
-    }
+    this.document.server.elements.upass0.value
+        =getCrypted(this.document.client.elements.upass$now.value);
 }
 
 this.document.client.elements.uname.value='';
@@ -479,8 +470,6 @@
    <input type="hidden" name="serverid" value="$lonhost" />
    <input type="hidden" name="uname" value="" />
    <input type="hidden" name="upass0" value="" />
-   <input type="hidden" name="upass1" value="" />
-   <input type="hidden" name="upass2" value="" />
    <input type="hidden" name="udom" value="" />
    <input type="hidden" name="localpath" value="$env{'form.localpath'}" />
    <input type="hidden" name="localres" value="$env{'form.localres'}" />
Index: loncom/auth/lonauth.pm
diff -u loncom/auth/lonauth.pm:1.138 loncom/auth/lonauth.pm:1.139
--- loncom/auth/lonauth.pm:1.138	Fri Mar  6 21:56:41 2015
+++ loncom/auth/lonauth.pm	Wed Feb 17 19:15:40 2016
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # User Authentication Module
 #
-# $Id: lonauth.pm,v 1.138 2015/03/06 21:56:41 raeburn Exp $
+# $Id: lonauth.pm,v 1.139 2016/02/17 19:15:40 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -346,8 +346,8 @@
         (undef,$form{'iptoken'}) = split('=',$iptokenstr);
     }
 
-    my $upass = $ENV{HTTPS} ? join("", @form{qw(upass0 upass1 upass2)}) 
-        : decrypt($key, @form{qw(upass0 upass1 upass2)});
+    my $upass = $ENV{HTTPS} ? $form{'upass0'} 
+        : &Apache::loncommon::des_decrypt($key,$form{'upass0'});
 
 # ---------------------------------------------------------------- Authenticate
 
@@ -525,34 +525,6 @@
     }
 }
 
-sub decrypt {
-    my ($key, @chunks) = @_;
-
-    my $keybin = pack("H16",$key);
-
-    my $cipher;
-    if ($Crypt::DES::VERSION >= 2.03) {
-        $cipher = new Crypt::DES $keybin;
-    } else {
-        $cipher = new DES $keybin;
-    }
-
-    my $upass='';
-    for (my $i=0;$i<=2;$i++) {
-        my $chunk =
-            $cipher->decrypt(
-                unpack("a8",pack("H16",substr($chunks[$i],0,16))));
-
-        $chunk .=
-            $cipher->decrypt(
-                unpack("a8",pack("H16",substr($chunks[$i],16,16))));
-
-        $chunk = substr($chunk,1,ord(substr($chunk,0,1)));
-        $upass .= $chunk;
-    }
-    return $upass;
-}
-
 sub check_can_host {
     my ($r,$form,$authhost,$domdesc) = @_;
     return unless (ref($form) eq 'HASH');
Index: loncom/auth/londes.js
diff -u loncom/auth/londes.js:1.9 loncom/auth/londes.js:1.10
--- loncom/auth/londes.js:1.9	Fri May 22 17:01:28 2009
+++ loncom/auth/londes.js	Wed Feb 17 19:15:40 2016
@@ -4,7 +4,7 @@
 // Encryption Routines according to Data Encryption Standard DES
 // Federal Information Processing Standards Publication 46-2 (1993 Dec 30)
 //
-// $Id: londes.js,v 1.9 2009/05/22 17:01:28 bisitz Exp $
+// $Id: londes.js,v 1.10 2016/02/17 19:15:40 raeburn Exp $
 //
 // Copyright Michigan State University Board of Trustees
 //
@@ -376,5 +376,22 @@
     return(hexstring(b3)+hexstring(b2)+hexstring(b1)+hexstring(b0));
 }
 
+function getCrypted(text) {
+    var cryptedtext = '';
+    if (text.length > 0) {
+        var rem = text.length % 15;
+        var count = Math.floor(text.length/15);
+        if (rem > 0) {
+            count ++;
+        }
+        for (var i=0; i<count; i++) {
+            var start = i*15;
+            cryptedtext += crypted(text.substr(start,15));
+        }
+    }
+    return cryptedtext;
+}
+
+
 // ]]>
 </script>
Index: loncom/lond
diff -u loncom/lond:1.517 loncom/lond:1.518
--- loncom/lond:1.517	Sun Jan 31 21:25:53 2016
+++ loncom/lond	Wed Feb 17 19:15:44 2016
@@ -2,7 +2,7 @@
 # The LearningOnline Network
 # lond "LON Daemon" Server (port "LOND" 5663)
 #
-# $Id: lond,v 1.517 2016/01/31 21:25:53 raeburn Exp $
+# $Id: lond,v 1.518 2016/02/17 19:15:44 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -55,13 +55,16 @@
 use Fcntl qw(:flock);
 use Apache::lonnet;
 use Mail::Send;
+use Crypt::Eksblowfish::Bcrypt;
+use Digest::SHA;
+use Encode;
 
 my $DEBUG = 0;		       # Non zero to enable debug log entries.
 
 my $status='';
 my $lastlog='';
 
-my $VERSION='$Revision: 1.517 $'; #' stupid emacs
+my $VERSION='$Revision: 1.518 $'; #' stupid emacs
 my $remoteVERSION;
 my $currenthostid="default";
 my $currentdomainid;
@@ -2013,15 +2016,14 @@
 	my ($howpwd,$contentpwd)=split(/:/,$realpasswd);
 	if ($howpwd eq 'internal') {
 	    &Debug("internal auth");
-	    my $salt=time;
-	    $salt=substr($salt,6,2);
-	    my $ncpass=crypt($npass,$salt);
+            my $ncpass = &hash_passwd($udom,$npass);
 	    if(&rewrite_password_file($udom, $uname, "internal:$ncpass")) {
 		my $msg="Result of password change for $uname: pwchange_success";
                 if ($lonhost) {
                     $msg .= " - request originated from: $lonhost";
                 }
                 &logthis($msg);
+                &update_passwd_history($uname,$udom,$howpwd,$context);
 		&Reply($client, "ok\n", $userinput);
 	    } else {
 		&logthis("Unable to open $uname passwd "               
@@ -2030,6 +2032,9 @@
 	    }
 	} elsif ($howpwd eq 'unix' && $context ne 'reset_by_email') {
 	    my $result = &change_unix_password($uname, $npass);
+            if ($result eq 'ok') {
+                &update_passwd_history($uname,$udom,$howpwd,$context);
+             }
 	    &logthis("Result of password change for $uname: ".
 		     $result);
 	    &Reply($client, \$result, $userinput);
@@ -2052,6 +2057,42 @@
 }
 &register_handler("passwd", \&change_password_handler, 1, 1, 0);
 
+sub hash_passwd {
+    my ($domain,$plainpass, at rest) = @_;
+    my ($salt,$cost);
+    if (@rest) {
+        $cost = $rest[0];
+        # salt is first 22 characters, base-64 encoded by bcrypt
+        my $plainsalt = substr($rest[1],0,22);
+        $salt = Crypt::Eksblowfish::Bcrypt::de_base64($plainsalt);
+    } else {
+        my $defaultcost;
+        my %domconfig =
+            &Apache::lonnet::get_dom('configuration',['password'],$domain);
+        if (ref($domconfig{'password'}) eq 'HASH') {
+            $defaultcost = $domconfig{'password'}{'cost'};
+        }
+        if (($defaultcost eq '') || ($defaultcost =~ /D/)) {
+            $cost = 10;
+        } else {
+            $cost = $defaultcost;
+        }
+        # Generate random 16-octet base64 salt
+        $salt = "";
+        $salt .= pack("C", int rand(256)) for 1..16;
+    }
+    my $hash = &Crypt::Eksblowfish::Bcrypt::bcrypt_hash({
+        key_nul => 1,
+        cost    => $cost,
+        salt    => $salt,
+    }, Digest::SHA::sha512(Encode::encode('UTF-8',$plainpass)));
+
+    my $result = join("!", "", "bcrypt", sprintf("%02d",$cost),
+                &Crypt::Eksblowfish::Bcrypt::en_base64($salt).
+                &Crypt::Eksblowfish::Bcrypt::en_base64($hash));
+    return $result;
+}
+
 #
 #   Create a new user.  User in this case means a lon-capa user.
 #   The user must either already exist in some authentication realm
@@ -2095,7 +2136,8 @@
 		    ."makeuser";
 	    }
 	    unless ($fperror) {
-		my $result=&make_passwd_file($uname,$udom,$umode,$npass, $passfilename);
+		my $result=&make_passwd_file($uname,$udom,$umode,$npass,
+                                             $passfilename,'makeuser');
 		&Reply($client,\$result, $userinput);     #BUGBUG - could be fail
 	    } else {
 		&Failure($client, \$fperror, $userinput);
@@ -2164,12 +2206,14 @@
 		my $result = &change_unix_password($uname, $npass);
 		&logthis("Result of password change for $uname: ".$result);
 		if ($result eq "ok") {
+                    &update_passwd_history($uname,$udom,$umode,'changeuserauth'); 
 		    &Reply($client, \$result);
 		} else {
 		    &Failure($client, \$result);
 		}
 	    } else {
-		my $result=&make_passwd_file($uname,$udom,$umode,$npass,$passfilename);
+		my $result=&make_passwd_file($uname,$udom,$umode,$npass,
+                                             $passfilename,'changeuserauth');
 		#
 		#  If the current auth mode is internal, and the old auth mode was
 		#  unix, or krb*,  and the user is an author for this domain,
@@ -2190,6 +2234,17 @@
 }
 &register_handler("changeuserauth", \&change_authentication_handler, 1,1, 0);
 
+sub update_passwd_history {
+    my ($uname,$udom,$umode,$context) = @_;
+    my $proname=&propath($udom,$uname);
+    my $now = time;
+    if (open(my $fh,">>$proname/passwd.log")) {
+        print $fh "$now:$umode:$context\n";
+        close($fh);
+    }
+    return;
+}
+
 #
 #   Determines if this is the home server for a user.  The home server
 #   for a user will have his/her lon-capa passwd file.  Therefore all we need
@@ -7147,7 +7202,18 @@
     } 
     if ($howpwd ne 'nouser') {
 	if($howpwd eq "internal") { # Encrypted is in local password file.
-	    $validated = (crypt($password, $contentpwd) eq $contentpwd);
+            if (length($contentpwd) == 13) {
+                $validated = (crypt($password,$contentpwd) eq $contentpwd);
+                if ($validated) {
+                    my $ncpass = &hash_passwd($domain,$password);
+                    if (&rewrite_password_file($domain,$user,"$howpwd:$ncpass")) {
+                        &update_passwd_history($user,$domain,$howpwd,'conversion');
+                        &logthis("Validated password hashed with bcrypt for $user:$domain");
+                    }
+                }
+            } else {
+                $validated = &check_internal_passwd($password,$contentpwd,$domain);
+            }
 	}
 	elsif ($howpwd eq "unix") { # User is a normal unix user.
 	    $contentpwd = (getpwnam($user))[1];
@@ -7215,6 +7281,39 @@
     return $validated;
 }
 
+sub check_internal_passwd {
+    my ($plainpass,$stored,$domain) = @_;
+    my (undef,$method, at rest) = split(/!/,$stored);
+    if ($method eq "bcrypt") {
+        my $result = &hash_passwd($domain,$plainpass, at rest);
+        if ($result ne $stored) {
+            return 0;
+        }
+        # Upgrade to a larger number of rounds if necessary
+        my $defaultcost;
+        my %domconfig =
+            &Apache::lonnet::get_dom('configuration',['password'],$domain);
+        if (ref($domconfig{'password'}) eq 'HASH') {
+            $defaultcost = $domconfig{'password'}{'cost'};
+        }
+        if (($defaultcost eq '') || ($defaultcost =~ /D/)) {
+            $defaultcost = 10;
+        }
+        return 1 unless($rest[0]<$defaultcost);
+    }
+    return 0;
+}
+
+sub get_last_authchg {
+    my ($domain,$user) = @_;
+    my $lastmod;
+    my $logname = &propath($domain,$user).'/passwd.log';
+    if (-e "$logname") {
+        $lastmod = (stat("$logname"))[9];
+    }
+    return $lastmod;
+}
+
 sub krb4_authen {
     my ($password,$null,$user,$contentpwd) = @_;
     my $validated = 0;
@@ -7530,26 +7629,26 @@
 
 
 sub make_passwd_file {
-    my ($uname,$udom,$umode,$npass,$passfilename)=@_;
+    my ($uname,$udom,$umode,$npass,$passfilename,$action)=@_;
     my $result="ok";
     if ($umode eq 'krb4' or $umode eq 'krb5') {
 	{
 	    my $pf = IO::File->new(">$passfilename");
 	    if ($pf) {
 		print $pf "$umode:$npass\n";
+                &update_passwd_history($uname,$udom,$umode,$action);
 	    } else {
 		$result = "pass_file_failed_error";
 	    }
 	}
     } elsif ($umode eq 'internal') {
-	my $salt=time;
-	$salt=substr($salt,6,2);
-	my $ncpass=crypt($npass,$salt);
+        my $ncpass = &hash_passwd($udom,$npass);
 	{
 	    &Debug("Creating internal auth");
 	    my $pf = IO::File->new(">$passfilename");
 	    if($pf) {
-		print $pf "internal:$ncpass\n"; 
+		print $pf "internal:$ncpass\n";
+                &update_passwd_history($uname,$udom,$umode,$action); 
 	    } else {
 		$result = "pass_file_failed_error";
 	    }
Index: loncom/interface/lonpreferences.pm
diff -u loncom/interface/lonpreferences.pm:1.218 loncom/interface/lonpreferences.pm:1.219
--- loncom/interface/lonpreferences.pm:1.218	Sun Jan 31 21:25:37 2016
+++ loncom/interface/lonpreferences.pm	Wed Feb 17 19:15:48 2016
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Preferences
 #
-# $Id: lonpreferences.pm,v 1.218 2016/01/31 21:25:37 raeburn Exp $
+# $Id: lonpreferences.pm,v 1.219 2016/02/17 19:15:48 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -1409,21 +1409,18 @@
         uextkey=this.document.client.elements.ukey_cpass.value;
         lextkey=this.document.client.elements.lkey_cpass.value;
         initkeys();
-
-        this.document.pserver.elements.currentpass.value
-            =crypted(this.document.client.elements.currentpass.value);
-
+        this.document.pserver.elements.currentpass.value =
+            getCrypted(this.document.client.elements.currentpass.value);
         uextkey=this.document.client.elements.ukey_npass1.value;
         lextkey=this.document.client.elements.lkey_npass1.value;
         initkeys();
         this.document.pserver.elements.newpass_1.value
-            =crypted(this.document.client.elements.newpass_1.value);
-
+            =getCrypted(this.document.client.elements.newpass_1.value);
         uextkey=this.document.client.elements.ukey_npass2.value;
         lextkey=this.document.client.elements.lkey_npass2.value;
         initkeys();
         this.document.pserver.elements.newpass_2.value
-            =crypted(this.document.client.elements.newpass_2.value);
+            =getCrypted(this.document.client.elements.newpass_2.value);
 |;
     if ($caller eq 'reset_by_email') {
         $output .= qq|
@@ -1438,6 +1435,7 @@
     $ output .= qq|
         this.document.pserver.submit();
     }
+
 </script>
 |;
 }
@@ -1463,7 +1461,7 @@
                   .&Apache::lonhtmlcommon::row_closure()
                   .&Apache::lonhtmlcommon::row_title(
                        '<label for="uname">'.$lt{'username'}.'</label>')
-                  .'<input type="text" name="uname" size="15" />'
+                  .'<input type="text" name="uname" size="20" />'
                   .'<input type="hidden" name="currentpass" value="'.$currentpass.'" />'
                   .&Apache::lonhtmlcommon::row_closure()
                   .&Apache::lonhtmlcommon::row_title(
@@ -1473,16 +1471,16 @@
     } else {
         $output .= &Apache::lonhtmlcommon::row_title(
                        '<label for="currentpass">'.$lt{'currentpass'}.'</label>')
-                  .'<input type="password" name="currentpass" size="10"/>'
+                  .'<input type="password" name="currentpass" size="20"/>'
                   .&Apache::lonhtmlcommon::row_closure();
     }
     $output .= &Apache::lonhtmlcommon::row_title(
                    '<label for="newpass_1">'.$lt{'newpass'}.'</label>')
-              .'<input type="password" name="newpass_1" size="10" />'
+              .'<input type="password" name="newpass_1" size="20" />'
               .&Apache::lonhtmlcommon::row_closure()
               .&Apache::lonhtmlcommon::row_title(
                    '<label for="newpass_2">'.$lt{'confirmpass'}.'</label>')
-              .'<input type="password" name="newpass_2" size="10" />'
+              .'<input type="password" name="newpass_2" size="20" />'
               .&Apache::lonhtmlcommon::row_closure(1)
               .&Apache::lonhtmlcommon::end_pick_box();
     $output .= '<p><input type="button" value="'.$lt{'changepass'}.'" onclick="send();" /></p>'
@@ -1605,7 +1603,7 @@
         return 1;
     }
     my ($ckey,$n1key,$n2key)=split(/&/,$tmpinfo);
-    # 
+    #
     $currentpass = &Apache::loncommon::des_decrypt($ckey ,$currentpass);
     $newpass1    = &Apache::loncommon::des_decrypt($n1key,$newpass1);
     $newpass2    = &Apache::loncommon::des_decrypt($n2key,$newpass2);
@@ -2283,7 +2281,7 @@
     }elsif($env{'form.action'} eq 'changepass'){
         &passwordchanger($r);
     }elsif($env{'form.action'} eq 'verify_and_change_pass'){
-        &verify_and_change_password($r);
+        &verify_and_change_password($r,'preferences');
     }elsif($env{'form.action'} eq 'changescreenname'){
         &screennamechanger($r);
     }elsif($env{'form.action'} eq 'verify_and_change_screenname'){
Index: loncom/interface/createaccount.pm
diff -u loncom/interface/createaccount.pm:1.70 loncom/interface/createaccount.pm:1.71
--- loncom/interface/createaccount.pm:1.70	Tue Jun  9 21:22:55 2015
+++ loncom/interface/createaccount.pm	Wed Feb 17 19:15:48 2016
@@ -4,7 +4,7 @@
 # kerberos, or SSO) or an e-mail address. Requests to use an e-mail address as
 # username may be processed automatically, or may be queued for approval.
 #
-# $Id: createaccount.pm,v 1.70 2015/06/09 21:22:55 damieng Exp $
+# $Id: createaccount.pm,v 1.71 2016/02/17 19:15:48 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -431,7 +431,7 @@
                 initkeys();
 
                 server.elements.upass.value
-                    = crypted(client.elements.upass$now.value);
+                    = getCrypted(client.elements.upass$now.value);
 
                 client.elements.uname.value='';
                 client.elements.upass$now.value='';
@@ -444,6 +444,7 @@
         }
         return false;
     }
+
 // ]]>
 </script>
 ENDSCRIPT
Index: loncom/interface/loncreateuser.pm
diff -u loncom/interface/loncreateuser.pm:1.407 loncom/interface/loncreateuser.pm:1.408
--- loncom/interface/loncreateuser.pm:1.407	Sun Jan 31 21:25:38 2016
+++ loncom/interface/loncreateuser.pm	Wed Feb 17 19:15:48 2016
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Create a user
 #
-# $Id: loncreateuser.pm,v 1.407 2016/01/31 21:25:38 raeburn Exp $
+# $Id: loncreateuser.pm,v 1.408 2016/02/17 19:15:48 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -2244,8 +2244,8 @@
                    '<input type="text" name="uname" size="25" value="" autocomplete="off" />';
         $rowcount ++;
         $output .= &Apache::lonhtmlcommon::row_closure(1);
-        my $upassone = '<input type="password" name="upass'.$now.'" size="10" autocomplete="off" />';
-        my $upasstwo = '<input type="password" name="upasscheck'.$now.'" size="10" autocomplete="off" />';
+        my $upassone = '<input type="password" name="upass'.$now.'" size="20" autocomplete="off" />';
+        my $upasstwo = '<input type="password" name="upasscheck'.$now.'" size="20" autocomplete="off" />';
         $output .= &Apache::lonhtmlcommon::row_title(&mt('Password').'<b>*</b>',
                                                     'LC_pick_box_title',
                                                     'LC_oddrow_value')."\n".
Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.1232 loncom/interface/loncommon.pm:1.1233
--- loncom/interface/loncommon.pm:1.1232	Wed Jan 27 00:24:09 2016
+++ loncom/interface/loncommon.pm	Wed Feb 17 19:15:48 2016
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.1232 2016/01/27 00:24:09 raeburn Exp $
+# $Id: loncommon.pm,v 1.1233 2016/02/17 19:15:48 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -16766,11 +16766,19 @@
     } else {
         $cypher=new DES $keybin;
     }
-    my $plaintext=
-        $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,0,16))));
-    $plaintext.=
-        $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,16,16))));
-    $plaintext=substr($plaintext,1,ord(substr($plaintext,0,1)) );
+    my $plaintext='';
+    my $cypherlength = length($cyphertext);
+    my $numchunks = int($cypherlength/32);
+    for (my $j=0; $j<$numchunks; $j++) {
+        my $start = $j*32;
+        my $cypherblock = substr($cyphertext,$start,32);
+        my $chunk =
+            $cypher->decrypt(unpack("a8",pack("H16",substr($cypherblock,0,16))));
+        $chunk .=
+            $cypher->decrypt(unpack("a8",pack("H16",substr($cypherblock,16,16))));
+        $chunk=substr($chunk,1,ord(substr($chunk,0,1)) );
+        $plaintext .= $chunk;
+    }
     return $plaintext;
 }
 


More information about the LON-CAPA-cvs mailing list