MDL-56310 restore: Confirm user has permission to change capabilities
authorPeter Dias <peter@moodle.com>
Wed, 9 Sep 2020 05:50:21 +0000 (13:50 +0800)
committerJenkins <jenkins@worker14.test.in.moodle.com>
Tue, 3 Nov 2020 11:34:28 +0000 (12:34 +0100)
backup/moodle2/restore_stepslib.php

index 69fcf19..67abb20 100644 (file)
@@ -2121,14 +2121,29 @@ class restore_ras_and_caps_structure_step extends restore_structure_step {
         $data = (object)$data;
 
         // Check roleid is one of the mapped ones
-        $newroleid = $this->get_mappingid('role', $data->roleid);
+        $newrole = $this->get_mapping('role', $data->roleid);
+        $newroleid = $newrole->newitemid ?? false;
+        $userid = $this->task->get_userid();
+
         // If newroleid and context are valid assign it via API (it handles dupes and so on)
         if ($newroleid && $this->task->get_contextid()) {
-            if (!get_capability_info($data->capability)) {
+            if (!$capability = get_capability_info($data->capability)) {
                 $this->log("Capability '{$data->capability}' was not found!", backup::LOG_WARNING);
             } else {
-                // TODO: assign_capability() needs one userid param to be able to specify our restore userid.
-                assign_capability($data->capability, $data->permission, $newroleid, $this->task->get_contextid());
+                $context = context::instance_by_id($this->task->get_contextid());
+                $overrideableroles = get_overridable_roles($context, ROLENAME_SHORT);
+                $safecapability = is_safe_capability($capability);
+
+                // Check if the new role is an overrideable role AND if the user performing the restore has the
+                // capability to assign the capability.
+                if (in_array($newrole->info['shortname'], $overrideableroles) &&
+                    ($safecapability && has_capability('moodle/role:safeoverride', $context, $userid) ||
+                        !$safecapability && has_capability('moodle/role:override', $context, $userid))
+                ) {
+                    assign_capability($data->capability, $data->permission, $newroleid, $this->task->get_contextid());
+                } else {
+                    $this->log("Insufficient capability to assign capability '{$data->capability}' to role!", backup::LOG_WARNING);
+                }
             }
         }
     }