1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-23 14:00:56 +01:00

Let users review their own account activity logs

Summary:
Ref T4398. This adds a settings panel for account activity so users can review activity on their own account. Some goals are:

  - Make it easier for us to develop and support auth and credential information, see T4398. This is the primary driver.
  - Make it easier for users to understand and review auth and credential information (see T4842 for an example -- this isn't there yet, but builds toward it).
  - Improve user confidence in security by making logging more apparent and accessible.

Minor corresponding changes:

  - Entering and exiting hisec mode is now logged.
  - This, sessions, and OAuth authorizations have moved to a new "Sessions and Logs" area, since "Authentication" was getting huge.

Test Plan:
  - Viewed new panel.
  - Viewed old UI.
  - Entered/exited hisec and got prompted.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T4398

Differential Revision: https://secure.phabricator.com/D8871
This commit is contained in:
epriestley 2014-04-27 17:32:09 -07:00
parent 320be1a1b8
commit 3f5a55fa6e
10 changed files with 195 additions and 65 deletions

View file

@ -2055,6 +2055,7 @@ phutil_register_library_map(array(
'PhabricatorSettingsMainController' => 'applications/settings/controller/PhabricatorSettingsMainController.php',
'PhabricatorSettingsPanel' => 'applications/settings/panel/PhabricatorSettingsPanel.php',
'PhabricatorSettingsPanelAccount' => 'applications/settings/panel/PhabricatorSettingsPanelAccount.php',
'PhabricatorSettingsPanelActivity' => 'applications/settings/panel/PhabricatorSettingsPanelActivity.php',
'PhabricatorSettingsPanelConduit' => 'applications/settings/panel/PhabricatorSettingsPanelConduit.php',
'PhabricatorSettingsPanelConpherencePreferences' => 'applications/settings/panel/PhabricatorSettingsPanelConpherencePreferences.php',
'PhabricatorSettingsPanelDeveloperPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelDeveloperPreferences.php',
@ -2221,6 +2222,7 @@ phutil_register_library_map(array(
'PhabricatorUserEmail' => 'applications/people/storage/PhabricatorUserEmail.php',
'PhabricatorUserEmailTestCase' => 'applications/people/storage/__tests__/PhabricatorUserEmailTestCase.php',
'PhabricatorUserLog' => 'applications/people/storage/PhabricatorUserLog.php',
'PhabricatorUserLogView' => 'applications/people/view/PhabricatorUserLogView.php',
'PhabricatorUserPreferences' => 'applications/settings/storage/PhabricatorUserPreferences.php',
'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php',
'PhabricatorUserProfileEditor' => 'applications/people/editor/PhabricatorUserProfileEditor.php',
@ -4950,6 +4952,7 @@ phutil_register_library_map(array(
'PhabricatorSettingsAdjustController' => 'PhabricatorController',
'PhabricatorSettingsMainController' => 'PhabricatorController',
'PhabricatorSettingsPanelAccount' => 'PhabricatorSettingsPanel',
'PhabricatorSettingsPanelActivity' => 'PhabricatorSettingsPanel',
'PhabricatorSettingsPanelConduit' => 'PhabricatorSettingsPanel',
'PhabricatorSettingsPanelConpherencePreferences' => 'PhabricatorSettingsPanel',
'PhabricatorSettingsPanelDeveloperPreferences' => 'PhabricatorSettingsPanel',
@ -5131,6 +5134,7 @@ phutil_register_library_map(array(
0 => 'PhabricatorUserDAO',
1 => 'PhabricatorPolicyInterface',
),
'PhabricatorUserLogView' => 'AphrontView',
'PhabricatorUserPreferences' => 'PhabricatorUserDAO',
'PhabricatorUserProfile' => 'PhabricatorUserDAO',
'PhabricatorUserProfileEditor' => 'PhabricatorApplicationTransactionEditor',

View file

@ -20,11 +20,8 @@ final class PhabricatorAuthDowngradeSessionController
if ($request->isFormPost()) {
queryfx(
$session->establishConnection('w'),
'UPDATE %T SET highSecurityUntil = NULL WHERE id = %d',
$session->getTableName(),
$session->getID());
id(new PhabricatorAuthSessionEngine())
->exitHighSecurity($viewer, $session);
return id(new AphrontRedirectResponse())
->setURI($this->getApplicationURI('session/downgrade/'));

View file

@ -249,6 +249,12 @@ final class PhabricatorAuthSessionEngine extends Phobject {
$session->getTableName(),
$until,
$session->getID());
$log = PhabricatorUserLog::initializeNewLog(
$viewer,
$viewer->getPHID(),
PhabricatorUserLog::ACTION_ENTER_HISEC);
$log->save();
}
}
@ -302,4 +308,21 @@ final class PhabricatorAuthSessionEngine extends Phobject {
}
public function exitHighSecurity(
PhabricatorUser $viewer,
PhabricatorAuthSession $session) {
queryfx(
$session->establishConnection('w'),
'UPDATE %T SET highSecurityUntil = NULL WHERE id = %d',
$session->getTableName(),
$session->getID());
$log = PhabricatorUserLog::initializeNewLog(
$viewer,
$viewer->getPHID(),
PhabricatorUserLog::ACTION_EXIT_HISEC);
$log->save();
}
}

View file

@ -12,7 +12,7 @@ final class PhabricatorOAuthServerAuthorizationsSettingsPanel
}
public function getPanelGroup() {
return pht('Authentication');
return pht('Sessions and Logs');
}
public function isEnabled() {

View file

@ -35,64 +35,11 @@ final class PhabricatorPeopleLogsController extends PhabricatorPeopleController
$phids = array_keys($phids);
$handles = $this->loadViewerHandles($phids);
$action_map = PhabricatorUserLog::getActionTypeMap();
$rows = array();
foreach ($logs as $log) {
$ip_href = $this->getApplicationURI(
'logs/?ip='.$log->getRemoteAddr());
$session_href = $this->getApplicationURI(
'logs/?sessions='.$log->getSession());
$action = $log->getAction();
$action_name = idx($action_map, $action, $action);
$rows[] = array(
phabricator_date($log->getDateCreated(), $viewer),
phabricator_time($log->getDateCreated(), $viewer),
$action_name,
$log->getActorPHID()
? $handles[$log->getActorPHID()]->getName()
: null,
$handles[$log->getUserPHID()]->getName(),
phutil_tag(
'a',
array(
'href' => $ip_href,
),
$log->getRemoteAddr()),
phutil_tag(
'a',
array(
'href' => $session_href,
),
substr($log->getSession(), 0, 6)),
);
}
$table = new AphrontTableView($rows);
$table->setHeaders(
array(
pht('Date'),
pht('Time'),
pht('Action'),
pht('Actor'),
pht('User'),
pht('IP'),
pht('Session'),
));
$table->setColumnClasses(
array(
'',
'right',
'wide',
'',
'',
'',
'n',
));
$table = id(new PhabricatorUserLogView())
->setUser($viewer)
->setLogs($logs)
->setSearchBaseURI($this->getApplicationURI('logs/'))
->setHandles($handles);
return id(new PHUIObjectBoxView())
->setHeaderText(pht('User Activity Logs'))

View file

@ -76,6 +76,7 @@ final class PhabricatorPeopleLogQuery
$where[] = qsprintf(
$conn_r,
'actorPHID IN (%Ls) OR userPHID IN (%Ls)',
$this->relatedPHIDs,
$this->relatedPHIDs);
}

View file

@ -27,6 +27,9 @@ final class PhabricatorUserLog extends PhabricatorUserDAO
const ACTION_CHANGE_PASSWORD = 'change-password';
const ACTION_CHANGE_USERNAME = 'change-username';
const ACTION_ENTER_HISEC = 'hisec-enter';
const ACTION_EXIT_HISEC = 'hisec-exit';
protected $actorPHID;
protected $userPHID;
protected $action;
@ -58,6 +61,8 @@ final class PhabricatorUserLog extends PhabricatorUserDAO
self::ACTION_EMAIL_REMOVE => pht('Email: Remove Address'),
self::ACTION_CHANGE_PASSWORD => pht('Change Password'),
self::ACTION_CHANGE_USERNAME => pht('Change Username'),
self::ACTION_ENTER_HISEC => pht('Hisec: Enter'),
self::ACTION_EXIT_HISEC => pht('Hisec: Exit'),
);
}

View file

@ -0,0 +1,95 @@
<?php
final class PhabricatorUserLogView extends AphrontView {
private $logs;
private $handles;
private $searchBaseURI;
public function setSearchBaseURI($search_base_uri) {
$this->searchBaseURI = $search_base_uri;
return $this;
}
public function setLogs(array $logs) {
assert_instances_of($logs, 'PhabricatorUserLog');
$this->logs = $logs;
return $this;
}
public function setHandles(array $handles) {
assert_instances_of($handles, 'PhabricatorObjectHandle');
$this->handles = $handles;
return $this;
}
public function render() {
$logs = $this->logs;
$handles = $this->handles;
$viewer = $this->getUser();
$action_map = PhabricatorUserLog::getActionTypeMap();
$base_uri = $this->searchBaseURI;
$rows = array();
foreach ($logs as $log) {
$ip = $log->getRemoteAddr();
$session = substr($log->getSession(), 0, 6);
if ($base_uri) {
$ip = phutil_tag(
'a',
array(
'href' => $base_uri.'?ip='.$log->getRemoteAddr().'#R',
),
$ip);
$session = phutil_tag(
'a',
array(
'href' => $base_uri.'?sessions='.$log->getSession().'#R',
),
$session);
}
$action = $log->getAction();
$action_name = idx($action_map, $action, $action);
$rows[] = array(
phabricator_date($log->getDateCreated(), $viewer),
phabricator_time($log->getDateCreated(), $viewer),
$action_name,
$log->getActorPHID()
? $handles[$log->getActorPHID()]->getName()
: null,
$handles[$log->getUserPHID()]->getName(),
$ip,
$session,
);
}
$table = new AphrontTableView($rows);
$table->setHeaders(
array(
pht('Date'),
pht('Time'),
pht('Action'),
pht('Actor'),
pht('User'),
pht('IP'),
pht('Session'),
));
$table->setColumnClasses(
array(
'',
'right',
'wide',
'',
'',
'',
'n',
));
return $table;
}
}

View file

@ -0,0 +1,58 @@
<?php
final class PhabricatorSettingsPanelActivity
extends PhabricatorSettingsPanel {
public function getPanelKey() {
return 'activity';
}
public function getPanelName() {
return pht('Activity Logs');
}
public function getPanelGroup() {
return pht('Sessions and Logs');
}
public function isEnabled() {
return true;
}
public function processRequest(AphrontRequest $request) {
$viewer = $request->getUser();
$user = $this->getUser();
$logs = id(new PhabricatorPeopleLogQuery())
->setViewer($viewer)
->withRelatedPHIDs(array($user->getPHID()))
->execute();
$phids = array();
foreach ($logs as $log) {
$phids[] = $log->getUserPHID();
$phids[] = $log->getActorPHID();
}
if ($phids) {
$handles = id(new PhabricatorHandleQuery())
->setViewer($viewer)
->withPHIDs($phids)
->execute();
} else {
$handles = array();
}
$table = id(new PhabricatorUserLogView())
->setUser($viewer)
->setLogs($logs)
->setHandles($handles);
$panel = id(new PHUIObjectBoxView())
->setHeaderText(pht('Account Activity Logs'))
->appendChild($table);
return $panel;
}
}

View file

@ -12,7 +12,7 @@ final class PhabricatorSettingsPanelSessions
}
public function getPanelGroup() {
return pht('Authentication');
return pht('Sessions and Logs');
}
public function isEnabled() {