MDL-21912 restore: Add admin setting to restore conflicting admin user

This commit is contained in:
Cameron Ball 2016-01-11 14:08:58 +08:00
parent e65dfd9f28
commit 088d6086d8
4 changed files with 40 additions and 5 deletions

View File

@ -205,6 +205,9 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
// 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.

View File

@ -1287,7 +1287,11 @@ abstract class restore_dbops {
* 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
@ -1305,7 +1309,7 @@ abstract class restore_dbops {
* 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
@ -1376,7 +1380,7 @@ abstract class restore_dbops {
// 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
@ -1393,6 +1397,14 @@ abstract class restore_dbops {
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()
@ -1500,6 +1512,9 @@ abstract class restore_dbops {
// 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
@ -1535,14 +1550,28 @@ abstract class restore_dbops {
}
// 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

View File

@ -153,6 +153,8 @@ $string['hidetypes'] = 'Hide type options';
$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';

View File

@ -1555,6 +1555,7 @@ $string['restorecancelled'] = 'Restore cancelled';
$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';