diff --git a/lib/WeBWorK/Authen.pm b/lib/WeBWorK/Authen.pm index 2dcb29e076..6a56877175 100644 --- a/lib/WeBWorK/Authen.pm +++ b/lib/WeBWorK/Authen.pm @@ -55,7 +55,7 @@ use Scalar::Util qw(weaken); use Mojo::Util qw(b64_encode b64_decode); use WeBWorK::Debug; -use WeBWorK::Utils qw(x runtime_use); +use WeBWorK::Utils qw(x runtime_use utf8Crypt); use WeBWorK::Utils::Logs qw(writeCourseLog); use WeBWorK::Utils::TOTP; use WeBWorK::Localize; @@ -633,15 +633,8 @@ sub checkPassword { my $Password = $db->getPassword($userID); if (defined $Password) { # Check against the password in the database. - my $possibleCryptPassword = ''; - # Wrap crypt in an eval to catch any "Wide character in crypt" errors. - # If crypt fails due to a wide character, encode to UTF-8 before calling crypt. - eval { $possibleCryptPassword = crypt $possibleClearPassword, $Password->password; }; - if ($@ && $@ =~ /Wide char/) { - $possibleCryptPassword = crypt Encode::encode_utf8($possibleClearPassword), $Password->password; - } - - my $dbPassword = $Password->password; + my $possibleCryptPassword = utf8Crypt($possibleClearPassword, $Password->password); + my $dbPassword = $Password->password; # This next line explicitly insures that blank or null passwords from the database can never succeed in matching # an entered password. This also rejects cases when the database has a crypted password which matches a # submitted all white-space or null password by requiring that the $possibleClearPassword contain some non-space diff --git a/lib/WeBWorK/ContentGenerator/Options.pm b/lib/WeBWorK/ContentGenerator/Options.pm index 91b52dc8b7..22cefad897 100644 --- a/lib/WeBWorK/ContentGenerator/Options.pm +++ b/lib/WeBWorK/ContentGenerator/Options.pm @@ -22,7 +22,7 @@ WeBWorK::ContentGenerator::Options - Change user options. =cut -use WeBWorK::Utils qw(cryptPassword); +use WeBWorK::Utils qw(cryptPassword utf8Crypt); use WeBWorK::Localize; sub page_title ($c) { @@ -56,16 +56,7 @@ sub initialize ($c) { $userID ne $effectiveUserID ? eval { $db->getPassword($c->{effectiveUser}->user_id) } : $password; # Check that either password is not defined or if it is defined then we have the right one. - my $cryptedCurrP; - if (defined $password) { - # Wrap crypt in an eval to catch any "Wide character in crypt" errors. - # If crypt fails due to a wide character, encode to UTF-8 before calling crypt. - eval { $cryptedCurrP = crypt($currP // '', $password->password); }; - if ($@ && $@ =~ /Wide char/) { - $cryptedCurrP = crypt(Encode::encode_utf8($currP), $password->password); - } - } - if (!defined $password || $cryptedCurrP eq $password->password) { + if (!defined $password || utf8Crypt($currP // '', $password->password) eq $password->password) { my $e_user_name = $c->{effectiveUser}->first_name . ' ' . $c->{effectiveUser}->last_name; if ($newP eq $confirmP) { if (!defined $effectiveUserPassword) { diff --git a/lib/WeBWorK/Utils.pm b/lib/WeBWorK/Utils.pm index d65974bbbd..471c3139dd 100644 --- a/lib/WeBWorK/Utils.pm +++ b/lib/WeBWorK/Utils.pm @@ -35,6 +35,7 @@ our @EXPORT_OK = qw( max wwRound cryptPassword + utf8Crypt undefstr sortByName sortAchievements @@ -151,14 +152,15 @@ sub cryptPassword ($clearPassword) { $salt .= ('.', '/', '0' .. '9', 'A' .. 'Z', 'a' .. 'z')[ rand 64 ]; } + return utf8Crypt(trim_spaces($clearPassword), $salt); +} + +sub utf8Crypt ($clearPassword, $hash) { # Wrap crypt in an eval to catch any "Wide character in crypt" errors. # If crypt fails due to a wide character, encode to UTF-8 before calling crypt. my $cryptedPassword = ''; - eval { $cryptedPassword = crypt(trim_spaces($clearPassword), $salt); }; - if ($@ && $@ =~ /Wide char/) { - $cryptedPassword = crypt(Encode::encode_utf8(trim_spaces($clearPassword)), $salt); - } - + eval { $cryptedPassword = crypt($clearPassword, $hash); }; + $cryptedPassword = crypt(encode('UTF-8', $clearPassword), $hash) if $@ && $@ =~ /Wide char/; return $cryptedPassword; } @@ -621,6 +623,16 @@ Usage: C Returns the crypted form of C<$clearPassword> using a random 16 character salt. +=head2 utf8Crypt + +Usage: C + +Attempts to call C on C<$clearPassword>. If that fails, then C is +called on the UTF-8 encoded version of C<$clearPassword>. + +Note that C<$hash> can be a salt or a password hash generated by a previous call +of this method with a salt.. + =head2 undefstr Usage: C