1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 16:22:43 +01:00

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
This commit is contained in:
epriestley 2014-11-07 15:34:44 -08:00
parent a17a368692
commit bf17b12daf
13 changed files with 136 additions and 33 deletions

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_auth.auth_sshkey
CHANGE userPHID objectPHID VARBINARY(64) NOT NULL;

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_auth.auth_sshkey
DROP COLUMN keyHash;

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_auth.auth_sshkey
ADD COLUMN keyIndex BINARY(12);

View file

@ -0,0 +1,50 @@
<?php
$table = new PhabricatorAuthSSHKey();
$conn_w = $table->establishConnection('w');
echo "Updating SSH public key indexes...\n";
$keys = new LiskMigrationIterator($table);
foreach ($keys as $key) {
$id = $key->getID();
echo "Updating key {$id}...\n";
try {
$hash = $key->toPublicKey()->getHash();
} catch (Exception $ex) {
echo "Key has bad format! Removing key.\n";
queryfx(
$conn_w,
'DELETE FROM %T WHERE id = %d',
$table->getTableName(),
$id);
continue;
}
$collision = queryfx_all(
$conn_w,
'SELECT * FROM %T WHERE keyIndex = %s AND id < %d',
$table->getTableName(),
$hash,
$key->getID());
if ($collision) {
echo "Key is a duplicate! Removing key.\n";
queryfx(
$conn_w,
'DELETE FROM %T WHERE id = %d',
$table->getTableName(),
$id);
continue;
}
queryfx(
$conn_w,
'UPDATE %T SET keyIndex = %s WHERE id = %d',
$table->getTableName(),
$hash,
$key->getID());
}
echo "Done.\n";

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_auth.auth_sshkey
CHANGE keyIndex keyIndex BINARY(12) NOT NULL;

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_auth.auth_sshkey
ADD UNIQUE KEY `key_unique` (keyIndex);

View file

@ -0,0 +1,23 @@
UPDATE {$NAMESPACE}_auth.auth_sshkey
SET name = '' WHERE name IS NULL;
ALTER TABLE {$NAMESPACE}_auth.auth_sshkey
CHANGE name name VARCHAR(255) COLLATE {$COLLATE_TEXT} NOT NULL;
UPDATE {$NAMESPACE}_auth.auth_sshkey
SET keyType = '' WHERE keyType IS NULL;
ALTER TABLE {$NAMESPACE}_auth.auth_sshkey
CHANGE keyType keyType VARCHAR(255) COLLATE {$COLLATE_TEXT} NOT NULL;
UPDATE {$NAMESPACE}_auth.auth_sshkey
SET keyBody = '' WHERE keyBody IS NULL;
ALTER TABLE {$NAMESPACE}_auth.auth_sshkey
CHANGE keyBody keyBody LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL;
UPDATE {$NAMESPACE}_auth.auth_sshkey
SET keyComment = '' WHERE keyComment IS NULL;
ALTER TABLE {$NAMESPACE}_auth.auth_sshkey
CHANGE keyComment keyComment VARCHAR(255) COLLATE {$COLLATE_TEXT} NOT NULL;

View file

