Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/auth/management/PhabricatorAuthManagementRevokeWorkflow.php b/src/applications/auth/management/PhabricatorAuthManagementRevokeWorkflow.php
index ea46fef540..6d907e67d6 100644
--- a/src/applications/auth/management/PhabricatorAuthManagementRevokeWorkflow.php
+++ b/src/applications/auth/management/PhabricatorAuthManagementRevokeWorkflow.php
@@ -1,145 +1,195 @@
<?php
final class PhabricatorAuthManagementRevokeWorkflow
extends PhabricatorAuthManagementWorkflow {
protected function didConstruct() {
$this
->setName('revoke')
->setExamples(
- "**revoke** --type __type__ --from __user__\n".
+ "**revoke** --list\n".
+ "**revoke** --type __type__ --from __@user__\n".
"**revoke** --everything --everywhere")
->setSynopsis(
pht(
'Revoke credentials which may have been leaked or disclosed.'))
->setArguments(
array(
array(
'name' => 'from',
- 'param' => 'user',
+ 'param' => 'object',
'help' => pht(
- 'Revoke credentials for the specified user.'),
+ 'Revoke credentials for the specified object. To revoke '.
+ 'credentials for a user, use "@username".'),
),
array(
'name' => 'type',
'param' => 'type',
+ 'help' => pht('Revoke credentials of the given type.'),
+ ),
+ array(
+ 'name' => 'list',
'help' => pht(
- 'Revoke credentials of the given type.'),
+ 'List information about available credential revokers.'),
),
array(
'name' => 'everything',
'help' => pht('Revoke all credentials types.'),
),
array(
'name' => 'everywhere',
'help' => pht('Revoke from all credential owners.'),
),
array(
'name' => 'force',
'help' => pht('Revoke credentials without prompting.'),
),
));
}
public function execute(PhutilArgumentParser $args) {
- $viewer = PhabricatorUser::getOmnipotentUser();
+ $viewer = $this->getViewer();
$all_types = PhabricatorAuthRevoker::getAllRevokers();
$is_force = $args->getArg('force');
+ // The "--list" flag is compatible with revoker selection flags like
+ // "--type" to filter the list, but not compatible with target selection
+ // flags like "--from".
+ $is_list = $args->getArg('list');
+
$type = $args->getArg('type');
$is_everything = $args->getArg('everything');
if (!strlen($type) && !$is_everything) {
- throw new PhutilArgumentUsageException(
- pht(
- 'Specify the credential type to revoke with "--type" or specify '.
- '"--everything".'));
+ if ($is_list) {
+ // By default, "bin/revoke --list" implies "--everything".
+ $types = $all_types;
+ } else {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Specify the credential type to revoke with "--type" or specify '.
+ '"--everything". Use "--list" to list available credential '.
+ 'types.'));
+ }
} else if (strlen($type) && $is_everything) {
throw new PhutilArgumentUsageException(
pht(
'Specify the credential type to revoke with "--type" or '.
'"--everything", but not both.'));
} else if ($is_everything) {
$types = $all_types;
} else {
if (empty($all_types[$type])) {
throw new PhutilArgumentUsageException(
pht(
'Credential type "%s" is not valid. Valid credential types '.
'are: %s.',
$type,
implode(', ', array_keys($all_types))));
}
$types = array($all_types[$type]);
}
$is_everywhere = $args->getArg('everywhere');
$from = $args->getArg('from');
+
+ if ($is_list) {
+ if (strlen($from) || $is_everywhere) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'You can not "--list" and revoke credentials (with "--from" or '.
+ '"--everywhere") in the same operation.'));
+ }
+ }
+
+ if ($is_list) {
+ $last_key = last_key($types);
+ foreach ($types as $key => $type) {
+ echo tsprintf(
+ "**%s** (%s)\n\n",
+ $type->getRevokerKey(),
+ $type->getRevokerName());
+
+ id(new PhutilConsoleBlock())
+ ->addParagraph(tsprintf('%B', $type->getRevokerDescription()))
+ ->draw();
+ }
+
+ return 0;
+ }
+
$target = null;
if (!strlen($from) && !$is_everywhere) {
throw new PhutilArgumentUsageException(
pht(
'Specify the target to revoke credentials from with "--from" or '.
'specify "--everywhere".'));
} else if (strlen($from) && $is_everywhere) {
throw new PhutilArgumentUsageException(
pht(
'Specify the target to revoke credentials from with "--from" or '.
'specify "--everywhere", but not both.'));
} else if ($is_everywhere) {
// Just carry the flag through.
} else {
$target = id(new PhabricatorObjectQuery())
->setViewer($viewer)
->withNames(array($from))
->executeOne();
if (!$target) {
throw new PhutilArgumentUsageException(
pht(
'Target "%s" is not a valid target to revoke credentials from. '.
'Usually, revoke from "@username".',
$from));
}
}
if ($is_everywhere && !$is_force) {
echo id(new PhutilConsoleBlock())
->addParagraph(
pht(
'You are destroying an entire class of credentials. This may be '.
'very disruptive to users. You should normally do this only if '.
'you suspect there has been a widespread compromise which may '.
'have impacted everyone.'))
->drawConsoleString();
$prompt = pht('Really destroy credentials everywhere?');
if (!phutil_console_confirm($prompt)) {
throw new PhutilArgumentUsageException(
pht('Aborted workflow.'));
}
}
foreach ($types as $type) {
$type->setViewer($viewer);
if ($is_everywhere) {
$count = $type->revokeAllCredentials();
} else {
$count = $type->revokeCredentialsFrom($target);
}
echo tsprintf(
"%s\n",
pht(
'Destroyed %s credential(s) of type "%s".',
new PhutilNumber($count),
$type->getRevokerKey()));
+
+ $guidance = $type->getRevokerNextSteps();
+ if ($guidance !== null) {
+ echo tsprintf(
+ "%s\n",
+ $guidance);
+ }
}
echo tsprintf(
"%s\n",
pht('Done.'));
return 0;
}
}
diff --git a/src/applications/auth/revoker/PhabricatorAuthConduitTokenRevoker.php b/src/applications/auth/revoker/PhabricatorAuthConduitTokenRevoker.php
index c3b8572d55..578b489a24 100644
--- a/src/applications/auth/revoker/PhabricatorAuthConduitTokenRevoker.php
+++ b/src/applications/auth/revoker/PhabricatorAuthConduitTokenRevoker.php
@@ -1,33 +1,46 @@
<?php
final class PhabricatorAuthConduitTokenRevoker
extends PhabricatorAuthRevoker {
const REVOKERKEY = 'conduit';
+ public function getRevokerName() {
+ return pht('Conduit API Tokens');
+ }
+
+ public function getRevokerDescription() {
+ return pht(
+ "Revokes all Conduit API tokens used to access the API.\n\n".
+ "Users will need to use `arc install-certificate` to install new ".
+ "API tokens before `arc` commands will work. Bots and scripts which ".
+ "access the API will need to have new tokens generated and ".
+ "installed.");
+ }
+
public function revokeAllCredentials() {
$table = id(new PhabricatorConduitToken());
$conn = $table->establishConnection('w');
queryfx(
$conn,
'DELETE FROM %T',
$table->getTableName());
return $conn->getAffectedRows();
}
public function revokeCredentialsFrom($object) {
$table = id(new PhabricatorConduitToken());
$conn = $table->establishConnection('w');
queryfx(
$conn,
'DELETE FROM %T WHERE objectPHID = %s',
$table->getTableName(),
$object->getPHID());
return $conn->getAffectedRows();
}
}
diff --git a/src/applications/auth/revoker/PhabricatorAuthPasswordRevoker.php b/src/applications/auth/revoker/PhabricatorAuthPasswordRevoker.php
index e42d0db256..646d266b1e 100644
--- a/src/applications/auth/revoker/PhabricatorAuthPasswordRevoker.php
+++ b/src/applications/auth/revoker/PhabricatorAuthPasswordRevoker.php
@@ -1,52 +1,81 @@
<?php
final class PhabricatorAuthPasswordRevoker
extends PhabricatorAuthRevoker {
const REVOKERKEY = 'password';
+ public function getRevokerName() {
+ return pht('Passwords');
+ }
+
+ public function getRevokerDescription() {
+ return pht(
+ "Revokes all stored passwords.\n\n".
+ "Account passwords and VCS passwords (used to access repositories ".
+ "over HTTP) will both be revoked. Passwords for any third party ".
+ "applications which use shared password infrastructure will also ".
+ "be revoked.\n\n".
+ "Users will need to reset account passwords, possibly by using the ".
+ "\"Forgot Password?\" link on the login page. They will also need ".
+ "to reset VCS passwords.\n\n".
+ "Passwords are revoked, not just removed. Users will be unable to ".
+ "select the passwords they used previously and must choose new, ".
+ "unique passwords.\n\n".
+ "Revoking passwords will not terminate outstanding login sessions. ".
+ "Use the \"session\" revoker in conjunction with this revoker to force ".
+ "users to login again.");
+ }
+
+ public function getRevokerNextSteps() {
+ return pht(
+ 'NOTE: Revoking passwords does not terminate existing sessions which '.
+ 'were established using the old passwords. To terminate existing '.
+ 'sessions, run the "session" revoker now.');
+ }
+
public function revokeAllCredentials() {
$query = new PhabricatorAuthPasswordQuery();
return $this->revokeWithQuery($query);
}
public function revokeCredentialsFrom($object) {
$query = id(new PhabricatorAuthPasswordQuery())
->withObjectPHIDs(array($object->getPHID()));
return $this->revokeWithQuery($query);
}
private function revokeWithQuery(PhabricatorAuthPasswordQuery $query) {
$viewer = $this->getViewer();
$passwords = $query
->setViewer($viewer)
->withIsRevoked(false)
->execute();
$content_source = PhabricatorContentSource::newForSource(
PhabricatorDaemonContentSource::SOURCECONST);
$revoke_type = PhabricatorAuthPasswordRevokeTransaction::TRANSACTIONTYPE;
$auth_phid = id(new PhabricatorAuthApplication())->getPHID();
foreach ($passwords as $password) {
$xactions = array();
$xactions[] = $password->getApplicationTransactionTemplate()
->setTransactionType($revoke_type)
->setNewValue(true);
$editor = $password->getApplicationTransactionEditor()
->setActor($viewer)
->setActingAsPHID($auth_phid)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->setContentSource($content_source)
->applyTransactions($password, $xactions);
}
return count($passwords);
}
}
diff --git a/src/applications/auth/revoker/PhabricatorAuthRevoker.php b/src/applications/auth/revoker/PhabricatorAuthRevoker.php
index 3a807e3089..9bf44b05bc 100644
--- a/src/applications/auth/revoker/PhabricatorAuthRevoker.php
+++ b/src/applications/auth/revoker/PhabricatorAuthRevoker.php
@@ -1,31 +1,38 @@
<?php
abstract class PhabricatorAuthRevoker
extends Phobject {
private $viewer;
abstract public function revokeAllCredentials();
abstract public function revokeCredentialsFrom($object);
+ abstract public function getRevokerName();
+ abstract public function getRevokerDescription();
+
+ public function getRevokerNextSteps() {
+ return null;
+ }
+
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
}
public function getViewer() {
return $this->viewer;
}
final public function getRevokerKey() {
return $this->getPhobjectClassConstant('REVOKERKEY');
}
final public static function getAllRevokers() {
return id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)
->setUniqueMethod('getRevokerKey')
->execute();
}
}
diff --git a/src/applications/auth/revoker/PhabricatorAuthSSHRevoker.php b/src/applications/auth/revoker/PhabricatorAuthSSHRevoker.php
index a18a2e7812..3e6b862370 100644
--- a/src/applications/auth/revoker/PhabricatorAuthSSHRevoker.php
+++ b/src/applications/auth/revoker/PhabricatorAuthSSHRevoker.php
@@ -1,53 +1,65 @@
<?php
final class PhabricatorAuthSSHRevoker
extends PhabricatorAuthRevoker {
const REVOKERKEY = 'ssh';
+ public function getRevokerName() {
+ return pht('SSH Keys');
+ }
+
+ public function getRevokerDescription() {
+ return pht(
+ "Revokes all SSH public keys.\n\n".
+ "SSH public keys are revoked, not just removed. Users will need to ".
+ "generate and upload new, unique keys before they can access ".
+ "repositories or other services over SSH.");
+ }
+
public function revokeAllCredentials() {
$query = new PhabricatorAuthSSHKeyQuery();
return $this->revokeWithQuery($query);
}
public function revokeCredentialsFrom($object) {
$query = id(new PhabricatorAuthSSHKeyQuery())
->withObjectPHIDs(array($object->getPHID()));
return $this->revokeWithQuery($query);
}
private function revokeWithQuery(PhabricatorAuthSSHKeyQuery $query) {
$viewer = $this->getViewer();
// We're only going to revoke keys which have not already been revoked.
$ssh_keys = $query
->setViewer($viewer)
->withIsActive(true)
->execute();
$content_source = PhabricatorContentSource::newForSource(
PhabricatorDaemonContentSource::SOURCECONST);
$auth_phid = id(new PhabricatorAuthApplication())->getPHID();
foreach ($ssh_keys as $ssh_key) {
$xactions = array();
$xactions[] = $ssh_key->getApplicationTransactionTemplate()
->setTransactionType(PhabricatorAuthSSHKeyTransaction::TYPE_DEACTIVATE)
->setNewValue(1);
$editor = $ssh_key->getApplicationTransactionEditor()
->setActor($viewer)
->setActingAsPHID($auth_phid)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->setContentSource($content_source)
->setIsAdministrativeEdit(true)
->applyTransactions($ssh_key, $xactions);
}
return count($ssh_keys);
}
}
diff --git a/src/applications/auth/revoker/PhabricatorAuthSessionRevoker.php b/src/applications/auth/revoker/PhabricatorAuthSessionRevoker.php
index b5e294e6f1..c3362b0331 100644
--- a/src/applications/auth/revoker/PhabricatorAuthSessionRevoker.php
+++ b/src/applications/auth/revoker/PhabricatorAuthSessionRevoker.php
@@ -1,33 +1,43 @@
<?php
final class PhabricatorAuthSessionRevoker
extends PhabricatorAuthRevoker {
const REVOKERKEY = 'session';
+ public function getRevokerName() {
+ return pht('Sessions');
+ }
+
+ public function getRevokerDescription() {
+ return pht(
+ "Revokes all active login sessions.\n\n".
+ "Affected users will be logged out and need to log in again.");
+ }
+
public function revokeAllCredentials() {
$table = new PhabricatorAuthSession();
$conn = $table->establishConnection('w');
queryfx(
$conn,
'DELETE FROM %T',
$table->getTableName());
return $conn->getAffectedRows();
}
public function revokeCredentialsFrom($object) {
$table = new PhabricatorAuthSession();
$conn = $table->establishConnection('w');
queryfx(
$conn,
'DELETE FROM %T WHERE userPHID = %s',
$table->getTableName(),
$object->getPHID());
return $conn->getAffectedRows();
}
}
diff --git a/src/applications/auth/revoker/PhabricatorAuthTemporaryTokenRevoker.php b/src/applications/auth/revoker/PhabricatorAuthTemporaryTokenRevoker.php
index 8f9fdb2b9e..f274e13a18 100644
--- a/src/applications/auth/revoker/PhabricatorAuthTemporaryTokenRevoker.php
+++ b/src/applications/auth/revoker/PhabricatorAuthTemporaryTokenRevoker.php
@@ -1,33 +1,46 @@
<?php
final class PhabricatorAuthTemporaryTokenRevoker
extends PhabricatorAuthRevoker {
const REVOKERKEY = 'temporary';
+ public function getRevokerName() {
+ return pht('Temporary Tokens');
+ }
+
+ public function getRevokerDescription() {
+ return pht(
+ "Revokes temporary authentication tokens.\n\n".
+ "Temporary tokens are used in password reset mail, welcome mail, and ".
+ "by some other systems like Git LFS. Revoking temporary tokens will ".
+ "invalidate existing links in password reset and invite mail that ".
+ "was sent before the revocation occurred.");
+ }
+
public function revokeAllCredentials() {
$table = new PhabricatorAuthTemporaryToken();
$conn = $table->establishConnection('w');
queryfx(
$conn,
'DELETE FROM %T',
$table->getTableName());
return $conn->getAffectedRows();
}
public function revokeCredentialsFrom($object) {
$table = new PhabricatorAuthTemporaryToken();
$conn = $table->establishConnection('w');
queryfx(
$conn,
'DELETE FROM %T WHERE tokenResource = %s',
$table->getTableName(),
$object->getPHID());
return $conn->getAffectedRows();
}
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Apr 29, 2:02 AM (19 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
108154
Default Alt Text
(17 KB)

Event Timeline