Skip to content

Commit

Permalink
MDL-21912 restore: Add admin setting to restore conflicting admin user
Browse files Browse the repository at this point in the history
  • Loading branch information
cameorn1730 committed Jan 11, 2016
1 parent 2a416b3 commit 4a5fb82
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 5 deletions.
3 changes: 3 additions & 0 deletions admin/settings/courses.php
Expand Up @@ -205,6 +205,9 @@
// Create a page for general import configuration and defaults.
$temp = new admin_settingpage('importgeneralsettings', new lang_string('importgeneralsettings', 'backup'), 'moodle/backup:backupcourse');
$temp->add(new admin_setting_configtext('backup/import_general_maxresults', new lang_string('importgeneralmaxresults', 'backup'), new lang_string('importgeneralmaxresults_desc', 'backup'), 10));
$temp->add(new admin_setting_configcheckbox('backup/import_general_duplicate_admin_allowed',
new lang_string('importgeneralduplicateadminallowed', 'backup'),
new lang_string('importgeneralduplicateadminallowed_desc', 'backup'), 0));
$ADMIN->add('backups', $temp);

// Create a page for automated backups configuration and defaults.
Expand Down
39 changes: 34 additions & 5 deletions backup/util/dbops/restore_dbops.class.php
Expand Up @@ -1287,7 +1287,11 @@ public static function create_included_users($basepath, $restoreid, $userid,
* 1F - None of the above, return true => User needs to be created
*
* if restoring from another site backup (cannot match by id here, replace it by email/firstaccess combination):
* 2A - Normal check: If match by username and mnethost and (email or non-zero firstaccess) => ok, return target user
* 2A - Normal check:
* 2A1 - If match by username and mnethost and (email or non-zero firstaccess) => ok, return target user
* 2A2 - Exceptional handling (MDL-21912): Match "admin" username. Then, if import_general_duplicate_admin_allowed is
* enabled, attempt to map the admin user to the user 'admin_[oldsiteid]' if it exists. If not,
* the user 'admin_[oldsiteid]' will be created in precheck_included users
* 2B - Handle users deleted in DB and "alive" in backup file:
* 2B1 - If match by mnethost and user is deleted in DB and not empty email = md5(username) and
* (username LIKE 'backup_email.%' or non-zero firstaccess) => ok, return target user
Expand All @@ -1305,7 +1309,7 @@ public static function create_included_users($basepath, $restoreid, $userid,
* Note: for DB deleted users md5(username) is stored *sometimes* in the email field,
* hence we are looking there for usernames if not empty. See delete_user()
*/
protected static function precheck_user($user, $samesite) {
protected static function precheck_user($user, $samesite, $siteid = null) {
global $CFG, $DB;

// Handle checks from same site backups
Expand Down Expand Up @@ -1376,7 +1380,7 @@ protected static function precheck_user($user, $samesite) {
// Handle checks from different site backups
} else {

// 2A - If match by username and mnethost and
// 2A1 - If match by username and mnethost and
// (email or non-zero firstaccess) => ok, return target user
if ($rec = $DB->get_record_sql("SELECT *
FROM {user} u
Expand All @@ -1393,6 +1397,14 @@ protected static function precheck_user($user, $samesite) {
return $rec; // Matching user found, return it
}

// 2A2 - If we're allowing conflicting admins, attempt to map user to admin_[oldsiteid].
if (get_config('backup', 'import_general_duplicate_admin_allowed') && $user->username === 'admin' && $siteid
&& $user->mnethostid == $CFG->mnet_localhost_id) {
if ($rec = $DB->get_record('user', array('username' => 'admin_' . $siteid))) {
return $rec;
}
}

// 2B - Handle users deleted in DB and "alive" in backup file
// Note: for DB deleted users email is stored in username field, hence we
// are looking there for emails. See delete_user()
Expand Down Expand Up @@ -1500,6 +1512,9 @@ public static function precheck_included_users($restoreid, $courseid, $userid, $
// Calculate the context we are going to use for capability checking
$context = context_course::instance($courseid);

// When conflicting users are detected we may need original site info.
$restoreinfo = restore_controller_dbops::load_controller($restoreid)->get_info();

// Calculate if we have perms to create users, by checking:
// to 'moodle/restore:createuser' and 'moodle/restore:userinfo'
// and also observe $CFG->disableusercreationonrestore
Expand Down Expand Up @@ -1535,14 +1550,28 @@ public static function precheck_included_users($restoreid, $courseid, $userid, $
}

// Now, precheck that user and, based on returned results, annotate action/problem
$usercheck = self::precheck_user($user, $samesite);
$usercheck = self::precheck_user($user, $samesite, $restoreinfo->original_site_identifier_hash);

if (is_object($usercheck)) { // No problem, we have found one user in DB to be mapped to
// Annotate it, for later process. Set newitemid to mapping user->id
self::set_backup_ids_record($restoreid, 'user', $recuser->itemid, $usercheck->id);

} else if ($usercheck === false) { // Found conflict, report it as problem
$problems[] = get_string('restoreuserconflict', '', $user->username);
if (!get_config('backup', 'import_general_duplicate_admin_allowed')) {
$problems[] = get_string('restoreuserconflict', '', $user->username);
} else if ($user->username == 'admin') {
if (!$cancreateuser) {
$problems[] = get_string('restorecannotcreateuser', '', $user->username);
}
if ($user->mnethostid != $CFG->mnet_localhost_id) {
$problems[] = get_string('restoremnethostidmismatch', '', $user->username);
}
if (!$problems) {
// Duplicate admin allowed, append original site idenfitier to username.
$user->username .= '_' . $restoreinfo->original_site_identifier_hash;
self::set_backup_ids_record($restoreid, 'user', $recuser->itemid, 0, null, (array)$user);
}
}

} else if ($usercheck === true) { // User needs to be created, check if we are able
if ($cancreateuser) { // Can create user, set newitemid to 0 so will be created later
Expand Down
2 changes: 2 additions & 0 deletions lang/en/backup.php
Expand Up @@ -148,6 +148,8 @@
$string['importgeneralsettings'] = 'General import defaults';
$string['importgeneralmaxresults'] = 'Maximum number of courses listed for import';
$string['importgeneralmaxresults_desc'] = 'This controls the number of courses that are listed during the first step of the import process';
$string['importgeneralduplicateadminallowed'] = 'Allow admin conflict resolution';
$string['importgeneralduplicateadminallowed_desc'] = 'If the site has an account with username \'admin\', then attempting to restore a backup file containing an account with username \'admin\' can cause a conflict. If this setting is enabled, the conflict will be resolved by changing the username in the backup file to \'admin_xyz\'.';
$string['importfile'] = 'Import a backup file';
$string['importbackupstage1action'] = 'Next';
$string['importbackupstage2action'] = 'Next';
Expand Down
1 change: 1 addition & 0 deletions lang/en/moodle.php
Expand Up @@ -1551,6 +1551,7 @@
$string['restorecannotassignroles'] = 'Restore needs to assign roles and you do not have permission to do so';
$string['restorecannotcreateorassignroles'] = 'Restore needs to create or assign roles and you do not have permission to do so';
$string['restorecannotcreateuser'] = 'Restore needs to create user \'{$a}\' from backup file and you do not have permission to do so';
$string['restoremnethostidmismatch'] = 'MNet host id of user \'{$a}\' does not match local MNet host ID.';
$string['restorecannotoverrideperms'] = 'Restore needs to override permissions and you do not have permission to do so';
$string['restorecoursenow'] = 'Restore this course now!';
$string['restoredaccount'] = 'Restored account';
Expand Down

0 comments on commit 4a5fb82

Please sign in to comment.