From 9fccc080039174378d5bff12ee4bcdc9b0dea476 Mon Sep 17 00:00:00 2001 From: toyomoyo Date: Wed, 25 Oct 2006 03:47:59 +0000 Subject: [PATCH] fix in load_user_capability() merged when 2 contexts in overrides are not related --- lib/accesslib.php | 126 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 109 insertions(+), 17 deletions(-) diff --git a/lib/accesslib.php b/lib/accesslib.php index fb45c6f56e2..b9b660d334a 100755 --- a/lib/accesslib.php +++ b/lib/accesslib.php @@ -518,6 +518,53 @@ function capability_search($capability, $context, $capabilities) { return $permission; } +// auxillary function for load_user_capabilities() +// if context c1 is a parent (or itself) of context c2 +// returns true +function is_parent_context($c1, $c2) { + static $parentsarray; + + // context can be itself and this is ok + if ($c1 == $c2) { + return true; + } + // hit in cache? + if (isset($parentsarray[$c1][$c2])) { + return $parentsarray[$c1][$c2]; + } + + if (!$co2 = get_record('context', 'id', $c2)) { + return false; + } + + if (!$parents = get_parent_contexts($co2)) { + return false; + } + + foreach ($parents as $parent) { + $parentsarray[$parent][$c2] = true; + } + + if (in_array($c1, $parents)) { + return true; + } else { // else not a parent, set the cache anyway + $parentsarray[$c1][$c2] = false; + return false; + } +} + + +/* + * auxillary function for load_user_capabilities() + * handler in usort() to sort contexts according to level + */ +function roles_context_cmp($contexta, $contextb) { + if ($contexta->contextlevel == $contextb->contextlevel) { + return 0; + } + return ($contexta->contextlevel < $contextb->contextlevel) ? -1 : 1; +} + /** * This function should be called immediately after a login, when $USER is set. @@ -604,8 +651,10 @@ function load_user_capability($capability='', $context ='', $userid='') { /// The second part gets the capabilities of overriden roles. $siteinstance = get_context_instance(CONTEXT_SYSTEM, SITEID); - - $SQL = " SELECT rc.capability, c1.id, (c1.contextlevel * 100) AS aggrlevel, + $capabilities = array(); // Reinitialize. + + // SQL for normal capabilities + $SQL1 = "SELECT rc.capability, c1.id as id1, c1.id as id2, (c1.contextlevel * 100) AS aggrlevel, SUM(rc.permission) AS sum FROM {$CFG->prefix}role_assignments ra, @@ -622,11 +671,37 @@ function load_user_capability($capability='', $context ='', $userid='') { GROUP BY rc.capability, (c1.contextlevel * 100), c1.id HAVING - SUM(rc.permission) != 0 - UNION + SUM(rc.permission) != 0 + ORDER BY + aggrlevel ASC"; + + if (!$rs = get_recordset_sql($SQL1)) { + error("Query failed in load_user_capability."); + } - SELECT rc.capability, c2.id, (c1.contextlevel * 100 + c2.contextlevel) AS aggrlevel, - SUM(rc.permission) AS sum + if ($rs && $rs->RecordCount() > 0) { + while (!$rs->EOF) { + $array = $rs->fields; + $temprecord = new object; + + foreach ($array as $key=>$val) { + if ($key == 'aggrlevel') { + $temprecord->contextlevel = $val; + } else { + $temprecord->{$key} = $val; + } + } + + $capabilities[] = $temprecord; + $rs->MoveNext(); + } + } + // SQL for overrides + // this is take out because we have no way of making sure c1 is indeed related to c2 (parent) + // if we do not group by sum, it is possible to have multiple records of rc.capability, c1.id, c2.id, tuple having + // different values, we can maually sum it when we go through the list + $SQL2 = "SELECT rc.capability, c1.id as id1, c2.id as id2, (c1.contextlevel * 100 + c2.contextlevel) AS aggrlevel, + rc.permission AS sum FROM {$CFG->prefix}role_assignments ra, {$CFG->prefix}role_capabilities rc, @@ -643,15 +718,15 @@ function load_user_capability($capability='', $context ='', $userid='') { $timesql GROUP BY - rc.capability, (c1.contextlevel * 100 + c2.contextlevel), c2.id, c1.id + rc.capability, (c1.contextlevel * 100 + c2.contextlevel), c1.id, c2.id HAVING - SUM(rc.permission) != 0 + rc.permission != 0 ORDER BY aggrlevel ASC "; - $capabilities = array(); // Reinitialize. - if (!$rs = get_recordset_sql($SQL)) { + + if (!$rs = get_recordset_sql($SQL2)) { error("Query failed in load_user_capability."); } @@ -667,10 +742,20 @@ function load_user_capability($capability='', $context ='', $userid='') { $temprecord->{$key} = $val; } } - $capabilities[] = $temprecord; + // for overrides, we have to make sure that context2 is a child of context1 + // otherwise the combination makes no sense + if (is_parent_context($temprecord->id1, $temprecord->id2)) { + $capabilities[] = $temprecord; + } // only write if relevant $rs->MoveNext(); } } + + // this step sorts capabilities according to the contextlevel + // it is very important because the order matters when we + // go through each capabilities later. (i.e. higher level contextlevel + // will override lower contextlevel settings + usort($capabilities, 'roles_context_cmp'); /* so up to this point we should have somethign like this * $capabilities[1] ->contextlevel = 1000 @@ -721,23 +806,26 @@ function load_user_capability($capability='', $context ='', $userid='') { $usercap = array(); // for other user's capabilities foreach ($capabilities as $capability) { - if (!$context = get_context_instance_by_id($capability->id)) { + if (!$context = get_context_instance_by_id($capability->id2)) { continue; // incorrect stale context } if (!empty($otheruserid)) { // we are pulling out other user's capabilities, do not write to session if (capability_prohibits($capability->capability, $context, $capability->sum, $usercap)) { - $usercap[$capability->id][$capability->capability] = CAP_PROHIBIT; + $usercap[$capability->id2][$capability->capability] = CAP_PROHIBIT; continue; } - - $usercap[$capability->id][$capability->capability] = $capability->sum; + if (!empty($usercap[$capability->id2][$capability->capability])) { + $usercap[$capability->id2][$capability->capability] += $capability->sum; + } else { + $usercap[$capability->id2][$capability->capability] = $capability->sum; + } } else { if (capability_prohibits($capability->capability, $context, $capability->sum)) { // if any parent or parent's parent is set to prohibit - $USER->capabilities[$capability->id][$capability->capability] = CAP_PROHIBIT; + $USER->capabilities[$capability->id2][$capability->capability] = CAP_PROHIBIT; continue; } @@ -748,7 +836,11 @@ function load_user_capability($capability='', $context ='', $userid='') { // parental prohibits // no point writing 0, since 0 = inherit // we need to write even if it's 0, because it could be an inherit override - $USER->capabilities[$capability->id][$capability->capability] = $capability->sum; + if (!empty($USER->capabilities[$capability->id2][$capability->capability])) { + $USER->capabilities[$capability->id2][$capability->capability] += $capability->sum; + } else { + $USER->capabilities[$capability->id2][$capability->capability] = $capability->sum; + } } }