Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15456348
D17500.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
8 KB
Referenced Files
None
Subscribers
None
D17500.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -3763,6 +3763,7 @@
'PhabricatorSearchBaseController' => 'applications/search/controller/PhabricatorSearchBaseController.php',
'PhabricatorSearchCheckboxesField' => 'applications/search/field/PhabricatorSearchCheckboxesField.php',
'PhabricatorSearchConfigOptions' => 'applications/search/config/PhabricatorSearchConfigOptions.php',
+ 'PhabricatorSearchConstraintException' => 'applications/search/exception/PhabricatorSearchConstraintException.php',
'PhabricatorSearchController' => 'applications/search/controller/PhabricatorSearchController.php',
'PhabricatorSearchCustomFieldProxyField' => 'applications/search/field/PhabricatorSearchCustomFieldProxyField.php',
'PhabricatorSearchDAO' => 'applications/search/storage/PhabricatorSearchDAO.php',
@@ -9072,6 +9073,7 @@
'PhabricatorSearchBaseController' => 'PhabricatorController',
'PhabricatorSearchCheckboxesField' => 'PhabricatorSearchField',
'PhabricatorSearchConfigOptions' => 'PhabricatorApplicationConfigOptions',
+ 'PhabricatorSearchConstraintException' => 'Exception',
'PhabricatorSearchController' => 'PhabricatorSearchBaseController',
'PhabricatorSearchCustomFieldProxyField' => 'PhabricatorSearchField',
'PhabricatorSearchDAO' => 'PhabricatorLiskDAO',
diff --git a/src/applications/config/option/PhabricatorSecurityConfigOptions.php b/src/applications/config/option/PhabricatorSecurityConfigOptions.php
--- a/src/applications/config/option/PhabricatorSecurityConfigOptions.php
+++ b/src/applications/config/option/PhabricatorSecurityConfigOptions.php
@@ -66,6 +66,21 @@
,
PhabricatorEnv::getDoclink('Configuring Encryption')));
+ $require_mfa_description = $this->deformat(pht(<<<EOTEXT
+By default, Phabricator allows users to add multi-factor authentication to
+their accounts, but does not require it. By enabling this option, you can
+force all users to add at least one authentication factor before they can use
+their accounts.
+
+Administrators can query a list of users who do not have MFA configured in
+{nav People}:
+
+ - **[[ %s | %s ]]**
+EOTEXT
+ ,
+ '/people/?mfa=false',
+ pht('List of Users Without MFA')));
+
return array(
$this->newOption('security.alternate-file-domain', 'string', null)
->setLocked(true)
@@ -132,13 +147,7 @@
->setLocked(true)
->setSummary(
pht('Require all users to configure multi-factor authentication.'))
- ->setDescription(
- pht(
- 'By default, Phabricator allows users to add multi-factor '.
- 'authentication to their accounts, but does not require it. '.
- 'By enabling this option, you can force all users to add '.
- 'at least one authentication factor before they can use their '.
- 'accounts.'))
+ ->setDescription($require_mfa_description)
->setBoolOptions(
array(
pht('Multi-Factor Required'),
diff --git a/src/applications/people/query/PhabricatorPeopleQuery.php b/src/applications/people/query/PhabricatorPeopleQuery.php
--- a/src/applications/people/query/PhabricatorPeopleQuery.php
+++ b/src/applications/people/query/PhabricatorPeopleQuery.php
@@ -18,6 +18,7 @@
private $nameLike;
private $nameTokens;
private $namePrefixes;
+ private $isEnrolledInMultiFactor;
private $needPrimaryEmail;
private $needProfile;
@@ -100,6 +101,11 @@
return $this;
}
+ public function withIsEnrolledInMultiFactor($enrolled) {
+ $this->isEnrolledInMultiFactor = $enrolled;
+ return $this;
+ }
+
public function needPrimaryEmail($need) {
$this->needPrimaryEmail = $need;
return $this;
@@ -337,6 +343,13 @@
$this->nameLike);
}
+ if ($this->isEnrolledInMultiFactor !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'user.isEnrolledInMultiFactor = %d',
+ (int)$this->isEnrolledInMultiFactor);
+ }
+
return $where;
}
diff --git a/src/applications/people/query/PhabricatorPeopleSearchEngine.php b/src/applications/people/query/PhabricatorPeopleSearchEngine.php
--- a/src/applications/people/query/PhabricatorPeopleSearchEngine.php
+++ b/src/applications/people/query/PhabricatorPeopleSearchEngine.php
@@ -18,7 +18,7 @@
}
protected function buildCustomSearchFields() {
- return array(
+ $fields = array(
id(new PhabricatorSearchStringListField())
->setLabel(pht('Usernames'))
->setKey('usernames')
@@ -84,18 +84,36 @@
pht(
'Pass true to find only users awaiting administrative approval, '.
'or false to omit these users.')),
- id(new PhabricatorSearchDateField())
- ->setKey('createdStart')
- ->setLabel(pht('Joined After'))
- ->setDescription(
- pht('Find user accounts created after a given time.')),
- id(new PhabricatorSearchDateField())
- ->setKey('createdEnd')
- ->setLabel(pht('Joined Before'))
+ );
+
+ $viewer = $this->requireViewer();
+ if ($viewer->getIsAdmin()) {
+ $fields[] = id(new PhabricatorSearchThreeStateField())
+ ->setLabel(pht('Has MFA'))
+ ->setKey('mfa')
+ ->setOptions(
+ pht('(Show All)'),
+ pht('Show Only Users With MFA'),
+ pht('Hide Users With MFA'))
->setDescription(
- pht('Find user accounts created before a given time.')),
+ pht(
+ 'Pass true to find only users who are enrolled in MFA, or false '.
+ 'to omit these users.'));
+ }
- );
+ $fields[] = id(new PhabricatorSearchDateField())
+ ->setKey('createdStart')
+ ->setLabel(pht('Joined After'))
+ ->setDescription(
+ pht('Find user accounts created after a given time.'));
+
+ $fields[] = id(new PhabricatorSearchDateField())
+ ->setKey('createdEnd')
+ ->setLabel(pht('Joined Before'))
+ ->setDescription(
+ pht('Find user accounts created before a given time.'));
+
+ return $fields;
}
protected function getDefaultFieldOrder() {
@@ -151,6 +169,19 @@
$query->withIsApproved(!$map['needsApproval']);
}
+ if (idx($map, 'mfa') !== null) {
+ $viewer = $this->requireViewer();
+ if (!$viewer->getIsAdmin()) {
+ throw new PhabricatorSearchConstraintException(
+ pht(
+ 'The "Has MFA" query constraint may only be used by '.
+ 'administrators, to prevent attackers from using it to target '.
+ 'weak accounts.'));
+ }
+
+ $query->withIsEnrolledInMultiFactor($map['mfa']);
+ }
+
if ($map['createdStart']) {
$query->withDateCreatedAfter($map['createdStart']);
}
@@ -255,6 +286,12 @@
}
if ($viewer->getIsAdmin()) {
+ if ($user->getIsEnrolledInMultiFactor()) {
+ $item->addIcon('fa-lock', pht('Has MFA'));
+ }
+ }
+
+ if ($viewer->getIsAdmin()) {
$user_id = $user->getID();
if ($is_approval) {
$item->addAction(
diff --git a/src/applications/search/controller/PhabricatorApplicationSearchController.php b/src/applications/search/controller/PhabricatorApplicationSearchController.php
--- a/src/applications/search/controller/PhabricatorApplicationSearchController.php
+++ b/src/applications/search/controller/PhabricatorApplicationSearchController.php
@@ -331,6 +331,8 @@
'query parameters and correct errors.');
} catch (PhutilSearchQueryCompilerSyntaxException $ex) {
$exec_errors[] = $ex->getMessage();
+ } catch (PhabricatorSearchConstraintException $ex) {
+ $exec_errors[] = $ex->getMessage();
}
// The engine may have encountered additional errors during rendering;
diff --git a/src/applications/search/exception/PhabricatorSearchConstraintException.php b/src/applications/search/exception/PhabricatorSearchConstraintException.php
new file mode 100644
--- /dev/null
+++ b/src/applications/search/exception/PhabricatorSearchConstraintException.php
@@ -0,0 +1,4 @@
+<?php
+
+final class PhabricatorSearchConstraintException
+ extends Exception {}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Mar 31, 8:58 AM (3 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7223533
Default Alt Text
D17500.diff (8 KB)
Attached To
Mode
D17500: Allow administrators to get a list of users who don't have MFA configured
Attached
Detach File
Event Timeline
Log In to Comment