mirror of
https://we.phorge.it/source/phorge.git
synced 2025-03-28 12:08:14 +01:00
Summary: Ref T13222. Providers can now be deprecated (existing factors still work, but users can't add new factors for the provider) or disabled (factors stop working, also can't add new ones). Test Plan: - Enabled, deprecated, and disabled some providers. - Viewed provider detail, provider list. - Viewed MFA settings list. - Verified that I'm prompted for enabled + deprecated only at gates. - Tried to disable final provider, got an error. - Hit the MFA setup gate by enabling "Require MFA" with no providers, got a more useful message. - Immediately forced a user to the "MFA Setup Gate" by disabling their only active provider with another provider enabled ("We no longer support TOTP, you HAVE to finish Duo enrollment to continue starting Monday."). Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13222 Differential Revision: https://secure.phabricator.com/D20031
103 lines
3.2 KiB
PHP
103 lines
3.2 KiB
PHP
<?php
|
|
|
|
final class PhabricatorAuthFactorProviderStatusTransaction
|
|
extends PhabricatorAuthFactorProviderTransactionType {
|
|
|
|
const TRANSACTIONTYPE = 'status';
|
|
|
|
public function generateOldValue($object) {
|
|
return $object->getStatus();
|
|
}
|
|
|
|
public function applyInternalEffects($object, $value) {
|
|
$object->setStatus($value);
|
|
}
|
|
|
|
public function getTitle() {
|
|
$old = $this->getOldValue();
|
|
$new = $this->getNewValue();
|
|
|
|
$old_display = PhabricatorAuthFactorProviderStatus::newForStatus($old)
|
|
->getName();
|
|
$new_display = PhabricatorAuthFactorProviderStatus::newForStatus($new)
|
|
->getName();
|
|
|
|
return pht(
|
|
'%s changed the status of this provider from %s to %s.',
|
|
$this->renderAuthor(),
|
|
$this->renderValue($old_display),
|
|
$this->renderValue($new_display));
|
|
}
|
|
|
|
public function validateTransactions($object, array $xactions) {
|
|
$errors = array();
|
|
$actor = $this->getActor();
|
|
|
|
$map = PhabricatorAuthFactorProviderStatus::getMap();
|
|
foreach ($xactions as $xaction) {
|
|
$new_value = $xaction->getNewValue();
|
|
|
|
if (!isset($map[$new_value])) {
|
|
$errors[] = $this->newInvalidError(
|
|
pht(
|
|
'Status "%s" is invalid. Valid statuses are: %s.',
|
|
$new_value,
|
|
implode(', ', array_keys($map))),
|
|
$xaction);
|
|
continue;
|
|
}
|
|
|
|
$require_key = 'security.require-multi-factor-auth';
|
|
$require_mfa = PhabricatorEnv::getEnvConfig($require_key);
|
|
|
|
if ($require_mfa) {
|
|
$status_active = PhabricatorAuthFactorProviderStatus::STATUS_ACTIVE;
|
|
if ($new_value !== $status_active) {
|
|
$active_providers = id(new PhabricatorAuthFactorProviderQuery())
|
|
->setViewer($actor)
|
|
->withStatuses(
|
|
array(
|
|
$status_active,
|
|
))
|
|
->execute();
|
|
$active_providers = mpull($active_providers, null, 'getID');
|
|
unset($active_providers[$object->getID()]);
|
|
|
|
if (!$active_providers) {
|
|
$errors[] = $this->newInvalidError(
|
|
pht(
|
|
'You can not deprecate or disable the last active MFA '.
|
|
'provider while "%s" is enabled, because new users would '.
|
|
'be unable to enroll in MFA. Disable the MFA requirement '.
|
|
'in Config, or create or enable another MFA provider first.',
|
|
$require_key));
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $errors;
|
|
}
|
|
|
|
public function didCommitTransaction($object, $value) {
|
|
$status = PhabricatorAuthFactorProviderStatus::newForStatus($value);
|
|
|
|
// If a provider has undergone a status change, reset the MFA enrollment
|
|
// cache for all users. This may immediately force a lot of users to redo
|
|
// MFA enrollment.
|
|
|
|
// We could be more surgical about this: we only really need to affect
|
|
// users who had a factor under the provider, and only really need to
|
|
// do anything if a provider was disabled. This is just a little simpler.
|
|
|
|
$table = new PhabricatorUser();
|
|
$conn = $table->establishConnection('w');
|
|
|
|
queryfx(
|
|
$conn,
|
|
'UPDATE %R SET isEnrolledInMultiFactor = 0',
|
|
$table);
|
|
}
|
|
|
|
}
|