1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-19 13:22:42 +01:00

Allow users to terminate login sessions

Summary:
This is partly a good feature, and partly should reduce false positives on HackerOne reporting things vaguely related to this.

Allow a user to terminate login sessions from the settings panel.

Test Plan:
  - Terminated a session.
  - Terminated all sessions.
  - Tried to terminate all sessions again.
  - Logged in with two browsers, terminated the other browser's session, reloaded, got kicked out.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Differential Revision: https://secure.phabricator.com/D8556
This commit is contained in:
epriestley 2014-03-17 15:02:01 -07:00
parent 38cc38eaf6
commit aea624118b
5 changed files with 131 additions and 3 deletions

View file

@ -1226,6 +1226,7 @@ phutil_register_library_map(array(
'PhabricatorAuthSessionGarbageCollector' => 'applications/auth/garbagecollector/PhabricatorAuthSessionGarbageCollector.php', 'PhabricatorAuthSessionGarbageCollector' => 'applications/auth/garbagecollector/PhabricatorAuthSessionGarbageCollector.php',
'PhabricatorAuthSessionQuery' => 'applications/auth/query/PhabricatorAuthSessionQuery.php', 'PhabricatorAuthSessionQuery' => 'applications/auth/query/PhabricatorAuthSessionQuery.php',
'PhabricatorAuthStartController' => 'applications/auth/controller/PhabricatorAuthStartController.php', 'PhabricatorAuthStartController' => 'applications/auth/controller/PhabricatorAuthStartController.php',
'PhabricatorAuthTerminateSessionController' => 'applications/auth/controller/PhabricatorAuthTerminateSessionController.php',
'PhabricatorAuthUnlinkController' => 'applications/auth/controller/PhabricatorAuthUnlinkController.php', 'PhabricatorAuthUnlinkController' => 'applications/auth/controller/PhabricatorAuthUnlinkController.php',
'PhabricatorAuthValidateController' => 'applications/auth/controller/PhabricatorAuthValidateController.php', 'PhabricatorAuthValidateController' => 'applications/auth/controller/PhabricatorAuthValidateController.php',
'PhabricatorAuthenticationConfigOptions' => 'applications/config/option/PhabricatorAuthenticationConfigOptions.php', 'PhabricatorAuthenticationConfigOptions' => 'applications/config/option/PhabricatorAuthenticationConfigOptions.php',
@ -3910,6 +3911,7 @@ phutil_register_library_map(array(
'PhabricatorAuthSessionGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorAuthSessionGarbageCollector' => 'PhabricatorGarbageCollector',
'PhabricatorAuthSessionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorAuthSessionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorAuthStartController' => 'PhabricatorAuthController', 'PhabricatorAuthStartController' => 'PhabricatorAuthController',
'PhabricatorAuthTerminateSessionController' => 'PhabricatorAuthController',
'PhabricatorAuthUnlinkController' => 'PhabricatorAuthController', 'PhabricatorAuthUnlinkController' => 'PhabricatorAuthController',
'PhabricatorAuthValidateController' => 'PhabricatorAuthController', 'PhabricatorAuthValidateController' => 'PhabricatorAuthController',
'PhabricatorAuthenticationConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorAuthenticationConfigOptions' => 'PhabricatorApplicationConfigOptions',

View file

@ -86,6 +86,8 @@ final class PhabricatorApplicationAuth extends PhabricatorApplication {
=> 'PhabricatorAuthLinkController', => 'PhabricatorAuthLinkController',
'confirmlink/(?P<akey>[^/]+)/' 'confirmlink/(?P<akey>[^/]+)/'
=> 'PhabricatorAuthConfirmLinkController', => 'PhabricatorAuthConfirmLinkController',
'session/terminate/(?P<id>[^/]+)/'
=> 'PhabricatorAuthTerminateSessionController',
), ),
'/oauth/(?P<provider>\w+)/login/' '/oauth/(?P<provider>\w+)/login/'

View file

@ -0,0 +1,83 @@
<?php
final class PhabricatorAuthTerminateSessionController
extends PhabricatorAuthController {
private $id;
public function willProcessRequest(array $data) {
$this->id = $data['id'];
}
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
$is_all = ($this->id === 'all');
$query = id(new PhabricatorAuthSessionQuery())
->setViewer($viewer)
->withIdentityPHIDs(array($viewer->getPHID()));
if (!$is_all) {
$query->withIDs(array($this->id));
}
$current_key = PhabricatorHash::digest(
$request->getCookie(PhabricatorCookies::COOKIE_SESSION));
$sessions = $query->execute();
foreach ($sessions as $key => $session) {
if ($session->getSessionKey() == $current_key) {
// Don't terminate the current login session.
unset($sessions[$key]);
}
}
$panel_uri = '/settings/panel/sessions/';
if (!$sessions) {
$dialog = id(new AphrontDialogView())
->setUser($viewer)
->setTitle(pht('No Matching Sessions'))
->appendParagraph(
pht('There are no matching sessions to terminate.'))
->appendParagraph(
pht(
'(You can not terminate your current login session. To '.
'terminate it, log out.)'))
->addCancelButton($panel_uri);
return id(new AphrontDialogResponse())->setDialog($dialog);
}
if ($request->isDialogFormPost()) {
foreach ($sessions as $session) {
$session->delete();
}
return id(new AphrontRedirectResponse())->setURI($panel_uri);
}
if ($is_all) {
$title = pht('Terminate Sessions?');
$body = pht(
'Really terminate all sessions? (Your current login session will '.
'not be terminated.)');
} else {
$title = pht('Terminate Session?');
$body = pht(
'Really terminate session %s?',
phutil_tag('strong', array(), substr($session->getSessionKey(), 0, 6)));
}
$dialog = id(new AphrontDialogView())
->setUser($viewer)
->setTitle($title)
->appendParagraph($body)
->addSubmitButton(pht('Terminate'))
->addCancelButton($panel_uri);
return id(new AphrontDialogResponse())->setDialog($dialog);
}
}

View file

@ -3,6 +3,7 @@
final class PhabricatorAuthSessionQuery final class PhabricatorAuthSessionQuery
extends PhabricatorCursorPagedPolicyAwareQuery { extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $identityPHIDs; private $identityPHIDs;
private $sessionKeys; private $sessionKeys;
private $sessionTypes; private $sessionTypes;
@ -22,6 +23,11 @@ final class PhabricatorAuthSessionQuery
return $this; return $this;
} }
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
protected function loadPage() { protected function loadPage() {
$table = new PhabricatorAuthSession(); $table = new PhabricatorAuthSession();
$conn_r = $table->establishConnection('r'); $conn_r = $table->establishConnection('r');
@ -62,6 +68,13 @@ final class PhabricatorAuthSessionQuery
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
$where = array(); $where = array();
if ($this->ids) {
$where[] = qsprintf(
$conn_r,
'id IN (%Ld)',
$this->ids);
}
if ($this->identityPHIDs) { if ($this->identityPHIDs) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn_r,

View file

@ -48,16 +48,31 @@ final class PhabricatorSettingsPanelSessions
foreach ($sessions as $session) { foreach ($sessions as $session) {
if ($session->getSessionKey() == $current_key) { if ($session->getSessionKey() == $current_key) {
$rowc[] = 'highlighted'; $rowc[] = 'highlighted';
$button = phutil_tag(
'a',
array(
'class' => 'small grey button disabled',
),
pht('Current'));
} else { } else {
$rowc[] = null; $rowc[] = null;
$button = javelin_tag(
'a',
array(
'href' => '/auth/session/terminate/'.$session->getID().'/',
'class' => 'small grey button',
'sigil' => 'workflow',
),
pht('Terminate'));
} }
$rows[] = array( $rows[] = array(
$handles[$session->getUserPHID()]->renderLink(), $handles[$session->getUserPHID()]->renderLink(),
substr($session->getSessionKey(), 0, 12), substr($session->getSessionKey(), 0, 6),
$session->getType(), $session->getType(),
phabricator_datetime($session->getSessionStart(), $viewer), phabricator_datetime($session->getSessionStart(), $viewer),
phabricator_datetime($session->getSessionExpires(), $viewer), phabricator_date($session->getSessionExpires(), $viewer),
$button,
); );
} }
@ -71,6 +86,7 @@ final class PhabricatorSettingsPanelSessions
pht('Type'), pht('Type'),
pht('Created'), pht('Created'),
pht('Expires'), pht('Expires'),
pht(''),
)); ));
$table->setColumnClasses( $table->setColumnClasses(
array( array(
@ -79,11 +95,23 @@ final class PhabricatorSettingsPanelSessions
'', '',
'right', 'right',
'right', 'right',
'action',
)); ));
$terminate_icon = id(new PHUIIconView())
->setSpriteSheet(PHUIIconView::SPRITE_ICONS)
->setSpriteIcon('warning');
$terminate_button = id(new PHUIButtonView())
->setText(pht('Terminate All Sessions'))
->setHref('/auth/session/terminate/all/')
->setTag('a')
->setWorkflow(true)
->setIcon($terminate_icon);
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader(pht('Active Login Sessions')); ->setHeader(pht('Active Login Sessions'))
->addActionLink($terminate_button);
$panel = id(new PHUIObjectBoxView()) $panel = id(new PHUIObjectBoxView())
->setHeader($header) ->setHeader($header)