]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 785283 - Support increased values for PASSWORD_SALT_LENGTH without breaking compa...
authorReed Loden <reed@reedloden.com>
Mon, 31 Dec 2012 21:51:11 +0000 (13:51 -0800)
committerReed Loden <reed@reedloden.com>
Mon, 31 Dec 2012 21:51:11 +0000 (13:51 -0800)
[r=LpSolit a=LpSolit]

Bugzilla/Auth/Verify/DB.pm
Bugzilla/Constants.pm
Bugzilla/Install/DB.pm
Bugzilla/Util.pm

index 2ad98874daa8791e6d1a198f9a294cb103dd36e7..82fa662dc8fc3123cf595d635087c0616e7b51f8 100644 (file)
@@ -66,11 +66,22 @@ sub check_credentials {
     Bugzilla::Token::DeletePasswordTokens($user->id, "user_logged_in");
     $user->clear_login_failures();
 
+    my $update_password = 0;
+
     # If their old password was using crypt() or some different hash
     # than we're using now, convert the stored password to using
     # whatever hashing system we're using now.
     my $current_algorithm = PASSWORD_DIGEST_ALGORITHM;
-    if ($real_password_crypted !~ /{\Q$current_algorithm\E}$/) {
+    $update_password = 1 if ($real_password_crypted !~ /{\Q$current_algorithm\E}$/);
+
+    # If their old password was using a different length salt than what
+    # we're using now, update the password to use the new salt length.
+    if ($real_password_crypted =~ /^([^,]+),/) {
+        $update_password = 1 if (length($1) != PASSWORD_SALT_LENGTH);
+    }
+
+    # If needed, update the user's password.
+    if ($update_password) {
         $user->set_password($password);
         $user->update();
     }
index 5af1718787f992b713de51c452f30d0fcd0df8e8..8410ae46a732ea8c0a6cb258f4cde21a0f9ff7ac 100644 (file)
@@ -567,10 +567,10 @@ use constant MAX_QUIP_LENGTH => 512;
 # This is the name of the algorithm used to hash passwords before storing
 # them in the database. This can be any string that is valid to pass to
 # Perl's "Digest" module. Note that if you change this, it won't take
-# effect until a user changes his password.
+# effect until a user logs in or changes his password.
 use constant PASSWORD_DIGEST_ALGORITHM => 'SHA-256';
-# How long of a salt should we use? Note that if you change this, none
-# of your users will be able to log in until they reset their passwords.
+# How long of a salt should we use? Note that if you change this, it
+# won't take effect until a user logs in or changes his password.
 use constant PASSWORD_SALT_LENGTH => 8;
 
 # Certain scripts redirect to GET even if the form was submitted originally
index abf57ac27c11b77507c5792cf13de2dee32f9bb8..e1a3f3630591f5ea02f2e49756b8bfb8afe71350 100644 (file)
@@ -24,6 +24,7 @@ use Bugzilla::Field;
 
 use Date::Parse;
 use Date::Format;
+use Digest;
 use IO::File;
 use List::MoreUtils qw(uniq);
 use URI;
@@ -701,6 +702,9 @@ sub update_table_definitions {
     # 2012-08-01 koosha.khajeh@gmail.com - Bug 187753
     _shorten_long_quips();
 
+    # 2012-12-29 reed@reedloden.com - Bug 785283
+    _add_password_salt_separator();
+
     ################################################################
     # New --TABLE-- changes should go *** A B O V E *** this point #
     ################################################################
@@ -3776,6 +3780,39 @@ sub _shorten_long_quips {
     $dbh->bz_alter_column('quips', 'quip', { TYPE => 'varchar(512)', NOTNULL => 1});
 }
 
+sub _add_password_salt_separator {
+    my $dbh = Bugzilla->dbh;
+
+    $dbh->bz_start_transaction();
+
+    my $profiles = $dbh->selectall_arrayref("SELECT userid, cryptpassword FROM profiles WHERE ("
+        . $dbh->sql_regexp("cryptpassword", "'^[^,]+{'") . ")");
+
+    if (@$profiles) {
+        say "Adding salt separator to password hashes...";
+
+        my $query = $dbh->prepare("UPDATE profiles SET cryptpassword = ? WHERE userid = ?");
+        my %algo_sizes;
+
+        foreach my $profile (@$profiles) {
+            my ($userid, $hash) = @$profile;
+            my ($algorithm) = $hash =~ /{([^}]+)}$/;
+
+            $algo_sizes{$algorithm} ||= length(Digest->new($algorithm)->b64digest);
+
+            # Calculate the salt length by taking the stored hash and
+            # subtracting the combined lengths of the hash size, the
+            # algorithm name, and 2 for the {} surrounding the name.
+            my $not_salt_len = $algo_sizes{$algorithm} + length($algorithm) + 2;
+            my $salt_len = length($hash) - $not_salt_len;
+
+            substr($hash, $salt_len, 0, ',');
+            $query->execute($hash, $userid);
+        }
+    }
+    $dbh->bz_commit_transaction();
+}
+
 1;
 
 __END__
index bf072e88d51b818c166d371c6c614a09a6fd8396..cee12ee21114149e158ef9bde3683819207f60d7 100644 (file)
@@ -591,11 +591,10 @@ sub bz_crypt {
     }
     else {
         my $hasher = Digest->new($algorithm);
-        # We only want to use the first characters of the salt, no
-        # matter how long of a salt we may have been passed.
-        $salt = substr($salt, 0, PASSWORD_SALT_LENGTH);
+        # Newly created salts won't yet have a comma.
+        ($salt) = $salt =~ /^([^,]+),?/;
         $hasher->add($password, $salt);
-        $crypted_password = $salt . $hasher->b64digest . "{$algorithm}";
+        $crypted_password = $salt . ',' . $hasher->b64digest . "{$algorithm}";
     }
 
     # Return the crypted password.