Commit 40517fde authored by Jiri Baum's avatar Jiri Baum
Browse files

Masquerading auditability - ask for reason, notify, emit event. (Bug #900983)



Masquerading (aka Loginas) is a useful and sometimes indispensable function.
However, previously it was rather too powerful, because admins can do anything
as the target user, with no indication that it is not the user themselves doing
so.

This feature adds some auditability to masquerading, by logging and reporting
who, when, why and (partially) what, as well as notifying the affected user.

See also bugs: #900983 and #1027574

This commit changes the masquerading feature itself to request a reason from
the admin masquerading, notify the user, and emit an event (for logging by the
next commit).

Change-Id: I066e9fdeb4d2e00679b2aa9b0b839cb4b78629a8
Signed-off-by: default avatarJiri Baum <jiri@catalyst-au.net>
parent 7f362262
......@@ -204,6 +204,20 @@ $siteoptionform = array(
'defaultvalue' => get_config('userscandisabledevicedetection'),
'disabled' => in_array('userscandisabledevicedetection', $OVERRIDDEN),
),
'masqueradingreasonrequired' => array(
'type' => 'checkbox',
'title' => get_string('masqueradingreasonrequired', 'admin'),
'description' => get_string('masqueradingreasonrequireddescription', 'admin'),
'defaultvalue' => get_config('masqueradingreasonrequired'),
'disabled' => in_array('masqueradingreasonrequired', $OVERRIDDEN),
),
'masqueradingnotified' => array(
'type' => 'checkbox',
'title' => get_string('masqueradingnotified', 'admin'),
'description' => get_string('masqueradingnotifieddescription', 'admin'),
'defaultvalue' => get_config('masqueradingnotified'),
'disabled' => in_array('masqueradingnotified', $OVERRIDDEN),
),
),
),
'searchsettings' => array(
......@@ -630,6 +644,7 @@ function siteoptions_submit(Pieform $form, $values) {
'noreplyaddress', 'defaultnotificationmethod', 'homepageinfo', 'showonlineuserssideblock', 'onlineuserssideblockmaxusers',
'registerterms', 'allowmobileuploads', 'creategroups', 'createpublicgroups', 'allowgroupcategories', 'wysiwyg',
'staffreports', 'staffstats', 'userscandisabledevicedetection',
'masqueradingreasonrequired', 'masqueradingnotified',
);
// if public views are disabled, sitemap generation must also be disabled.
......
......@@ -28,6 +28,7 @@
define('INTERNAL', 1);
define('NOCHECKPASSWORDCHANGE', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
require_once('activity.php');
if (param_integer('login_submitted', 0)) {
redirect(get_config('wwwroot'));
......@@ -38,6 +39,83 @@ if (param_integer('restore', 0)) {
redirect(get_config('wwwroot') . 'admin/users/edit.php?id=' . $id);
}
$id = param_integer('id');
$USER->change_identity_to($id); // Permissions checking is done in here
redirect(get_config('wwwroot'));
/**
* Notify user (if configured), do the masquerading and emit event. Called when
* no (further) interaction with the admin is needed before the loginas.
*
* @param string $why The masquerading reason (if given) or null.
*/
function do_masquerade($why = null) {
global $USER, $SESSION;
$id = param_integer('id');
$who = display_name($USER, $id);
$when = format_date(time());
if (get_config('masqueradingnotified')) {
$msg = (object) array(
'subject' => get_string('masqueradenotificationsubject', 'admin'),
'message' => $why === null ?
get_string('masqueradenotificationnoreason', 'admin',
$who, $when
) :
get_string('masqueradenotificationreason', 'admin',
$who, $when, $why
),
'users' => array($id),
'url' => profile_url($USER, false),
'urltext' => $who,
);
activity_occurred('maharamessage', $msg);
$SESSION->add_info_msg(get_string('masqueradenotificationdone', 'admin'));
}
$USER->change_identity_to($id); // Permissions checking is done in here
handle_event('loginas', array(
'who' => $who,
'when' => $when,
'reason' => $why,
));
redirect(get_config('wwwroot'));
}
if (!get_config('masqueradingreasonrequired')) {
do_masquerade();
}
require_once('pieforms/pieform.php');
$form = array(
'name' => 'masqueradereason',
'renderer' => 'table',
'plugintype' => 'core',
'pluginname' => 'core',
'elements' => array(
'reason' => array(
'type' => 'textarea',
'title' => get_string('masqueradereason', 'admin'),
'description' => (get_config('masqueradingnotified') ? get_string('masqueradenotifiedreasondescription', 'admin') : get_string('masqueradereasondescription', 'admin')),
'defaultvalue' => '',
'rows' => 3,
'cols' => 30,
'rules' => array(
'required' => true,
),
'help' => true,
),
'id' => array(
'type' => 'hidden',
'value' => param_integer('id'),
),
'submit' => array(
'type' => 'submit',
'value' => get_string('masquerade', 'admin')
),
),
);
$form = pieform($form);
function masqueradereason_submit(Pieform $form, $values) {
do_masquerade($values['reason']);
}
$smarty = smarty();
$smarty->assign('form', $form);
$smarty->display('admin/users/changeuser.tpl');
......@@ -1006,3 +1006,18 @@ $string['usershaveloggedinsince'] = 'Users have logged in since';
$string['usershavenotloggedinsince'] = 'Users have not logged in since';
$string['lastlogin'] = 'Last login';
// Masquerading reasons and notification
$string['masqueradingreasonrequired'] = 'Require reason for masquerading';
$string['masqueradingreasonrequireddescription'] = 'If checked, administrators will be required to enter a reason for masquerading as other users. This will be logged, and if the setting "Notify users of masquerading" is enabled, included in the notification to the user about the masquerading.';
$string['masqueradingnotified'] = 'Notify users of masquerading';
$string['masqueradingnotifieddescription'] = 'If checked, users will be notified when an administrator masqueraded as them. The notification will include who, when and - if enabled under "Require reason for masquerading" - why.';
$string['masquerade'] = 'Continue';
$string['masqueradereason'] = 'Reason';
$string['masqueradereasondescription'] = 'Please enter a reason for logging in as this user. Note: The user will not be notified of this reason, but it will be logged.';
$string['masqueradenotificationdone'] = 'The user has been notified of this masquerading session.';
$string['masqueradenotifiedreasondescription'] = 'Please enter a reason for logging in as this user. Note: The user will receive a message containing your name, the date and time as well as the reason for your masquerading.';
$string['masqueradenotificationsubject'] = 'An administrator logged in as you';
$string['masqueradenotificationnoreason'] = 'The administrator %s logged into your account on %s.';
$string['masqueradenotificationreason'] = 'The administrator %s logged into your account on %s. The reason was: %s';
<h3>Masquerading reason</h3>
<p>Explain why you are logging in as this user. This will be recorded for audit purposes, and the user may be notified depending on the site settings.</p>
......@@ -3130,5 +3130,12 @@ function xmldb_core_upgrade($oldversion=0) {
set_config('defaultregistrationexpirylifetime', 1209600);
}
if ($oldversion < 2013012100) {
$event = (object)array(
'name' => 'loginas',
);
ensure_record_exists('event_type', $event, $event);
}
return $status;
}
......@@ -812,6 +812,7 @@ function core_install_firstcoredata_defaults() {
'addfriendrequest',
'removefriendrequest',
'creategroup',
'loginas',
);
foreach ($eventtypes as $et) {
......
......@@ -30,7 +30,7 @@ defined('INTERNAL') || die();
$config = new StdClass;
// See https://wiki.mahara.org/index.php/Developer_Area/Version_Numbering_Policy
// For upgrades on stable branches, increment the version by one. On master, use the date.
$config->version = 2013011700;
$config->version = 2013012100;
$config->release = '1.7.0dev';
$config->minupgradefrom = 2008040200;
$config->minupgraderelease = '1.0.0 (release tag 1.0.0_RELEASE)';
......
{include file="header.tpl"}
{$form|safe}
{include file="footer.tpl"}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment