@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Modernize VCS password storage to use shared hash infrastructure

Summary: Fixes T4443. Plug VCS passwords into the shared key stretching. They don't use any real stretching now (I anticipated doing something like T4443 eventually) so we can just migrate them into stretching all at once.

Test Plan:
- Viewed VCS settings.
- Used VCS password after migration.
- Set VCS password.
- Upgraded VCS password by using it.
- Used VCS password some more.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T4443

Differential Revision: https://secure.phabricator.com/D8272

+118 -28
+2
resources/sql/autopatches/20140218.passwords.3.vcsextend.sql
··· 1 + ALTER TABLE {$NAMESPACE}_repository.repository_vcspassword 2 + CHANGE passwordHash passwordHash VARCHAR(128) COLLATE utf8_bin NOT NULL;
+27
resources/sql/autopatches/20140218.passwords.4.vcs.php
··· 1 + <?php 2 + 3 + $table = new PhabricatorRepositoryVCSPassword(); 4 + $conn_w = $table->establishConnection('w'); 5 + 6 + echo "Upgrading password hashing for VCS passwords.\n"; 7 + 8 + $best_hasher = PhabricatorPasswordHasher::getBestHasher(); 9 + foreach (new LiskMigrationIterator($table) as $password) { 10 + $id = $password->getID(); 11 + 12 + echo "Migrating VCS password {$id}...\n"; 13 + 14 + $input_hash = $password->getPasswordHash(); 15 + $input_envelope = new PhutilOpaqueEnvelope($input_hash); 16 + 17 + $storage_hash = $best_hasher->getPasswordHashForStorage($input_envelope); 18 + 19 + queryfx( 20 + $conn_w, 21 + 'UPDATE %T SET passwordHash = %s WHERE id = %d', 22 + $table->getTableName(), 23 + $storage_hash->openEnvelope(), 24 + $id); 25 + } 26 + 27 + echo "Done.\n";
+12
src/applications/diffusion/controller/DiffusionServeController.php
··· 426 426 return null; 427 427 } 428 428 429 + // If the user's password is stored using a less-than-optimal hash, upgrade 430 + // them to the strongest available hash. 431 + 432 + $hash_envelope = new PhutilOpaqueEnvelope( 433 + $password_entry->getPasswordHash()); 434 + if (PhabricatorPasswordHasher::canUpgradeHash($hash_envelope)) { 435 + $password_entry->setPassword($password, $user); 436 + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); 437 + $password_entry->save(); 438 + unset($unguarded); 439 + } 440 + 429 441 return $user; 430 442 } 431 443
+20
src/applications/diffusion/panel/DiffusionSetPasswordPanel.php
··· 165 165 } 166 166 } 167 167 168 + $hash_envelope = new PhutilOpaqueEnvelope($vcspassword->getPasswordHash()); 169 + 170 + $form->appendChild( 171 + id(new AphrontFormStaticControl()) 172 + ->setLabel(pht('Current Algorithm')) 173 + ->setValue( 174 + PhabricatorPasswordHasher::getCurrentAlgorithmName($hash_envelope))); 175 + 176 + $form->appendChild( 177 + id(new AphrontFormStaticControl()) 178 + ->setLabel(pht('Best Available Algorithm')) 179 + ->setValue(PhabricatorPasswordHasher::getBestAlgorithmName())); 180 + 181 + if (PhabricatorPasswordHasher::canUpgradeHash($hash_envelope)) { 182 + $errors[] = pht( 183 + 'The strength of your stored VCS password hash can be upgraded. '. 184 + 'To upgrade, either: use the password to authenticate with a '. 185 + 'repository; or change your password.'); 186 + } 187 + 168 188 $object_box = id(new PHUIObjectBoxView()) 169 189 ->setHeaderText($title) 170 190 ->setForm($form)
+18 -6
src/applications/repository/storage/PhabricatorRepositoryVCSPassword.php
··· 9 9 public function setPassword( 10 10 PhutilOpaqueEnvelope $password, 11 11 PhabricatorUser $user) { 12 - return $this->setPasswordHash($this->hashPassword($password, $user)); 12 + $hash_envelope = $this->hashPassword($password, $user); 13 + return $this->setPasswordHash($hash_envelope->openEnvelope()); 13 14 } 14 15 15 16 public function comparePassword( 16 17 PhutilOpaqueEnvelope $password, 17 18 PhabricatorUser $user) { 18 19 19 - $hash = $this->hashPassword($password, $user); 20 - return ($hash == $this->getPasswordHash()); 20 + return PhabricatorPasswordHasher::comparePassword( 21 + $this->getPasswordHashInput($password, $user), 22 + new PhutilOpaqueEnvelope($this->getPasswordHash())); 21 23 } 22 24 23 - private function hashPassword( 25 + private function getPasswordHashInput( 24 26 PhutilOpaqueEnvelope $password, 25 27 PhabricatorUser $user) { 26 - 27 28 if ($user->getPHID() != $this->getUserPHID()) { 28 29 throw new Exception("User does not match password user PHID!"); 29 30 } 30 31 31 - return PhabricatorHash::digestPassword($password, $user->getPHID()); 32 + $raw_input = PhabricatorHash::digestPassword($password, $user->getPHID()); 33 + return new PhutilOpaqueEnvelope($raw_input); 34 + } 35 + 36 + private function hashPassword( 37 + PhutilOpaqueEnvelope $password, 38 + PhabricatorUser $user) { 39 + 40 + $input_envelope = $this->getPasswordHashInput($password, $user); 41 + 42 + $best_hasher = PhabricatorPasswordHasher::getBestHasher(); 43 + return $best_hasher->getPasswordHashForStorage($input_envelope); 32 44 } 33 45 34 46 }
+3 -22
src/applications/settings/panel/PhabricatorSettingsPanelPassword.php
··· 114 114 115 115 $hash_envelope = new PhutilOpaqueEnvelope($user->getPasswordHash()); 116 116 if (PhabricatorPasswordHasher::canUpgradeHash($hash_envelope)) { 117 - $best_hash = PhabricatorPasswordHasher::getBestHasher(); 118 117 $errors[] = pht( 119 118 'The strength of your stored password hash can be upgraded. '. 120 119 'To upgrade, either: log out and log in using your password; or '. ··· 157 156 id(new AphrontFormSubmitControl()) 158 157 ->setValue(pht('Change Password'))); 159 158 160 - if (!strlen($user->getPasswordHash())) { 161 - $current_name = pht('None'); 162 - } else { 163 - try { 164 - $current_hasher = PhabricatorPasswordHasher::getHasherForHash( 165 - new PhutilOpaqueEnvelope($user->getPasswordHash())); 166 - $current_name = $current_hasher->getHumanReadableName(); 167 - } catch (Exception $ex) { 168 - $current_name = pht('Unknown'); 169 - } 170 - } 171 - 172 159 $form->appendChild( 173 160 id(new AphrontFormStaticControl()) 174 161 ->setLabel(pht('Current Algorithm')) 175 - ->setValue($current_name)); 176 - 177 - try { 178 - $best_hasher = PhabricatorPasswordHasher::getBestHasher(); 179 - $best_name = $best_hasher->getHumanReadableName(); 180 - } catch (Exception $ex) { 181 - $best_name = pht('Unknown'); 182 - } 162 + ->setValue(PhabricatorPasswordHasher::getCurrentAlgorithmName( 163 + new PhutilOpaqueEnvelope($user->getPasswordHash())))); 183 164 184 165 $form->appendChild( 185 166 id(new AphrontFormStaticControl()) 186 167 ->setLabel(pht('Best Available Algorithm')) 187 - ->setValue($best_name)); 168 + ->setValue(PhabricatorPasswordHasher::getBestAlgorithmName())); 188 169 189 170 $form_box = id(new PHUIObjectBoxView()) 190 171 ->setHeaderText(pht('Change Password'))
+36
src/infrastructure/util/password/PhabricatorPasswordHasher.php
··· 385 385 return $hasher->verifyPassword($password, $parts['hash']); 386 386 } 387 387 388 + 389 + /** 390 + * Get the human-readable algorithm name for a given hash. 391 + * 392 + * @param PhutilOpaqueEnvelope Storage hash. 393 + * @return string Human-readable algorithm name. 394 + */ 395 + public static function getCurrentAlgorithmName(PhutilOpaqueEnvelope $hash) { 396 + $raw_hash = $hash->openEnvelope(); 397 + if (!strlen($raw_hash)) { 398 + return pht('None'); 399 + } 400 + 401 + try { 402 + $current_hasher = PhabricatorPasswordHasher::getHasherForHash($hash); 403 + return $current_hasher->getHumanReadableName(); 404 + } catch (Exception $ex) { 405 + return pht('Unknown'); 406 + } 407 + } 408 + 409 + 410 + /** 411 + * Get the human-readable algorithm name for the best available hash. 412 + * 413 + * @return string Human-readable name for best hash. 414 + */ 415 + public static function getBestAlgorithmName() { 416 + try { 417 + $best_hasher = PhabricatorPasswordHasher::getBestHasher(); 418 + return $best_hasher->getHumanReadableName(); 419 + } catch (Exception $ex) { 420 + return pht('Unknown'); 421 + } 422 + } 423 + 388 424 }