@ -34,9 +34,15 @@ foreach ($keys as $ssh_key) {
$type = $ssh_key->getKeyType();
$type = preg_replace('@[\x00-\x20]+@', '', $type);
if (!strlen($type)) {
continue;
}
$key = $ssh_key->getKeyBody();
$key = preg_replace('@[\x00-\x20]+@', '', $key);
if (!strlen($key)) {
continue;
}
$options = array(
'command="'.$cmd.'"',

View file

@ -73,21 +73,18 @@ final class PhabricatorAuthSSHKeyQuery
if ($this->objectPHIDs !== null) {
$where[] = qsprintf(
$conn_r,
'userPHID IN (%Ls)',
'objectPHID IN (%Ls)',
$this->objectPHIDs);
}
if ($this->keys !== null) {
// TODO: This could take advantage of a better key, and the hashing
// scheme for this table is a bit nonstandard and questionable.
$sql = array();
foreach ($this->keys as $key) {
$sql[] = qsprintf(
$conn_r,
'(keyType = %s AND keyBody = %s)',
'(keyType = %s AND keyIndex = %s)',
$key->getType(),
$key->getBody());
$key->getHash());
}
$where[] = implode(' OR ', $sql);
}

View file

@ -4,43 +4,45 @@ final class PhabricatorAuthSSHKey
extends PhabricatorAuthDAO
implements PhabricatorPolicyInterface {
protected $userPHID;
protected $objectPHID;
protected $name;
protected $keyType;
protected $keyIndex;
protected $keyBody;
protected $keyHash;
protected $keyComment;
protected $keyComment = '';
private $object = self::ATTACHABLE;
public function getObjectPHID() {
return $this->getUserPHID();
}
public function getConfiguration() {
return array(
self::CONFIG_COLUMN_SCHEMA => array(
'keyHash' => 'bytes32',
'keyComment' => 'text255?',
// T6203/NULLABILITY
// These seem like they should not be nullable.
'name' => 'text255?',
'keyType' => 'text255?',
'keyBody' => 'text?',
'name' => 'text255',
'keyType' => 'text255',
'keyIndex' => 'bytes12',
'keyBody' => 'text',
'keyComment' => 'text255',
),
self::CONFIG_KEY_SCHEMA => array(
'userPHID' => array(
'columns' => array('userPHID'),
'key_object' => array(
'columns' => array('objectPHID'),
),
'keyHash' => array(
'columns' => array('keyHash'),
'key_unique' => array(
'columns' => array('keyIndex'),
'unique' => true,
),
),
) + parent::getConfiguration();
}
public function save() {
$this->setKeyIndex($this->toPublicKey()->getHash());
return parent::save();
}
public function toPublicKey() {
return PhabricatorAuthSSHPublicKey::newFromStoredKey($this);
}
public function getEntireKey() {
$parts = array(
$this->getKeyType(),
@ -60,6 +62,8 @@ final class PhabricatorAuthSSHKey
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */

View file

@ -13,6 +13,15 @@ final class PhabricatorAuthSSHPublicKey extends Phobject {
// <internal>
}
public static function newFromStoredKey(PhabricatorAuthSSHKey $key) {
$public_key = new PhabricatorAuthSSHPublicKey();
$public_key->type = $key->getKeyType();
$public_key->body = $key->getKeyBody();
$public_key->comment = $key->getKeyComment();
return $public_key;
}
public static function newFromRawKey($entire_key) {
$entire_key = trim($entire_key);
if (!strlen($entire_key)) {
@ -83,4 +92,11 @@ final class PhabricatorAuthSSHPublicKey extends Phobject {
return $this->comment;
}
public function getHash() {
$body = $this->getBody();
$body = trim($body);
$body = rtrim($body, '=');
return PhabricatorHash::digestForIndex($body);
}
}

View file

@ -897,7 +897,7 @@ EOBODY;
}
$keys = id(new PhabricatorAuthSSHKey())->loadAllWhere(
'userPHID = %s',
'objectPHID = %s',
$this->getPHID());
foreach ($keys as $key) {
$key->delete();

View file

@ -44,8 +44,7 @@ final class PhabricatorSettingsPanelSSHKeys
$this->getPanelURI());
$id = nonempty($edit, $delete);
if ($id) {
if ($id && (int)$id) {
$key = id(new PhabricatorAuthSSHKeyQuery())
->setViewer($viewer)
->withIDs(array($id))
@ -59,8 +58,8 @@ final class PhabricatorSettingsPanelSSHKeys
return new Aphront404Response();
}
} else {
$key = new PhabricatorAuthSSHKey();
$key->setUserPHID($user->getPHID());
$key = id(new PhabricatorAuthSSHKey())
->setObjectPHID($user->getPHID());
}
if ($delete) {
@ -89,7 +88,6 @@ final class PhabricatorSettingsPanelSSHKeys
$key->setKeyType($type);
$key->setKeyBody($body);
$key->setKeyHash(md5($body));
$key->setKeyComment($comment);
$e_key = null;
@ -309,11 +307,10 @@ final class PhabricatorSettingsPanelSSHKeys
$body = $public_key->getBody();
$key = id(new PhabricatorAuthSSHKey())
->setUserPHID($user->getPHID())
->setObjectPHID($user->getPHID())
->setName('id_rsa_phabricator')
->setKeyType($type)
->setKeyBody($body)
->setKeyHash(md5($body))
->setKeyComment(pht('Generated'))
->save();