Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2892359
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
14 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/applications/settings/panel/PhabricatorSettingsPanelMultiFactor.php b/src/applications/settings/panel/PhabricatorSettingsPanelMultiFactor.php
index 0ba72962c1..716026da2e 100644
--- a/src/applications/settings/panel/PhabricatorSettingsPanelMultiFactor.php
+++ b/src/applications/settings/panel/PhabricatorSettingsPanelMultiFactor.php
@@ -1,304 +1,318 @@
<?php
final class PhabricatorSettingsPanelMultiFactor
extends PhabricatorSettingsPanel {
public function getPanelKey() {
return 'multifactor';
}
public function getPanelName() {
return pht('Multi-Factor Auth');
}
public function getPanelGroup() {
return pht('Authentication');
}
public function processRequest(AphrontRequest $request) {
if ($request->getExists('new')) {
return $this->processNew($request);
}
if ($request->getExists('edit')) {
return $this->processEdit($request);
}
if ($request->getExists('delete')) {
return $this->processDelete($request);
}
$user = $this->getUser();
$viewer = $request->getUser();
$factors = id(new PhabricatorAuthFactorConfig())->loadAllWhere(
'userPHID = %s',
$user->getPHID());
$rows = array();
$rowc = array();
$highlight_id = $request->getInt('id');
foreach ($factors as $factor) {
$impl = $factor->getImplementation();
if ($impl) {
$type = $impl->getFactorName();
} else {
$type = $factor->getFactorKey();
}
if ($factor->getID() == $highlight_id) {
$rowc[] = 'highlighted';
} else {
$rowc[] = null;
}
$rows[] = array(
javelin_tag(
'a',
array(
'href' => $this->getPanelURI('?edit='.$factor->getID()),
'sigil' => 'workflow',
),
$factor->getFactorName()),
$type,
phabricator_datetime($factor->getDateCreated(), $viewer),
javelin_tag(
'a',
array(
'href' => $this->getPanelURI('?delete='.$factor->getID()),
'sigil' => 'workflow',
'class' => 'small grey button',
),
pht('Remove')),
);
}
$table = new AphrontTableView($rows);
$table->setNoDataString(
pht("You haven't added any authentication factors to your account yet."));
$table->setHeaders(
array(
pht('Name'),
pht('Type'),
pht('Created'),
'',
));
$table->setColumnClasses(
array(
'wide pri',
'',
'right',
'action',
));
$table->setRowClasses($rowc);
$table->setDeviceVisibility(
array(
true,
false,
false,
true,
));
$panel = new PHUIObjectBoxView();
$header = new PHUIHeaderView();
+ $help_uri = PhabricatorEnv::getDoclink(
+ 'User Guide: Multi-Factor Authentication');
+
+ $help_icon = id(new PHUIIconView())
+ ->setSpriteSheet(PHUIIconView::SPRITE_ICONS)
+ ->setSpriteIcon('lint-info');
+ $help_button = id(new PHUIButtonView())
+ ->setText(pht('Help'))
+ ->setHref($help_uri)
+ ->setTag('a')
+ ->setIcon($help_icon);
+
$create_icon = id(new PHUIIconView())
->setSpriteSheet(PHUIIconView::SPRITE_ICONS)
->setSpriteIcon('new');
$create_button = id(new PHUIButtonView())
->setText(pht('Add Authentication Factor'))
->setHref($this->getPanelURI('?new=true'))
->setTag('a')
->setWorkflow(true)
->setIcon($create_icon);
$header->setHeader(pht('Authentication Factors'));
+ $header->addActionLink($help_button);
$header->addActionLink($create_button);
$panel->setHeader($header);
$panel->appendChild($table);
return $panel;
}
private function processNew(AphrontRequest $request) {
$viewer = $request->getUser();
$user = $this->getUser();
$token = id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession(
$viewer,
$request,
$this->getPanelURI());
$factors = PhabricatorAuthFactor::getAllFactors();
$form = id(new AphrontFormView())
->setUser($viewer);
$type = $request->getStr('type');
if (empty($factors[$type]) || !$request->isFormPost()) {
$factor = null;
} else {
$factor = $factors[$type];
}
$dialog = id(new AphrontDialogView())
->setUser($viewer)
->addHiddenInput('new', true);
if ($factor === null) {
$choice_control = id(new AphrontFormRadioButtonControl())
->setName('type')
->setValue(key($factors));
foreach ($factors as $available_factor) {
$choice_control->addButton(
$available_factor->getFactorKey(),
$available_factor->getFactorName(),
$available_factor->getFactorDescription());
}
$dialog->appendParagraph(
pht(
- 'Adding an additional authentication factor increases the security '.
- 'of your account.'));
+ 'Adding an additional authentication factor improves the security '.
+ 'of your account. Choose the type of factor to add:'));
$form
->appendChild($choice_control);
+
} else {
$dialog->addHiddenInput('type', $type);
$config = $factor->processAddFactorForm(
$form,
$request,
$user);
if ($config) {
$config->save();
$log = PhabricatorUserLog::initializeNewLog(
$viewer,
$user->getPHID(),
PhabricatorUserLog::ACTION_MULTI_ADD);
$log->save();
return id(new AphrontRedirectResponse())
->setURI($this->getPanelURI('?id='.$config->getID()));
}
}
$dialog
->setWidth(AphrontDialogView::WIDTH_FORM)
->setTitle(pht('Add Authentication Factor'))
->appendChild($form->buildLayoutView())
->addSubmitButton(pht('Continue'))
->addCancelButton($this->getPanelURI());
return id(new AphrontDialogResponse())
->setDialog($dialog);
}
private function processEdit(AphrontRequest $request) {
$viewer = $request->getUser();
$user = $this->getUser();
$factor = id(new PhabricatorAuthFactorConfig())->loadOneWhere(
'id = %d AND userPHID = %s',
$request->getInt('edit'),
$user->getPHID());
if (!$factor) {
return new Aphront404Response();
}
$e_name = true;
$errors = array();
if ($request->isFormPost()) {
$name = $request->getStr('name');
if (!strlen($name)) {
$e_name = pht('Required');
$errors[] = pht(
'Authentication factors must have a name to identify them.');
}
if (!$errors) {
$factor->setFactorName($name);
$factor->save();
return id(new AphrontRedirectResponse())
->setURI($this->getPanelURI('?id='.$factor->getID()));
}
} else {
$name = $factor->getFactorName();
}
$form = id(new AphrontFormView())
->setUser($viewer)
->appendChild(
id(new AphrontFormTextControl())
->setName('name')
->setLabel(pht('Name'))
->setValue($name)
->setError($e_name));
$dialog = id(new AphrontDialogView())
->setUser($viewer)
->addHiddenInput('edit', $factor->getID())
->setTitle(pht('Edit Authentication Factor'))
->setErrors($errors)
->appendChild($form->buildLayoutView())
->addSubmitButton(pht('Save'))
->addCancelButton($this->getPanelURI());
return id(new AphrontDialogResponse())
->setDialog($dialog);
}
private function processDelete(AphrontRequest $request) {
$viewer = $request->getUser();
$user = $this->getUser();
$token = id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession(
$viewer,
$request,
$this->getPanelURI());
$factor = id(new PhabricatorAuthFactorConfig())->loadOneWhere(
'id = %d AND userPHID = %s',
$request->getInt('delete'),
$user->getPHID());
if (!$factor) {
return new Aphront404Response();
}
if ($request->isFormPost()) {
$factor->delete();
$log = PhabricatorUserLog::initializeNewLog(
$viewer,
$user->getPHID(),
PhabricatorUserLog::ACTION_MULTI_REMOVE);
$log->save();
return id(new AphrontRedirectResponse())
->setURI($this->getPanelURI());
}
$dialog = id(new AphrontDialogView())
->setUser($viewer)
->addHiddenInput('delete', $factor->getID())
->setTitle(pht('Delete Authentication Factor'))
->appendParagraph(
pht(
'Really remove the authentication factor %s from your account?',
phutil_tag('strong', array(), $factor->getFactorName())))
->addSubmitButton(pht('Remove Factor'))
->addCancelButton($this->getPanelURI());
return id(new AphrontDialogResponse())
->setDialog($dialog);
}
}
diff --git a/src/docs/user/userguide/multi_factor_auth.diviner b/src/docs/user/userguide/multi_factor_auth.diviner
new file mode 100644
index 0000000000..c17c80d296
--- /dev/null
+++ b/src/docs/user/userguide/multi_factor_auth.diviner
@@ -0,0 +1,134 @@
+@title User Guide: Multi-Factor Authentication
+@group userguide
+
+Explains how multi-factor authentication works in Phabricator.
+
+Overview
+========
+
+Multi-factor authentication allows you to add additional credentials to your
+account to make it more secure.
+
+This sounds complicated, but in most cases it just means that Phabricator will
+make sure you have your mobile phone (by sending you a text message or having
+you enter a code from a mobile application) before allowing you to log in or
+take certain "high security" actions (like changing your password).
+
+Requiring you to prove you're really you by asking for something you know (your
+password) //and// something you have (your mobile phone) makes it much harder
+for attackers to access your account. The phone is an additional "factor" which
+protects your account from attacks.
+
+Requiring re-authentication before performing high security actions further
+limits the damage an attacker can do even if they manage to compromise a
+login session.
+
+
+How Multi-Factor Authentication Works
+=====================================
+
+If you've configured multi-factor authentication and try to log in to your
+account or take certain high security actions (like changing your password),
+you'll be stopped and asked to enter additional credentials.
+
+Usually, this means you'll receive an SMS with a security code on your phone, or
+you'll open an app on your phone which will show you a security code.
+In both cases, you'll enter the security code into Phabricator.
+
+If you're logging in, Phabricator will log you in after you enter the code.
+
+If you're taking a high security action, Phabricator will put your account in
+"high security" mode for a few minutes. In this mode, you can take high security
+actions like changing passwords or SSH keys freely without entering any more
+credentials. You can explicitly leave high security once you're done performing
+account management, or your account will naturally return to normal security
+after a short period of time.
+
+While your account is in high security, you'll see a notification on screen
+with instructions for returning to normal security.
+
+
+Configuring Multi-Factor Authentication
+=======================================
+
+To manage authentication factors for your account, go to
+Settings > Multi-Factor Auth. You can use this control panel to add or remove
+authentication factors from your account.
+
+You can also rename a factor by clicking the name. This can help you identify
+factors if you have several similar factors attached to your account.
+
+For a description of the available factors, see the next few sections.
+
+
+Factor: Mobile Phone App (TOTP)
+===============================
+
+TOTP stands for "Time-based One-Time Password". This factor operates by having
+you enter security codes from your mobile phone into Phabricator. The codes
+change every 30 seconds, so you will need to have your phone with you in order
+to enter them.
+
+To use this factor, you'll download an application onto your smartphone which
+can compute these codes. Two applications which work well are **Authy** and
+**Google Authenticator**. These applications are free, and you can find and
+download them from the appropriate store on your device.
+
+Your company may have a preferred application, or may use some other
+application, so check any in-house documentation for details. In general, any
+TOTP application should work properly.
+
+After you've downloaded the application onto your phone, use the Phabricator
+settings panel to add a factor to your account. You'll be prompted to enter a
+master key into your phone, and then read a security code from your phone and
+type it into Phabricator.
+
+Later, when you need to authenticate, you'll follow this same process: launch
+the application, read the security code, and type it into Phabricator. This will
+prove you have your phone.
+
+Don't lose your phone! You'll need it to log into Phabricator in the future.
+
+
+Recovering from Lost Factors
+============================
+
+If you've lost a factor associated with your account (for example, your phone
+has been lost or damaged), an administrator can strip the factor off your
+account so that you can log in without it.
+
+IMPORTANT: Before stripping factors from a user account, be absolutely certain
+that the user is who they claim to be!
+
+It is important to verify the user is who they claim they are before stripping
+factors because an attacker might pretend to be a user who has lost their phone
+in order to bypass multi-factor authentication. It is much easier for a typical
+attacker to spoof an email with a sad story in it than it is for a typical
+attacker to gain access to a mobile phone.
+
+A good way to verify user identity is to meet them in person and have them
+solemnly swear an oath that they lost their phone and are very sorry and
+definitely won't do it again. You can also work out a secret handshake in
+advance and require them to perform it. But no matter what you do, be certain
+the user (not an attacker //pretending// to be the user) is really the one
+making the request before stripping factors.
+
+After verifying identity, administrators can strip authentication factors from
+user accounts using the `bin/auth strip` command. For example, to strip all
+factors from the account of a user who has lost their phone, run this command:
+
+```lang=console
+# Strip all factors from a given user account.
+phabricator/ $ ./bin/auth strip --user <username> --all-types
+```
+
+You can run `bin/auth help strip` for more detail and all available flags and
+arguments.
+
+This command can selectively strip types of factors. You can use
+`bin/auth list-factors` for a list of available factor types.
+
+```lang=console
+# Show supported factor types.
+phabricator/ $ ./bin/auth list-factors
+```
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 19, 16:41 (2 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1126577
Default Alt Text
(14 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment