diff --git a/scripts/ssh/ssh-auth.php b/scripts/ssh/ssh-auth.php --- a/scripts/ssh/ssh-auth.php +++ b/scripts/ssh/ssh-auth.php @@ -4,74 +4,84 @@ $root = dirname(dirname(dirname(__FILE__))); require_once $root.'/scripts/__init_script__.php'; -$keys = id(new PhabricatorAuthSSHKeyQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withIsActive(true) - ->execute(); - -if (!$keys) { - echo pht('No keys found.')."\n"; - exit(1); -} +$cache = PhabricatorCaches::getMutableCache(); +$authfile_key = PhabricatorAuthSSHKeyQuery::AUTHFILE_CACHEKEY; +$authfile = $cache->getKey($authfile_key); + +if ($authfile === null) { + $keys = id(new PhabricatorAuthSSHKeyQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withIsActive(true) + ->execute(); + + if (!$keys) { + echo pht('No keys found.')."\n"; + exit(1); + } -$bin = $root.'/bin/ssh-exec'; -foreach ($keys as $ssh_key) { - $key_argv = array(); - $object = $ssh_key->getObject(); - if ($object instanceof PhabricatorUser) { - $key_argv[] = '--phabricator-ssh-user'; - $key_argv[] = $object->getUsername(); - } else if ($object instanceof AlmanacDevice) { - if (!$ssh_key->getIsTrusted()) { - // If this key is not a trusted device key, don't allow SSH - // authentication. + $bin = $root.'/bin/ssh-exec'; + foreach ($keys as $ssh_key) { + $key_argv = array(); + $object = $ssh_key->getObject(); + if ($object instanceof PhabricatorUser) { + $key_argv[] = '--phabricator-ssh-user'; + $key_argv[] = $object->getUsername(); + } else if ($object instanceof AlmanacDevice) { + if (!$ssh_key->getIsTrusted()) { + // If this key is not a trusted device key, don't allow SSH + // authentication. + continue; + } + $key_argv[] = '--phabricator-ssh-device'; + $key_argv[] = $object->getName(); + } else { + // We don't know what sort of key this is; don't permit SSH auth. continue; } - $key_argv[] = '--phabricator-ssh-device'; - $key_argv[] = $object->getName(); - } else { - // We don't know what sort of key this is; don't permit SSH auth. - continue; - } - $key_argv[] = '--phabricator-ssh-key'; - $key_argv[] = $ssh_key->getID(); + $key_argv[] = '--phabricator-ssh-key'; + $key_argv[] = $ssh_key->getID(); - $cmd = csprintf('%s %Ls', $bin, $key_argv); + $cmd = csprintf('%s %Ls', $bin, $key_argv); - $instance = PhabricatorEnv::getEnvConfig('cluster.instance'); - if (strlen($instance)) { - $cmd = csprintf('PHABRICATOR_INSTANCE=%s %C', $instance, $cmd); - } + $instance = PhabricatorEnv::getEnvConfig('cluster.instance'); + if (strlen($instance)) { + $cmd = csprintf('PHABRICATOR_INSTANCE=%s %C', $instance, $cmd); + } - // This is additional escaping for the SSH 'command="..."' string. - $cmd = addcslashes($cmd, '"\\'); + // This is additional escaping for the SSH 'command="..."' string. + $cmd = addcslashes($cmd, '"\\'); - // Strip out newlines and other nonsense from the key type and key body. + // Strip out newlines and other nonsense from the key type and key body. - $type = $ssh_key->getKeyType(); - $type = preg_replace('@[\x00-\x20]+@', '', $type); - if (!strlen($type)) { - continue; - } + $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; - } + $key = $ssh_key->getKeyBody(); + $key = preg_replace('@[\x00-\x20]+@', '', $key); + if (!strlen($key)) { + continue; + } + + $options = array( + 'command="'.$cmd.'"', + 'no-port-forwarding', + 'no-X11-forwarding', + 'no-agent-forwarding', + 'no-pty', + ); + $options = implode(',', $options); - $options = array( - 'command="'.$cmd.'"', - 'no-port-forwarding', - 'no-X11-forwarding', - 'no-agent-forwarding', - 'no-pty', - ); - $options = implode(',', $options); + $lines[] = $options.' '.$type.' '.$key."\n"; + } - $lines[] = $options.' '.$type.' '.$key."\n"; + $authfile = implode('', $lines); + $ttl = phutil_units('24 hours in seconds'); + $cache->setKey($authfile_key, $authfile, $ttl); } -echo implode('', $lines); +echo $authfile; exit(0); diff --git a/src/applications/auth/editor/PhabricatorAuthSSHKeyEditor.php b/src/applications/auth/editor/PhabricatorAuthSSHKeyEditor.php --- a/src/applications/auth/editor/PhabricatorAuthSSHKeyEditor.php +++ b/src/applications/auth/editor/PhabricatorAuthSSHKeyEditor.php @@ -191,6 +191,20 @@ return 'ssh-key-'.$object->getPHID(); } + protected function applyFinalEffects( + PhabricatorLiskDAO $object, + array $xactions) { + + // After making any change to an SSH key, drop the authfile cache so it + // is regenerated the next time anyone authenticates. + $cache = PhabricatorCaches::getMutableCache(); + $authfile_key = PhabricatorAuthSSHKeyQuery::AUTHFILE_CACHEKEY; + $cache->deleteKey($authfile_key); + + return $xactions; + } + + protected function getMailTo(PhabricatorLiskDAO $object) { return $object->getObject()->getSSHKeyNotifyPHIDs(); } diff --git a/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php b/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php --- a/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php +++ b/src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php @@ -3,6 +3,8 @@ final class PhabricatorAuthSSHKeyQuery extends PhabricatorCursorPagedPolicyAwareQuery { + const AUTHFILE_CACHEKEY = 'ssh.authfile'; + private $ids; private $phids; private $objectPHIDs; diff --git a/src/applications/cache/PhabricatorCaches.php b/src/applications/cache/PhabricatorCaches.php --- a/src/applications/cache/PhabricatorCaches.php +++ b/src/applications/cache/PhabricatorCaches.php @@ -99,6 +99,23 @@ return $caches; } + public static function getMutableCache() { + static $cache; + if (!$cache) { + $caches = self::buildMutableCaches(); + $cache = self::newStackFromCaches($caches); + } + return $cache; + } + + private static function buildMutableCaches() { + $caches = array(); + + $caches[] = new PhabricatorKeyValueDatabaseCache(); + + return $caches; + } + /* -( Repository Graph Cache )--------------------------------------------- */ diff --git a/src/applications/cache/PhabricatorKeyValueDatabaseCache.php b/src/applications/cache/PhabricatorKeyValueDatabaseCache.php --- a/src/applications/cache/PhabricatorKeyValueDatabaseCache.php +++ b/src/applications/cache/PhabricatorKeyValueDatabaseCache.php @@ -98,7 +98,7 @@ $this->establishConnection('w'), 'DELETE FROM %T WHERE cacheKeyHash IN (%Ls)', $this->getTableName(), - $keys); + $map); } return $this;