@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.

Standardize SSH key storage

Summary:
Ref T5833. This fixes a few weird things with this table:

- A bunch of columns were nullable for no reason.
- We stored an MD5 hash of the key (unusual) but never used it and callers were responsible for manually populating it.
- We didn't perform known-key-text lookups by using an index.

Test Plan:
- Ran migrations.
- Faked duplicate keys, saw them clean up correctly.
- Added new keys.
- Generated new keys.
- Used `bin/auth-ssh` and `bin/auth-ssh-key`.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T5833

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

+136 -33
+2
resources/sql/autopatches/20141107.ssh.1.colname.sql
··· 1 + ALTER TABLE {$NAMESPACE}_auth.auth_sshkey 2 + CHANGE userPHID objectPHID VARBINARY(64) NOT NULL;
+2
resources/sql/autopatches/20141107.ssh.2.keyhash.sql
··· 1 + ALTER TABLE {$NAMESPACE}_auth.auth_sshkey 2 + DROP COLUMN keyHash;
+2
resources/sql/autopatches/20141107.ssh.3.keyindex.sql
··· 1 + ALTER TABLE {$NAMESPACE}_auth.auth_sshkey 2 + ADD COLUMN keyIndex BINARY(12);
+50
resources/sql/autopatches/20141107.ssh.4.keymig.php
··· 1 + <?php 2 + 3 + $table = new PhabricatorAuthSSHKey(); 4 + $conn_w = $table->establishConnection('w'); 5 + 6 + echo "Updating SSH public key indexes...\n"; 7 + 8 + $keys = new LiskMigrationIterator($table); 9 + foreach ($keys as $key) { 10 + $id = $key->getID(); 11 + 12 + echo "Updating key {$id}...\n"; 13 + 14 + try { 15 + $hash = $key->toPublicKey()->getHash(); 16 + } catch (Exception $ex) { 17 + echo "Key has bad format! Removing key.\n"; 18 + queryfx( 19 + $conn_w, 20 + 'DELETE FROM %T WHERE id = %d', 21 + $table->getTableName(), 22 + $id); 23 + continue; 24 + } 25 + 26 + $collision = queryfx_all( 27 + $conn_w, 28 + 'SELECT * FROM %T WHERE keyIndex = %s AND id < %d', 29 + $table->getTableName(), 30 + $hash, 31 + $key->getID()); 32 + if ($collision) { 33 + echo "Key is a duplicate! Removing key.\n"; 34 + queryfx( 35 + $conn_w, 36 + 'DELETE FROM %T WHERE id = %d', 37 + $table->getTableName(), 38 + $id); 39 + continue; 40 + } 41 + 42 + queryfx( 43 + $conn_w, 44 + 'UPDATE %T SET keyIndex = %s WHERE id = %d', 45 + $table->getTableName(), 46 + $hash, 47 + $key->getID()); 48 + } 49 + 50 + echo "Done.\n";
+2
resources/sql/autopatches/20141107.ssh.5.indexnull.sql
··· 1 + ALTER TABLE {$NAMESPACE}_auth.auth_sshkey 2 + CHANGE keyIndex keyIndex BINARY(12) NOT NULL;
+2
resources/sql/autopatches/20141107.ssh.6.indexkey.sql
··· 1 + ALTER TABLE {$NAMESPACE}_auth.auth_sshkey 2 + ADD UNIQUE KEY `key_unique` (keyIndex);
+23
resources/sql/autopatches/20141107.ssh.7.colnull.sql
··· 1 + UPDATE {$NAMESPACE}_auth.auth_sshkey 2 + SET name = '' WHERE name IS NULL; 3 + 4 + ALTER TABLE {$NAMESPACE}_auth.auth_sshkey 5 + CHANGE name name VARCHAR(255) COLLATE {$COLLATE_TEXT} NOT NULL; 6 + 7 + UPDATE {$NAMESPACE}_auth.auth_sshkey 8 + SET keyType = '' WHERE keyType IS NULL; 9 + 10 + ALTER TABLE {$NAMESPACE}_auth.auth_sshkey 11 + CHANGE keyType keyType VARCHAR(255) COLLATE {$COLLATE_TEXT} NOT NULL; 12 + 13 + UPDATE {$NAMESPACE}_auth.auth_sshkey 14 + SET keyBody = '' WHERE keyBody IS NULL; 15 + 16 + ALTER TABLE {$NAMESPACE}_auth.auth_sshkey 17 + CHANGE keyBody keyBody LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL; 18 + 19 + UPDATE {$NAMESPACE}_auth.auth_sshkey 20 + SET keyComment = '' WHERE keyComment IS NULL; 21 + 22 + ALTER TABLE {$NAMESPACE}_auth.auth_sshkey 23 + CHANGE keyComment keyComment VARCHAR(255) COLLATE {$COLLATE_TEXT} NOT NULL;
+6
scripts/ssh/ssh-auth.php
··· 34 34 35 35 $type = $ssh_key->getKeyType(); 36 36 $type = preg_replace('@[\x00-\x20]+@', '', $type); 37 + if (!strlen($type)) { 38 + continue; 39 + } 37 40 38 41 $key = $ssh_key->getKeyBody(); 39 42 $key = preg_replace('@[\x00-\x20]+@', '', $key); 43 + if (!strlen($key)) { 44 + continue; 45 + } 40 46 41 47 $options = array( 42 48 'command="'.$cmd.'"',
+3 -6
src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php
··· 73 73 if ($this->objectPHIDs !== null) { 74 74 $where[] = qsprintf( 75 75 $conn_r, 76 - 'userPHID IN (%Ls)', 76 + 'objectPHID IN (%Ls)', 77 77 $this->objectPHIDs); 78 78 } 79 79 80 80 if ($this->keys !== null) { 81 - // TODO: This could take advantage of a better key, and the hashing 82 - // scheme for this table is a bit nonstandard and questionable. 83 - 84 81 $sql = array(); 85 82 foreach ($this->keys as $key) { 86 83 $sql[] = qsprintf( 87 84 $conn_r, 88 - '(keyType = %s AND keyBody = %s)', 85 + '(keyType = %s AND keyIndex = %s)', 89 86 $key->getType(), 90 - $key->getBody()); 87 + $key->getHash()); 91 88 } 92 89 $where[] = implode(' OR ', $sql); 93 90 }
+23 -19
src/applications/auth/storage/PhabricatorAuthSSHKey.php
··· 4 4 extends PhabricatorAuthDAO 5 5 implements PhabricatorPolicyInterface { 6 6 7 - protected $userPHID; 7 + protected $objectPHID; 8 8 protected $name; 9 9 protected $keyType; 10 + protected $keyIndex; 10 11 protected $keyBody; 11 - protected $keyHash; 12 - protected $keyComment; 12 + protected $keyComment = ''; 13 13 14 14 private $object = self::ATTACHABLE; 15 15 16 - public function getObjectPHID() { 17 - return $this->getUserPHID(); 18 - } 19 - 20 16 public function getConfiguration() { 21 17 return array( 22 18 self::CONFIG_COLUMN_SCHEMA => array( 23 - 'keyHash' => 'bytes32', 24 - 'keyComment' => 'text255?', 25 - 26 - // T6203/NULLABILITY 27 - // These seem like they should not be nullable. 28 - 'name' => 'text255?', 29 - 'keyType' => 'text255?', 30 - 'keyBody' => 'text?', 19 + 'name' => 'text255', 20 + 'keyType' => 'text255', 21 + 'keyIndex' => 'bytes12', 22 + 'keyBody' => 'text', 23 + 'keyComment' => 'text255', 31 24 ), 32 25 self::CONFIG_KEY_SCHEMA => array( 33 - 'userPHID' => array( 34 - 'columns' => array('userPHID'), 26 + 'key_object' => array( 27 + 'columns' => array('objectPHID'), 35 28 ), 36 - 'keyHash' => array( 37 - 'columns' => array('keyHash'), 29 + 'key_unique' => array( 30 + 'columns' => array('keyIndex'), 38 31 'unique' => true, 39 32 ), 40 33 ), 41 34 ) + parent::getConfiguration(); 42 35 } 43 36 37 + public function save() { 38 + $this->setKeyIndex($this->toPublicKey()->getHash()); 39 + return parent::save(); 40 + } 41 + 42 + public function toPublicKey() { 43 + return PhabricatorAuthSSHPublicKey::newFromStoredKey($this); 44 + } 45 + 44 46 public function getEntireKey() { 45 47 $parts = array( 46 48 $this->getKeyType(), ··· 58 60 $this->object = $object; 59 61 return $this; 60 62 } 63 + 64 + 61 65 62 66 63 67 /* -( PhabricatorPolicyInterface )----------------------------------------- */
+16
src/applications/auth/storage/PhabricatorAuthSSHPublicKey.php
··· 13 13 // <internal> 14 14 } 15 15 16 + public static function newFromStoredKey(PhabricatorAuthSSHKey $key) { 17 + $public_key = new PhabricatorAuthSSHPublicKey(); 18 + $public_key->type = $key->getKeyType(); 19 + $public_key->body = $key->getKeyBody(); 20 + $public_key->comment = $key->getKeyComment(); 21 + 22 + return $public_key; 23 + } 24 + 16 25 public static function newFromRawKey($entire_key) { 17 26 $entire_key = trim($entire_key); 18 27 if (!strlen($entire_key)) { ··· 81 90 82 91 public function getComment() { 83 92 return $this->comment; 93 + } 94 + 95 + public function getHash() { 96 + $body = $this->getBody(); 97 + $body = trim($body); 98 + $body = rtrim($body, '='); 99 + return PhabricatorHash::digestForIndex($body); 84 100 } 85 101 86 102 }
+1 -1
src/applications/people/storage/PhabricatorUser.php
··· 897 897 } 898 898 899 899 $keys = id(new PhabricatorAuthSSHKey())->loadAllWhere( 900 - 'userPHID = %s', 900 + 'objectPHID = %s', 901 901 $this->getPHID()); 902 902 foreach ($keys as $key) { 903 903 $key->delete();
+4 -7
src/applications/settings/panel/PhabricatorSettingsPanelSSHKeys.php
··· 44 44 $this->getPanelURI()); 45 45 46 46 $id = nonempty($edit, $delete); 47 - 48 - if ($id) { 47 + if ($id && (int)$id) { 49 48 $key = id(new PhabricatorAuthSSHKeyQuery()) 50 49 ->setViewer($viewer) 51 50 ->withIDs(array($id)) ··· 59 58 return new Aphront404Response(); 60 59 } 61 60 } else { 62 - $key = new PhabricatorAuthSSHKey(); 63 - $key->setUserPHID($user->getPHID()); 61 + $key = id(new PhabricatorAuthSSHKey()) 62 + ->setObjectPHID($user->getPHID()); 64 63 } 65 64 66 65 if ($delete) { ··· 89 88 90 89 $key->setKeyType($type); 91 90 $key->setKeyBody($body); 92 - $key->setKeyHash(md5($body)); 93 91 $key->setKeyComment($comment); 94 92 95 93 $e_key = null; ··· 309 307 $body = $public_key->getBody(); 310 308 311 309 $key = id(new PhabricatorAuthSSHKey()) 312 - ->setUserPHID($user->getPHID()) 310 + ->setObjectPHID($user->getPHID()) 313 311 ->setName('id_rsa_phabricator') 314 312 ->setKeyType($type) 315 313 ->setKeyBody($body) 316 - ->setKeyHash(md5($body)) 317 314 ->setKeyComment(pht('Generated')) 318 315 ->save(); 319 316