/** * Call to complete the user login process after authenticate_user_login() * has succeeded. It will setup the $USER variable and other required bits * and pieces. * * NOTE: * - It will NOT log anything -- up to the caller to decide what to log. * * * * @uses $CFG, $USER * @param string $user obj * @return user|flase A {@link $USER} object or false if error */ function complete_user_login($user) { global $CFG, $USER; $USER = $user; // this is required because we need to access preferences here! if (!empty($CFG->regenloginsession)) { // please note this setting may break some auth plugins session_regenerate_id(); } reload_user_preferences(); update_user_login_times(); if (empty($CFG->nolastloggedin)) { set_moodle_cookie($USER->username); } else { // do not store last logged in user in cookie // auth plugins can temporarily override this from loginpage_hook() // do not save $CFG->nolastloggedin in database! set_moodle_cookie('nobody'); } set_login_session_preferences(); // Call enrolment plugins check_enrolment_plugins($user); /// This is what lets the user do anything on the site :-) load_all_capabilities(); /// Select password change url $userauth = get_auth_plugin($USER->auth); /// check whether the user should be changing password if (get_user_preferences('auth_forcepasswordchange', false)) { if ($userauth->can_change_password()) { if ($changeurl = $userauth->change_password_url()) { redirect($changeurl); } else { redirect($CFG->httpswwwroot . '/login/change_password.php'); } } else { print_error('nopasswordchangeforced', 'auth'); } } return $USER; }
} else { if (isset($SESSION->wantsurl) and strpos($SESSION->wantsurl, $CFG->wwwroot) === 0) { $urltogo = $SESSION->wantsurl; /// Because it's an address in this site unset($SESSION->wantsurl); } else { $urltogo = $CFG->wwwroot . '/'; /// Go to the standard home page unset($SESSION->wantsurl); /// Just in case } } /// Go to my-moodle page instead of homepage if mymoodleredirect enabled if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM)) and !empty($CFG->mymoodleredirect) and !isguest()) { if ($urltogo == $CFG->wwwroot or $urltogo == $CFG->wwwroot . '/' or $urltogo == $CFG->wwwroot . '/index.php') { $urltogo = $CFG->wwwroot . '/my/'; } } check_enrolment_plugins($USER); load_all_capabilities(); /// This is what lets the user do anything on the site :-) redirect($urltogo); exit; } else { // For some weird reason the Shibboleth user couldn't be authenticated } } elseif (!empty($_SERVER['HTTP_SHIB_APPLICATION_ID']) || !empty($_SERVER['Shib-Application-ID'])) { print_error('shib_no_attributes_error', 'auth', '', '\'' . $pluginconfig->user_attribute . '\', \'' . $pluginconfig->field_map_firstname . '\', \'' . $pluginconfig->field_map_lastname . '\' and \'' . $pluginconfig->field_map_email . '\''); } else { print_error('shib_not_set_up_error', 'auth'); }
/** * Setup $USER object - called during login, loginas, etc. * Preloads capabilities and checks enrolment plugins * * @param object $user full user record object * @return void */ function session_set_user($user) { $_SESSION['USER'] = $user; unset($_SESSION['USER']->description); // conserve memory if (!isset($_SESSION['USER']->access)) { // check enrolments and load caps only once check_enrolment_plugins($_SESSION['USER']); load_all_capabilities(); } sesskey(); // init session key }
/** * A convenience function to completely load all the capabilities * for the current user. This is what gets called from login, for example. */ function load_all_capabilities() { global $USER, $CFG; $base = '/' . SYSCONTEXTID; if (isguestuser()) { $guest = get_guest_role(); // Load the rdefs $USER->access = get_role_access($guest->id); // Put the ghost enrolment in place... $USER->access['ra'][$base] = array($guest->id); } else { if (isloggedin()) { check_enrolment_plugins($USER); $accessdata = get_user_access_sitewide($USER->id); // // provide "default role" & set 'dr' // if (!empty($CFG->defaultuserroleid)) { $accessdata = get_role_access($CFG->defaultuserroleid, $accessdata); if (!isset($accessdata['ra'][$base])) { $accessdata['ra'][$base] = array($CFG->defaultuserroleid); } else { array_push($accessdata['ra'][$base], $CFG->defaultuserroleid); } $accessdata['dr'] = $CFG->defaultuserroleid; } $frontpagecontext = get_context_instance(CONTEXT_COURSE, SITEID); // // provide "default frontpage role" // if (!empty($CFG->defaultfrontpageroleid)) { $base = '/' . SYSCONTEXTID . '/' . $frontpagecontext->id; $accessdata = get_default_frontpage_role_access($CFG->defaultfrontpageroleid, $accessdata); if (!isset($accessdata['ra'][$base])) { $accessdata['ra'][$base] = array($CFG->defaultfrontpageroleid); } else { array_push($accessdata['ra'][$base], $CFG->defaultfrontpageroleid); } } $USER->access = $accessdata; } else { if (!empty($CFG->notloggedinroleid)) { $USER->access = get_role_access($CFG->notloggedinroleid); $USER->access['ra'][$base] = array($CFG->notloggedinroleid); } } } // Timestamp to read // dirty context timestamps $USER->access['time'] = time(); // Clear to force a refresh unset($USER->mycourses); }
function teosso_authenticate_user() { global $CFG, $USER, $SESSION; $pluginconfig = get_config('auth/teosso'); // retrieve the login data from the HTTP Headers $attributes = auth_plugin_teosso::get_sso_attributes(); // check to see if we got any authentication data if (empty($attributes)) { redirect($pluginconfig->signin_url); } // get the http headers for error reporting $headers = apache_request_headers(); $attr_hdrs = array(); foreach ($headers as $key => $value) { if (preg_match('/^HTTP_/', $key)) { $attr_hdrs[] = $key . ': ' . $value; } } $headers = implode(' | ', $attr_hdrs); // FIND THE VALIDIDTY OF THE HTTP HEADER $attrmap = auth_plugin_teosso::get_attributes(); if (empty($attrmap['idnumber'])) { // serious misdemeanour print_error('missingidnumber', 'auth_teosso'); } if (empty($attributes[$attrmap['idnumber']])) { # // not valid session. Ship user off to Federation Manager add_to_log(0, 'login', 'error', '/auth/teosso/index.php', get_string('idnumber_error', 'auth_teosso', $headers)); redirect($pluginconfig->signin_error_url); } else { // in theory we only need acct_id at this point - we should retrieve the user record to get the username via idnumber if (!($user = get_record('user', 'idnumber', $attributes[$attrmap['idnumber']]))) { // must be a new user if (!empty($attributes[$attrmap['username']])) { $attributes['username'] = $attributes[$attrmap['username']]; } else { add_to_log(0, 'login', 'error', '/auth/teosso/index.php', get_string('username_error', 'auth_teosso', $headers)); redirect($pluginconfig->signin_error_url); } } else { // user must use the auth type teosso or authenticate_user_login() will fail if ($user->auth != 'teosso') { add_to_log(0, 'login', 'error', '/auth/teosso/index.php', get_string('user_auth_type_error', 'auth_teosso', $headers)); redirect($pluginconfig->signin_error_url); } // because we want to retain acct_id as the master ID // we need to modify idnumber on mdl_user NOW - so it all lines up later if (isset($attributes[$attrmap['username']]) && $user->username != $attributes[$attrmap['username']]) { if (!set_field('user', 'username', $attributes[$attrmap['username']], 'id', $user->id)) { print_error('usernameupdatefailed', 'auth_teosso'); } $attributes['username'] = $attributes[$attrmap['username']]; } else { $attributes['username'] = $user->username; } } // Valid session. Register or update user in Moodle, log him on, and redirect to Moodle front // we require the plugin to know that we are now doing a teosso login in hook puser_login $GLOBALS['teosso_login'] = TRUE; // make variables accessible to teosso->get_userinfo. Information will be requested from authenticate_user_login -> create_user_record / update_user_record $GLOBALS['teosso_login_attributes'] = $attributes; // just passes time as a password. User will never log in directly to moodle with this password anyway or so we hope? $USER = authenticate_user_login($attributes['username'], time()); $USER->loggedin = true; $USER->site = $CFG->wwwroot; update_user_login_times(); if ($pluginconfig->notshowusername) { // Don't show username on login page set_moodle_cookie('nobody'); } set_login_session_preferences(); add_to_log(SITEID, 'user', 'login', "view.php?id={$USER->id}&course=" . SITEID, $USER->id, 0, $USER->id); check_enrolment_plugins($USER); load_all_capabilities(); // just fast copied this from some other module - might not work... if (isset($SESSION->wantsurl) and strpos($SESSION->wantsurl, $CFG->wwwroot) === 0) { $urltogo = $SESSION->wantsurl; } else { $urltogo = $CFG->wwwroot . '/'; } unset($SESSION->wantsurl); redirect($urltogo); } }
/** * It will build an array of all the capabilities at each level * i.e. site/metacourse/course_category/course/moduleinstance * Note we should only load capabilities if they are explicitly assigned already, * we should not load all module's capability! * * [Capabilities] => [26][forum_post] = 1 * [26][forum_start] = -8990 * [26][forum_edit] = -1 * [273][blah blah] = 1 * [273][blah blah blah] = 2 * * @param $capability string - Only get a specific capability (string) * @param $context object - Only get capabilities for a specific context object * @param $userid integer - the id of the user whose capabilities we want to load * @param $checkenrolments boolean - Should we checkenrolment plugins (potentially expensive) * @return array of permissions (or nothing if they get assigned to $USER) */ function load_user_capability($capability = '', $context = NULL, $userid = NULL, $checkenrolments = true) { global $USER, $CFG; // this flag has not been set! // (not clean install, or upgraded successfully to 1.7 and up) if (empty($CFG->rolesactive)) { return false; } if (empty($userid)) { if (empty($USER->id)) { // We have no user to get capabilities for debugging('User not logged in for load_user_capability!'); return false; } unset($USER->capabilities); // We don't want possible older capabilites hanging around if ($checkenrolments) { // Call "enrol" system to ensure that we have the correct picture check_enrolment_plugins($USER); } $userid = $USER->id; $otheruserid = false; } else { if (!($user = get_record('user', 'id', $userid))) { debugging('Non-existent userid in load_user_capability!'); return false; } if ($checkenrolments) { // Call "enrol" system to ensure that we have the correct picture check_enrolment_plugins($user); } $otheruserid = $userid; } /// First we generate a list of all relevant contexts of the user $usercontexts = array(); if ($context) { // if context is specified $usercontexts = get_parent_contexts($context); $usercontexts[] = $context->id; // Add the current context as well } else { // else, we load everything if ($userroles = get_records('role_assignments', 'userid', $userid)) { foreach ($userroles as $userrole) { if (!in_array($userrole->contextid, $usercontexts)) { $usercontexts[] = $userrole->contextid; } } } } /// Set up SQL fragments for searching contexts if ($usercontexts) { $listofcontexts = '(' . implode(',', $usercontexts) . ')'; $searchcontexts1 = "c1.id IN {$listofcontexts} AND"; } else { $searchcontexts1 = ''; } if ($capability) { // the doanything may override the requested capability $capsearch = " AND (rc.capability = '{$capability}' OR rc.capability = 'moodle/site:doanything') "; } else { $capsearch = ""; } /// Then we use 1 giant SQL to bring out all relevant capabilities. /// The first part gets the capabilities of orginal role. /// The second part gets the capabilities of overriden roles. $siteinstance = get_context_instance(CONTEXT_SYSTEM); $capabilities = array(); // Reinitialize. // SQL for normal capabilities $SQL1 = "SELECT rc.capability, c1.id as id1, c1.id as id2, (c1.contextlevel * 100) AS aggrlevel,\n SUM(rc.permission) AS sum\n FROM\n {$CFG->prefix}role_assignments ra,\n {$CFG->prefix}role_capabilities rc,\n {$CFG->prefix}context c1\n WHERE\n ra.contextid=c1.id AND\n ra.roleid=rc.roleid AND\n ra.userid={$userid} AND\n {$searchcontexts1}\n rc.contextid={$siteinstance->id}\n {$capsearch}\n GROUP BY\n rc.capability, c1.id, c1.contextlevel * 100\n HAVING\n SUM(rc.permission) != 0 \n \n UNION ALL\n \n SELECT rc.capability, c1.id as id1, c2.id as id2, (c1.contextlevel * 100 + c2.contextlevel) AS aggrlevel, \n SUM(rc.permission) AS sum\n FROM\n {$CFG->prefix}role_assignments ra LEFT JOIN\n {$CFG->prefix}role_capabilities rc on ra.roleid = rc.roleid LEFT JOIN\n {$CFG->prefix}context c1 on ra.contextid = c1.id LEFT JOIN\n {$CFG->prefix}context c2 on rc.contextid = c2.id LEFT JOIN\n {$CFG->prefix}context_rel cr on cr.c1 = c2.id\n WHERE\n ra.userid={$userid} AND\n {$searchcontexts1}\n rc.contextid != {$siteinstance->id}\n {$capsearch}\n AND cr.c2 = c1.id\n GROUP BY\n rc.capability, c1.id, c2.id, c1.contextlevel * 100 + c2.contextlevel\n HAVING\n SUM(rc.permission) != 0\n ORDER BY\n aggrlevel ASC"; if (!($rs = get_recordset_sql($SQL1))) { error("Query failed in load_user_capability."); } if ($rs && $rs->RecordCount() > 0) { while ($caprec = rs_fetch_next_record($rs)) { $array = (array) $caprec; $temprecord = new object(); foreach ($array as $key => $val) { if ($key == 'aggrlevel') { $temprecord->contextlevel = $val; } else { $temprecord->{$key} = $val; } } $capabilities[] = $temprecord; } rs_close($rs); } // 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, {$CFG->prefix}context c1, {$CFG->prefix}context c2 WHERE ra.contextid=c1.id AND ra.roleid=rc.roleid AND ra.userid=$userid AND rc.contextid=c2.id AND $searchcontexts1 rc.contextid != $siteinstance->id $capsearch GROUP BY rc.capability, (c1.contextlevel * 100 + c2.contextlevel), c1.id, c2.id, rc.permission ORDER BY aggrlevel ASC ";*/ /* if (!$rs = get_recordset_sql($SQL2)) { error("Query failed in load_user_capability."); } if ($rs && $rs->RecordCount() > 0) { while ($caprec = rs_fetch_next_record($rs)) { $array = (array)$caprec; $temprecord = new object; foreach ($array as $key=>$val) { if ($key == 'aggrlevel') { $temprecord->contextlevel = $val; } else { $temprecord->{$key} = $val; } } // 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_close($rs); } // 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 ->module = 0 // changed from SITEID in 1.8 (??) ->capability = do_anything ->id = 1 (id is the context id) ->sum = 0 * $capabilities[2] ->contextlevel = 1000 ->module = 0 // changed from SITEID in 1.8 (??) ->capability = post_messages ->id = 1 ->sum = -9000 * $capabilittes[3] ->contextlevel = 3000 ->module = course ->capability = view_course_activities ->id = 25 ->sum = 1 * $capabilittes[4] ->contextlevel = 3000 ->module = course ->capability = view_course_activities ->id = 26 ->sum = 0 (this is another course) * $capabilities[5] ->contextlevel = 3050 ->module = course ->capability = view_course_activities ->id = 25 (override in course 25) ->sum = -1 * .... * now we proceed to write the session array, going from top to bottom * at anypoint, we need to go up and check parent to look for prohibit */ // print_object($capabilities); /* This is where we write to the actualy capabilities array * what we need to do from here on is * going down the array from lowest level to highest level * 1) recursively check for prohibit, * if any, we write prohibit * else, we write the value * 2) at an override level, we overwrite current level * if it's not set to prohibit already, and if different * ........ that should be it ........ */ // This is the flag used for detecting the current context level. Since we are going through // the array in ascending order of context level. For normal capabilities, there should only // be 1 value per (capability, contextlevel, context), because they are already summed. But, // for overrides, since we are processing them separate, we need to sum the relevcant entries. // We set this flag when we hit a new level. // If the flag is already set, we keep adding (summing), otherwise, we just override previous // settings (from lower level contexts) $capflags = array(); // (contextid, contextlevel, capability) $usercap = array(); // for other user's capabilities foreach ($capabilities as $capability) { 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->id2][$capability->capability] = CAP_PROHIBIT; continue; } if (isset($usercap[$capability->id2][$capability->capability])) { // use isset because it can be sum 0 if (!empty($capflags[$capability->id2][$capability->contextlevel][$capability->capability])) { $usercap[$capability->id2][$capability->capability] += $capability->sum; } else { // else we override, and update flag $usercap[$capability->id2][$capability->capability] = $capability->sum; $capflags[$capability->id2][$capability->contextlevel][$capability->capability] = true; } } else { $usercap[$capability->id2][$capability->capability] = $capability->sum; $capflags[$capability->id2][$capability->contextlevel][$capability->capability] = true; } } else { if (capability_prohibits($capability->capability, $context, $capability->sum)) { // if any parent or parent's parent is set to prohibit $USER->capabilities[$capability->id2][$capability->capability] = CAP_PROHIBIT; continue; } // if no parental prohibit set // just write to session, i am not sure this is correct yet // since 3050 shows up after 3000, and 3070 shows up after 3050, // it should be ok just to overwrite like this, provided that there's no // parental prohibits // we need to write even if it's 0, because it could be an inherit override if (isset($USER->capabilities[$capability->id2][$capability->capability])) { if (!empty($capflags[$capability->id2][$capability->contextlevel][$capability->capability])) { $USER->capabilities[$capability->id2][$capability->capability] += $capability->sum; } else { // else we override, and update flag $USER->capabilities[$capability->id2][$capability->capability] = $capability->sum; $capflags[$capability->id2][$capability->contextlevel][$capability->capability] = true; } } else { $USER->capabilities[$capability->id2][$capability->capability] = $capability->sum; $capflags[$capability->id2][$capability->contextlevel][$capability->capability] = true; } } } // now we don't care about the huge array anymore, we can dispose it. unset($capabilities); unset($capflags); if (!empty($otheruserid)) { return $usercap; // return the array } }