Page MenuHomePhorge

No OneTemporary

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

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)

Event Timeline