Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/auth/mnet/auth.php
Go to the documentation of this file.
00001 <?php
00002 
00015 if (!defined('MOODLE_INTERNAL')) {
00016     die('Direct access to this script is forbidden.');    
00017 }
00018 
00019 require_once($CFG->libdir.'/authlib.php');
00020 
00024 class auth_plugin_mnet extends auth_plugin_base {
00025 
00029     function auth_plugin_mnet() {
00030         $this->authtype = 'mnet';
00031         $this->config = get_config('auth_mnet');
00032         $this->mnet = get_mnet_environment();
00033     }
00034 
00044     function user_login($username, $password) {
00045         return false; // print_error("mnetlocal");
00046     }
00047 
00055     function user_authorise($token, $useragent) {
00056         global $CFG, $SITE, $DB;
00057         $remoteclient = get_mnet_remote_client();
00058         require_once $CFG->dirroot . '/mnet/xmlrpc/serverlib.php';
00059 
00060         $mnet_session = $DB->get_record('mnet_session', array('token'=>$token, 'useragent'=>$useragent));
00061         if (empty($mnet_session)) {
00062             throw new mnet_server_exception(1, 'authfail_nosessionexists');
00063         }
00064 
00065         // check session confirm timeout
00066         if ($mnet_session->confirm_timeout < time()) {
00067             throw new mnet_server_exception(2, 'authfail_sessiontimedout');
00068         }
00069 
00070         // session okay, try getting the user
00071         if (!$user = $DB->get_record('user', array('id'=>$mnet_session->userid))) {
00072             throw new mnet_server_exception(3, 'authfail_usermismatch');
00073         }
00074 
00075         $userdata = mnet_strip_user((array)$user, mnet_fields_to_send($remoteclient));
00076 
00077         // extra special ones
00078         $userdata['auth']                    = 'mnet';
00079         $userdata['wwwroot']                 = $this->mnet->wwwroot;
00080         $userdata['session.gc_maxlifetime']  = ini_get('session.gc_maxlifetime');
00081 
00082         if (array_key_exists('picture', $userdata) && !empty($user->picture)) {
00083             $fs = get_file_storage();
00084             $usercontext = get_context_instance(CONTEXT_USER, $user->id, MUST_EXIST);
00085             if ($usericonfile = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f1.png')) {
00086                 $userdata['_mnet_userpicture_timemodified'] = $usericonfile->get_timemodified();
00087                 $userdata['_mnet_userpicture_mimetype'] = $usericonfile->get_mimetype();
00088             } else if ($usericonfile = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f1.jpg')) {
00089                 $userdata['_mnet_userpicture_timemodified'] = $usericonfile->get_timemodified();
00090                 $userdata['_mnet_userpicture_mimetype'] = $usericonfile->get_mimetype();
00091             }
00092         }
00093 
00094         $userdata['myhosts'] = array();
00095         if ($courses = enrol_get_users_courses($user->id, false)) {
00096             $userdata['myhosts'][] = array('name'=> $SITE->shortname, 'url' => $CFG->wwwroot, 'count' => count($courses));
00097         }
00098 
00099         $sql = "SELECT h.name AS hostname, h.wwwroot, h.id AS hostid,
00100                        COUNT(c.id) AS count
00101                   FROM {mnetservice_enrol_courses} c
00102                   JOIN {mnetservice_enrol_enrolments} e ON (e.hostid = c.hostid AND e.remotecourseid = c.remoteid)
00103                   JOIN {mnet_host} h ON h.id = c.hostid
00104                  WHERE e.userid = ? AND c.hostid = ?
00105               GROUP BY h.name, h.wwwroot, h.id";
00106 
00107         if ($courses = $DB->get_records_sql($sql, array($user->id, $remoteclient->id))) {
00108             foreach($courses as $course) {
00109                 $userdata['myhosts'][] = array('name'=> $course->hostname, 'url' => $CFG->wwwroot.'/auth/mnet/jump.php?hostid='.$course->hostid, 'count' => $course->count);
00110             }
00111         }
00112 
00113         return $userdata;
00114     }
00115 
00119     function generate_token() {
00120         return sha1(str_shuffle('' . mt_rand() . time()));
00121     }
00122 
00131     function start_jump_session($mnethostid, $wantsurl, $wantsurlbackhere=false) {
00132         global $CFG, $USER, $DB;
00133         require_once $CFG->dirroot . '/mnet/xmlrpc/client.php';
00134 
00135         if (session_is_loggedinas()) {
00136             print_error('notpermittedtojumpas', 'mnet');
00137         }
00138 
00139         // check remote login permissions
00140         if (! has_capability('moodle/site:mnetlogintoremote', get_system_context())
00141                 or is_mnet_remote_user($USER)
00142                 or isguestuser()
00143                 or !isloggedin()) {
00144             print_error('notpermittedtojump', 'mnet');
00145         }
00146 
00147         // check for SSO publish permission first
00148         if ($this->has_service($mnethostid, 'sso_sp') == false) {
00149             print_error('hostnotconfiguredforsso', 'mnet');
00150         }
00151 
00152         // set RPC timeout to 30 seconds if not configured
00153         if (empty($this->config->rpc_negotiation_timeout)) {
00154             $this->config->rpc_negotiation_timeout = 30;
00155             set_config('rpc_negotiation_timeout', '30', 'auth_mnet');
00156         }
00157 
00158         // get the host info
00159         $mnet_peer = new mnet_peer();
00160         $mnet_peer->set_id($mnethostid);
00161 
00162         // set up the session
00163         $mnet_session = $DB->get_record('mnet_session',
00164                                    array('userid'=>$USER->id, 'mnethostid'=>$mnethostid,
00165                                    'useragent'=>sha1($_SERVER['HTTP_USER_AGENT'])));
00166         if ($mnet_session == false) {
00167             $mnet_session = new stdClass();
00168             $mnet_session->mnethostid = $mnethostid;
00169             $mnet_session->userid = $USER->id;
00170             $mnet_session->username = $USER->username;
00171             $mnet_session->useragent = sha1($_SERVER['HTTP_USER_AGENT']);
00172             $mnet_session->token = $this->generate_token();
00173             $mnet_session->confirm_timeout = time() + $this->config->rpc_negotiation_timeout;
00174             $mnet_session->expires = time() + (integer)ini_get('session.gc_maxlifetime');
00175             $mnet_session->session_id = session_id();
00176             $mnet_session->id = $DB->insert_record('mnet_session', $mnet_session);
00177         } else {
00178             $mnet_session->useragent = sha1($_SERVER['HTTP_USER_AGENT']);
00179             $mnet_session->token = $this->generate_token();
00180             $mnet_session->confirm_timeout = time() + $this->config->rpc_negotiation_timeout;
00181             $mnet_session->expires = time() + (integer)ini_get('session.gc_maxlifetime');
00182             $mnet_session->session_id = session_id();
00183             $DB->update_record('mnet_session', $mnet_session);
00184         }
00185 
00186         // construct the redirection URL
00187         //$transport = mnet_get_protocol($mnet_peer->transport);
00188         $wantsurl = urlencode($wantsurl);
00189         $url = "{$mnet_peer->wwwroot}{$mnet_peer->application->sso_land_url}?token={$mnet_session->token}&idp={$this->mnet->wwwroot}&wantsurl={$wantsurl}";
00190         if ($wantsurlbackhere) {
00191             $url .= '&remoteurl=1';
00192         }
00193 
00194         return $url;
00195     }
00196 
00206     function confirm_mnet_session($token, $remotepeer) {
00207         global $CFG, $DB;
00208         require_once $CFG->dirroot . '/mnet/xmlrpc/client.php';
00209         require_once $CFG->libdir . '/gdlib.php';
00210 
00211         // verify the remote host is configured locally before attempting RPC call
00212         if (! $remotehost = $DB->get_record('mnet_host', array('wwwroot' => $remotepeer->wwwroot, 'deleted' => 0))) {
00213             print_error('notpermittedtoland', 'mnet');
00214         }
00215 
00216         // set up the RPC request
00217         $mnetrequest = new mnet_xmlrpc_client();
00218         $mnetrequest->set_method('auth/mnet/auth.php/user_authorise');
00219 
00220         // set $token and $useragent parameters
00221         $mnetrequest->add_param($token);
00222         $mnetrequest->add_param(sha1($_SERVER['HTTP_USER_AGENT']));
00223 
00224         // Thunderbirds are go! Do RPC call and store response
00225         if ($mnetrequest->send($remotepeer) === true) {
00226             $remoteuser = (object) $mnetrequest->response;
00227         } else {
00228             foreach ($mnetrequest->error as $errormessage) {
00229                 list($code, $message) = array_map('trim',explode(':', $errormessage, 2));
00230                 if($code == 702) {
00231                     $site = get_site();
00232                     print_error('mnet_session_prohibited', 'mnet', $remotepeer->wwwroot, format_string($site->fullname));
00233                     exit;
00234                 }
00235                 $message .= "ERROR $code:<br/>$errormessage<br/>";
00236             }
00237             print_error("rpcerror", '', '', $message);
00238         }
00239         unset($mnetrequest);
00240 
00241         if (empty($remoteuser) or empty($remoteuser->username)) {
00242             print_error('unknownerror', 'mnet');
00243             exit;
00244         }
00245 
00246         if (user_not_fully_set_up($remoteuser)) {
00247             print_error('notenoughidpinfo', 'mnet');
00248             exit;
00249         }
00250 
00251         $remoteuser = mnet_strip_user($remoteuser, mnet_fields_to_import($remotepeer));
00252 
00253         $remoteuser->auth = 'mnet';
00254         $remoteuser->wwwroot = $remotepeer->wwwroot;
00255 
00256         // the user may roam from Moodle 1.x where lang has _utf8 suffix
00257         // also, make sure that the lang is actually installed, otherwise set site default
00258         if (isset($remoteuser->lang)) {
00259             $remoteuser->lang = clean_param(str_replace('_utf8', '', $remoteuser->lang), PARAM_LANG);
00260         }
00261         if (empty($remoteuser->lang)) {
00262             if (!empty($CFG->lang)) {
00263                 $remoteuser->lang = $CFG->lang;
00264             } else {
00265                 $remoteuser->lang = 'en';
00266             }
00267         }
00268         $firsttime = false;
00269 
00270         // get the local record for the remote user
00271         $localuser = $DB->get_record('user', array('username'=>$remoteuser->username, 'mnethostid'=>$remotehost->id));
00272 
00273         // add the remote user to the database if necessary, and if allowed
00274         // TODO: refactor into a separate function
00275         if (empty($localuser) || ! $localuser->id) {
00276             /*
00277             if (empty($this->config->auto_add_remote_users)) {
00278                 print_error('nolocaluser', 'mnet');
00279             } See MDL-21327   for why this is commented out
00280             */
00281             $remoteuser->mnethostid = $remotehost->id;
00282             $remoteuser->firstaccess = time(); // First time user in this server, grab it here
00283             $remoteuser->confirmed = 1;
00284 
00285             $remoteuser->id = $DB->insert_record('user', $remoteuser);
00286             $firsttime = true;
00287             $localuser = $remoteuser;
00288         }
00289 
00290         // check sso access control list for permission first
00291         if (!$this->can_login_remotely($localuser->username, $remotehost->id)) {
00292             print_error('sso_mnet_login_refused', 'mnet', '', array('user'=>$localuser->username, 'host'=>$remotehost->name));
00293         }
00294 
00295         $fs = get_file_storage();
00296 
00297         // update the local user record with remote user data
00298         foreach ((array) $remoteuser as $key => $val) {
00299 
00300             if ($key == '_mnet_userpicture_timemodified' and empty($CFG->disableuserimages) and isset($remoteuser->picture)) {
00301                 // update the user picture if there is a newer verion at the identity provider
00302                 $usercontext = get_context_instance(CONTEXT_USER, $localuser->id, MUST_EXIST);
00303                 if ($usericonfile = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f1.png')) {
00304                     $localtimemodified = $usericonfile->get_timemodified();
00305                 } else if ($usericonfile = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f1.jpg')) {
00306                     $localtimemodified = $usericonfile->get_timemodified();
00307                 } else {
00308                     $localtimemodified = 0;
00309                 }
00310 
00311                 if (!empty($val) and $localtimemodified < $val) {
00312                     mnet_debug('refetching the user picture from the identity provider host');
00313                     $fetchrequest = new mnet_xmlrpc_client();
00314                     $fetchrequest->set_method('auth/mnet/auth.php/fetch_user_image');
00315                     $fetchrequest->add_param($localuser->username);
00316                     if ($fetchrequest->send($remotepeer) === true) {
00317                         if (strlen($fetchrequest->response['f1']) > 0) {
00318                             $imagefilename = $CFG->tempdir . '/mnet-usericon-' . $localuser->id;
00319                             $imagecontents = base64_decode($fetchrequest->response['f1']);
00320                             file_put_contents($imagefilename, $imagecontents);
00321                             if (process_new_icon($usercontext, 'user', 'icon', 0, $imagefilename)) {
00322                                 $localuser->picture = 1;
00323                             }
00324                             unlink($imagefilename);
00325                         }
00326                         // note that since Moodle 2.0 we ignore $fetchrequest->response['f2']
00327                         // the mimetype information provided is ignored and the type of the file is detected
00328                         // by process_new_icon()
00329                     }
00330                 }
00331             }
00332 
00333             if($key == 'myhosts') {
00334                 $localuser->mnet_foreign_host_array = array();
00335                 foreach($val as $rhost) {
00336                     $name  = clean_param($rhost['name'], PARAM_ALPHANUM);
00337                     $url   = clean_param($rhost['url'], PARAM_URL);
00338                     $count = clean_param($rhost['count'], PARAM_INT);
00339                     $url_is_local = stristr($url , $CFG->wwwroot);
00340                     if (!empty($name) && !empty($count) && empty($url_is_local)) {
00341                         $localuser->mnet_foreign_host_array[] = array('name'  => $name,
00342                                                                       'url'   => $url,
00343                                                                       'count' => $count);
00344                     }
00345                 }
00346             }
00347 
00348             $localuser->{$key} = $val;
00349         }
00350 
00351         $localuser->mnethostid = $remotepeer->id;
00352         if (empty($localuser->firstaccess)) { // Now firstaccess, grab it here
00353             $localuser->firstaccess = time();
00354         }
00355 
00356         $DB->update_record('user', $localuser);
00357 
00358         if (!$firsttime) {
00359             // repeat customer! let the IDP know about enrolments
00360             // we have for this user.
00361             // set up the RPC request
00362             $mnetrequest = new mnet_xmlrpc_client();
00363             $mnetrequest->set_method('auth/mnet/auth.php/update_enrolments');
00364 
00365             // pass username and an assoc array of "my courses"
00366             // with info so that the IDP can maintain mnetservice_enrol_enrolments
00367             $mnetrequest->add_param($remoteuser->username);
00368             $fields = 'id, category, sortorder, fullname, shortname, idnumber, summary, startdate, visible';
00369             $courses = enrol_get_users_courses($localuser->id, false, $fields, 'visible DESC,sortorder ASC');
00370             if (is_array($courses) && !empty($courses)) {
00371                 // Second request to do the JOINs that we'd have done
00372                 // inside enrol_get_users_courses() if we had been allowed
00373                 $sql = "SELECT c.id,
00374                                cc.name AS cat_name, cc.description AS cat_description
00375                           FROM {course} c
00376                           JOIN {course_categories} cc ON c.category = cc.id
00377                          WHERE c.id IN (" . join(',',array_keys($courses)) . ')';
00378                 $extra = $DB->get_records_sql($sql);
00379 
00380                 $keys = array_keys($courses);
00381                 $defaultrole = reset(get_archetype_roles('student'));
00382                 //$defaultrole = get_default_course_role($ccache[$shortname]); //TODO: rewrite this completely, there is no default course role any more!!!
00383                 foreach ($keys AS $id) {
00384                     if ($courses[$id]->visible == 0) {
00385                         unset($courses[$id]);
00386                         continue;
00387                     }
00388                     $courses[$id]->cat_id          = $courses[$id]->category;
00389                     $courses[$id]->defaultroleid   = $defaultrole->id;
00390                     unset($courses[$id]->category);
00391                     unset($courses[$id]->visible);
00392 
00393                     $courses[$id]->cat_name        = $extra[$id]->cat_name;
00394                     $courses[$id]->cat_description = $extra[$id]->cat_description;
00395                     $courses[$id]->defaultrolename = $defaultrole->name;
00396                     // coerce to array
00397                     $courses[$id] = (array)$courses[$id];
00398                 }
00399             } else {
00400                 // if the array is empty, send it anyway
00401                 // we may be clearing out stale entries
00402                 $courses = array();
00403             }
00404             $mnetrequest->add_param($courses);
00405 
00406             // Call 0800-RPC Now! -- we don't care too much if it fails
00407             // as it's just informational.
00408             if ($mnetrequest->send($remotepeer) === false) {
00409                 // error_log(print_r($mnetrequest->error,1));
00410             }
00411         }
00412 
00413         return $localuser;
00414     }
00415 
00416 
00425     public function update_mnet_session($user, $token, $remotepeer) {
00426         global $DB;
00427         $session_gc_maxlifetime = 1440;
00428         if (isset($user->session_gc_maxlifetime)) {
00429             $session_gc_maxlifetime = $user->session_gc_maxlifetime;
00430         }
00431         if (!$mnet_session = $DB->get_record('mnet_session',
00432                                    array('userid'=>$user->id, 'mnethostid'=>$remotepeer->id,
00433                                    'useragent'=>sha1($_SERVER['HTTP_USER_AGENT'])))) {
00434             $mnet_session = new stdClass();
00435             $mnet_session->mnethostid = $remotepeer->id;
00436             $mnet_session->userid = $user->id;
00437             $mnet_session->username = $user->username;
00438             $mnet_session->useragent = sha1($_SERVER['HTTP_USER_AGENT']);
00439             $mnet_session->token = $token; // Needed to support simultaneous sessions
00440                                            // and preserving DB rec uniqueness
00441             $mnet_session->confirm_timeout = time();
00442             $mnet_session->expires = time() + (integer)$session_gc_maxlifetime;
00443             $mnet_session->session_id = session_id();
00444             $mnet_session->id = $DB->insert_record('mnet_session', $mnet_session);
00445         } else {
00446             $mnet_session->expires = time() + (integer)$session_gc_maxlifetime;
00447             $DB->update_record('mnet_session', $mnet_session);
00448         }
00449     }
00450 
00451 
00452 
00463     function update_enrolments($username, $courses) {
00464         global $CFG, $DB;
00465         $remoteclient = get_mnet_remote_client();
00466 
00467         if (empty($username) || !is_array($courses)) {
00468             return false;
00469         }
00470         // make sure it is a user we have an in active session
00471         // with that host...
00472         $mnetsessions = $DB->get_records('mnet_session', array('username' => $username, 'mnethostid' => $remoteclient->id), '', 'id, userid');
00473         $userid = null;
00474         foreach ($mnetsessions as $mnetsession) {
00475             if (is_null($userid)) {
00476                 $userid = $mnetsession->userid;
00477                 continue;
00478             }
00479             if ($userid != $mnetsession->userid) {
00480                 throw new mnet_server_exception(3, 'authfail_usermismatch');
00481             }
00482         }
00483 
00484         if (empty($courses)) { // no courses? clear out quickly
00485             $DB->delete_records('mnetservice_enrol_enrolments', array('hostid'=>$remoteclient->id, 'userid'=>$userid));
00486             return true;
00487         }
00488 
00489         // IMPORTANT: Ask for remoteid as the first element in the query, so
00490         // that the array that comes back is indexed on the same field as the
00491         // array that we have received from the remote client
00492         $sql = "SELECT c.remoteid, c.id, c.categoryid AS cat_id, c.categoryname AS cat_name, c.sortorder,
00493                        c.fullname, c.shortname, c.idnumber, c.summary, c.summaryformat, c.startdate,
00494                        e.id AS enrolmentid
00495                   FROM {mnetservice_enrol_courses} c
00496              LEFT JOIN {mnetservice_enrol_enrolments} e ON (e.hostid = c.hostid AND e.remotecourseid = c.remoteid)
00497                  WHERE e.userid = ? AND c.hostid = ?";
00498 
00499         $currentcourses = $DB->get_records_sql($sql, array($userid, $remoteclient->id));
00500 
00501         $local_courseid_array = array();
00502         foreach($courses as $ix => $course) {
00503 
00504             $course['remoteid'] = $course['id'];
00505             $course['hostid']   =  (int)$remoteclient->id;
00506             $userisregd         = false;
00507 
00508             // if we do not have the the information about the remote course, it is not available
00509             // to us for remote enrolment - skip
00510             if (array_key_exists($course['remoteid'], $currentcourses)) {
00511                 // Pointer to current course:
00512                 $currentcourse =& $currentcourses[$course['remoteid']];
00513                 // We have a record - is it up-to-date?
00514                 $course['id'] = $currentcourse->id;
00515 
00516                 $saveflag = false;
00517 
00518                 foreach($course as $key => $value) {
00519                     if ($currentcourse->$key != $value) {
00520                         $saveflag = true;
00521                         $currentcourse->$key = $value;
00522                     }
00523                 }
00524 
00525                 if ($saveflag) {
00526                     $DB->update_record('mnetervice_enrol_courses', $currentcourse);
00527                 }
00528 
00529                 if (isset($currentcourse->enrolmentid) && is_numeric($currentcourse->enrolmentid)) {
00530                     $userisregd = true;
00531                 }
00532             } else {
00533                 unset ($courses[$ix]);
00534                 continue;
00535             }
00536 
00537             // By this point, we should always have a $dataObj->id
00538             $local_courseid_array[] = $course['id'];
00539 
00540             // Do we have a record for this assignment?
00541             if ($userisregd) {
00542                 // Yes - we know about this one already
00543                 // We don't want to do updates because the new data is probably
00544                 // 'less complete' than the data we have.
00545             } else {
00546                 // No - create a record
00547                 $assignObj = new stdClass();
00548                 $assignObj->userid    = $userid;
00549                 $assignObj->hostid    = (int)$remoteclient->id;
00550                 $assignObj->remotecourseid = $course['remoteid'];
00551                 $assignObj->rolename  = $course['defaultrolename'];
00552                 $assignObj->id = $DB->insert_record('mnetservice_enrol_enrolments', $assignObj);
00553             }
00554         }
00555 
00556         // Clean up courses that the user is no longer enrolled in.
00557         if (!empty($local_courseid_array)) {
00558             $local_courseid_string = implode(', ', $local_courseid_array);
00559             $whereclause = " userid = ? AND hostid = ? AND remotecourseid NOT IN ($local_courseid_string)";
00560             $DB->delete_records_select('mnetservice_enrol_enrolments', $whereclause, array($userid, $remoteclient->id));
00561         }
00562     }
00563 
00564     function prevent_local_passwords() {
00565         return true;
00566     }
00567 
00573     function is_internal() {
00574         return false;
00575     }
00576 
00583     function can_change_password() {
00584         //TODO: it should be able to redirect, right?
00585         return false;
00586     }
00587 
00594     function change_password_url() {
00595         return null;
00596     }
00597 
00608     function config_form($config, $err, $user_fields) {
00609         global $CFG, $DB;
00610 
00611          $query = "
00612             SELECT
00613                 h.id,
00614                 h.name as hostname,
00615                 h.wwwroot,
00616                 h2idp.publish as idppublish,
00617                 h2idp.subscribe as idpsubscribe,
00618                 idp.name as idpname,
00619                 h2sp.publish as sppublish,
00620                 h2sp.subscribe as spsubscribe,
00621                 sp.name as spname
00622             FROM
00623                 {mnet_host} h
00624             LEFT JOIN
00625                 {mnet_host2service} h2idp
00626             ON
00627                (h.id = h2idp.hostid AND
00628                (h2idp.publish = 1 OR
00629                 h2idp.subscribe = 1))
00630             INNER JOIN
00631                 {mnet_service} idp
00632             ON
00633                (h2idp.serviceid = idp.id AND
00634                 idp.name = 'sso_idp')
00635             LEFT JOIN
00636                 {mnet_host2service} h2sp
00637             ON
00638                (h.id = h2sp.hostid AND
00639                (h2sp.publish = 1 OR
00640                 h2sp.subscribe = 1))
00641             INNER JOIN
00642                 {mnet_service} sp
00643             ON
00644                (h2sp.serviceid = sp.id AND
00645                 sp.name = 'sso_sp')
00646             WHERE
00647                ((h2idp.publish = 1 AND h2sp.subscribe = 1) OR
00648                (h2sp.publish = 1 AND h2idp.subscribe = 1)) AND
00649                 h.id != ?
00650             ORDER BY
00651                 h.name ASC";
00652 
00653         $id_providers       = array();
00654         $service_providers  = array();
00655         if ($resultset = $DB->get_records_sql($query, array($CFG->mnet_localhost_id))) {
00656             foreach($resultset as $hostservice) {
00657                 if(!empty($hostservice->idppublish) && !empty($hostservice->spsubscribe)) {
00658                     $service_providers[]= array('id' => $hostservice->id, 'name' => $hostservice->hostname, 'wwwroot' => $hostservice->wwwroot);
00659                 }
00660                 if(!empty($hostservice->idpsubscribe) && !empty($hostservice->sppublish)) {
00661                     $id_providers[]= array('id' => $hostservice->id, 'name' => $hostservice->hostname, 'wwwroot' => $hostservice->wwwroot);
00662                 }
00663             }
00664         }
00665 
00666         include "config.html";
00667     }
00668 
00672     function process_config($config) {
00673         // set to defaults if undefined
00674         if (!isset ($config->rpc_negotiation_timeout)) {
00675             $config->rpc_negotiation_timeout = '30';
00676         }
00677         /*
00678         if (!isset ($config->auto_add_remote_users)) {
00679             $config->auto_add_remote_users = '0';
00680         } See MDL-21327   for why this is commented out
00681         set_config('auto_add_remote_users',   $config->auto_add_remote_users,   'auth_mnet');
00682         */
00683 
00684         // save settings
00685         set_config('rpc_negotiation_timeout', $config->rpc_negotiation_timeout, 'auth_mnet');
00686 
00687         return true;
00688     }
00689 
00696     function keepalive_client() {
00697         global $CFG, $DB;
00698         $cutoff = time() - 300; // TODO - find out what the remote server's session
00699                                 // cutoff is, and preempt that
00700 
00701         $sql = "
00702             select
00703                 id,
00704                 username,
00705                 mnethostid
00706             from
00707                 {user}
00708             where
00709                 lastaccess > ? AND
00710                 mnethostid != ?
00711             order by
00712                 mnethostid";
00713 
00714         $immigrants = $DB->get_records_sql($sql, array($cutoff, $CFG->mnet_localhost_id));
00715 
00716         if ($immigrants == false) {
00717             return true;
00718         }
00719 
00720         $usersArray = array();
00721         foreach($immigrants as $immigrant) {
00722             $usersArray[$immigrant->mnethostid][] = $immigrant->username;
00723         }
00724 
00725         require_once $CFG->dirroot . '/mnet/xmlrpc/client.php';
00726         foreach($usersArray as $mnethostid => $users) {
00727             $mnet_peer = new mnet_peer();
00728             $mnet_peer->set_id($mnethostid);
00729 
00730             $mnet_request = new mnet_xmlrpc_client();
00731             $mnet_request->set_method('auth/mnet/auth.php/keepalive_server');
00732 
00733             // set $token and $useragent parameters
00734             $mnet_request->add_param($users);
00735 
00736             if ($mnet_request->send($mnet_peer) === true) {
00737                 if (!isset($mnet_request->response['code'])) {
00738                     debugging("Server side error has occured on host $mnethostid");
00739                     continue;
00740                 } elseif ($mnet_request->response['code'] > 0) {
00741                     debugging($mnet_request->response['message']);
00742                 }
00743 
00744                 if (!isset($mnet_request->response['last log id'])) {
00745                     debugging("Server side error has occured on host $mnethostid\nNo log ID was received.");
00746                     continue;
00747                 }
00748             } else {
00749                 debugging("Server side error has occured on host $mnethostid: " .
00750                           join("\n", $mnet_request->error));
00751                 break;
00752             }
00753             $mnethostlogssql = "
00754             SELECT
00755                 mhostlogs.remoteid, mhostlogs.time, mhostlogs.userid, mhostlogs.ip,
00756                 mhostlogs.course, mhostlogs.module, mhostlogs.cmid, mhostlogs.action,
00757                 mhostlogs.url, mhostlogs.info, mhostlogs.username, c.fullname as coursename,
00758                 c.modinfo
00759             FROM
00760                 (
00761                     SELECT
00762                         l.id as remoteid, l.time, l.userid, l.ip, l.course, l.module, l.cmid,
00763                         l.action, l.url, l.info, u.username
00764                     FROM
00765                         {user} u
00766                         INNER JOIN {log} l on l.userid = u.id
00767                     WHERE
00768                         u.mnethostid = ?
00769                         AND l.id > ?
00770                     ORDER BY remoteid ASC
00771                     LIMIT 500
00772                 ) mhostlogs
00773                 INNER JOIN {course} c on c.id = mhostlogs.course
00774             ORDER by mhostlogs.remoteid ASC";
00775 
00776             $mnethostlogs = $DB->get_records_sql($mnethostlogssql, array($mnethostid, $mnet_request->response['last log id']));
00777 
00778             if ($mnethostlogs == false) {
00779                 continue;
00780             }
00781 
00782             $processedlogs = array();
00783 
00784             foreach($mnethostlogs as $hostlog) {
00785                 // Extract the name of the relevant module instance from the
00786                 // course modinfo if possible.
00787                 if (!empty($hostlog->modinfo) && !empty($hostlog->cmid)) {
00788                     $modinfo = unserialize($hostlog->modinfo);
00789                     unset($hostlog->modinfo);
00790                     $modulearray = array();
00791                     foreach($modinfo as $module) {
00792                         $modulearray[$module->cm] = $module->name;
00793                     }
00794                     $hostlog->resource_name = $modulearray[$hostlog->cmid];
00795                 } else {
00796                     $hostlog->resource_name = '';
00797                 }
00798 
00799                 $processedlogs[] = array (
00800                                     'remoteid'      => $hostlog->remoteid,
00801                                     'time'          => $hostlog->time,
00802                                     'userid'        => $hostlog->userid,
00803                                     'ip'            => $hostlog->ip,
00804                                     'course'        => $hostlog->course,
00805                                     'coursename'    => $hostlog->coursename,
00806                                     'module'        => $hostlog->module,
00807                                     'cmid'          => $hostlog->cmid,
00808                                     'action'        => $hostlog->action,
00809                                     'url'           => $hostlog->url,
00810                                     'info'          => $hostlog->info,
00811                                     'resource_name' => $hostlog->resource_name,
00812                                     'username'      => $hostlog->username
00813                                  );
00814             }
00815 
00816             unset($hostlog);
00817 
00818             $mnet_request = new mnet_xmlrpc_client();
00819             $mnet_request->set_method('auth/mnet/auth.php/refresh_log');
00820 
00821             // set $token and $useragent parameters
00822             $mnet_request->add_param($processedlogs);
00823 
00824             if ($mnet_request->send($mnet_peer) === true) {
00825                 if ($mnet_request->response['code'] > 0) {
00826                     debugging($mnet_request->response['message']);
00827                 }
00828             } else {
00829                 debugging("Server side error has occured on host $mnet_peer->ip: " .join("\n", $mnet_request->error));
00830             }
00831         }
00832     }
00833 
00841     function refresh_log($array) {
00842         global $CFG, $DB;
00843         $remoteclient = get_mnet_remote_client();
00844 
00845         // We don't want to output anything to the client machine
00846         $start = ob_start();
00847 
00848         $returnString = '';
00849         $transaction = $DB->start_delegated_transaction();
00850         $useridarray = array();
00851 
00852         foreach($array as $logEntry) {
00853             $logEntryObj = (object)$logEntry;
00854             $logEntryObj->hostid = $remoteclient->id;
00855 
00856             if (isset($useridarray[$logEntryObj->username])) {
00857                 $logEntryObj->userid = $useridarray[$logEntryObj->username];
00858             } else {
00859                 $logEntryObj->userid = $DB->get_field('user', 'id', array('username'=>$logEntryObj->username, 'mnethostid'=>(int)$logEntryObj->hostid));
00860                 if ($logEntryObj->userid == false) {
00861                     $logEntryObj->userid = 0;
00862                 }
00863                 $useridarray[$logEntryObj->username] = $logEntryObj->userid;
00864             }
00865 
00866             unset($logEntryObj->username);
00867 
00868             $logEntryObj = $this->trim_logline($logEntryObj);
00869             $insertok = $DB->insert_record('mnet_log', $logEntryObj, false);
00870 
00871             if ($insertok) {
00872                 $remoteclient->last_log_id = $logEntryObj->remoteid;
00873             } else {
00874                 $returnString .= 'Record with id '.$logEntryObj->remoteid." failed to insert.\n";
00875             }
00876         }
00877         $remoteclient->commit();
00878         $transaction->allow_commit();
00879 
00880         $end = ob_end_clean();
00881 
00882         if (empty($returnString)) return array('code' => 0, 'message' => 'All ok');
00883         return array('code' => 1, 'message' => $returnString);
00884     }
00885 
00893     function keepalive_server($array) {
00894         global $CFG, $DB;
00895         $remoteclient = get_mnet_remote_client();
00896 
00897         // We don't want to output anything to the client machine
00898         $start = ob_start();
00899 
00900         // We'll get session records in batches of 30
00901         $superArray = array_chunk($array, 30);
00902 
00903         $returnString = '';
00904 
00905         foreach($superArray as $subArray) {
00906             $subArray = array_values($subArray);
00907             $instring = "('".implode("', '",$subArray)."')";
00908             $query = "select id, session_id, username from {mnet_session} where username in $instring";
00909             $results = $DB->get_records_sql($query);
00910 
00911             if ($results == false) {
00912                 // We seem to have a username that breaks our query:
00913                 // TODO: Handle this error appropriately
00914                 $returnString .= "We failed to refresh the session for the following usernames: \n".implode("\n", $subArray)."\n\n";
00915             } else {
00916                 foreach($results as $emigrant) {
00917                     session_touch($emigrant->session_id);
00918                 }
00919             }
00920         }
00921 
00922         $end = ob_end_clean();
00923 
00924         if (empty($returnString)) return array('code' => 0, 'message' => 'All ok', 'last log id' => $remoteclient->last_log_id);
00925         return array('code' => 1, 'message' => $returnString, 'last log id' => $remoteclient->last_log_id);
00926     }
00927 
00933     function cron() {
00934         global $DB;
00935 
00936         // run the keepalive client
00937         $this->keepalive_client();
00938 
00939         // admin/cron.php should have run srand for us
00940         $random100 = rand(0,100);
00941         if ($random100 < 10) {     // Approximately 10% of the time.
00942             // nuke olden sessions
00943             $longtime = time() - (1 * 3600 * 24);
00944             $DB->delete_records_select('mnet_session', "expires < ?", array($longtime));
00945         }
00946     }
00947 
00955     function prelogout_hook() {
00956         global $CFG, $USER;
00957 
00958         if (!is_enabled_auth('mnet')) {
00959             return;
00960         }
00961 
00962         // If the user is local to this Moodle:
00963         if ($USER->mnethostid == $this->mnet->id) {
00964             $this->kill_children($USER->username, sha1($_SERVER['HTTP_USER_AGENT']));
00965 
00966         // Else the user has hit 'logout' at a Service Provider Moodle:
00967         } else {
00968             $this->kill_parent($USER->username, sha1($_SERVER['HTTP_USER_AGENT']));
00969 
00970         }
00971     }
00972 
00980     function kill_parent($username, $useragent) {
00981         global $CFG, $USER, $DB;
00982 
00983         require_once $CFG->dirroot.'/mnet/xmlrpc/client.php';
00984         $sql = "
00985             select
00986                 *
00987             from
00988                 {mnet_session} s
00989             where
00990                 s.username   = ? AND
00991                 s.useragent  = ? AND
00992                 s.mnethostid = ?";
00993 
00994         $mnetsessions = $DB->get_records_sql($sql, array($username, $useragent, $USER->mnethostid));
00995 
00996         $ignore = $DB->delete_records('mnet_session',
00997                                  array('username'=>$username,
00998                                  'useragent'=>$useragent,
00999                                  'mnethostid'=>$USER->mnethostid));
01000 
01001         if (false != $mnetsessions) {
01002             $mnet_peer = new mnet_peer();
01003             $mnet_peer->set_id($USER->mnethostid);
01004 
01005             $mnet_request = new mnet_xmlrpc_client();
01006             $mnet_request->set_method('auth/mnet/auth.php/kill_children');
01007 
01008             // set $token and $useragent parameters
01009             $mnet_request->add_param($username);
01010             $mnet_request->add_param($useragent);
01011             if ($mnet_request->send($mnet_peer) === false) {
01012                 debugging(join("\n", $mnet_request->error));
01013                 return false;
01014             }
01015         }
01016 
01017         return true;
01018     }
01019 
01027     function kill_children($username, $useragent) {
01028         global $CFG, $USER, $DB;
01029         $remoteclient = null;
01030         if (defined('MNET_SERVER')) {
01031             $remoteclient = get_mnet_remote_client();
01032         }
01033         require_once $CFG->dirroot.'/mnet/xmlrpc/client.php';
01034 
01035         $userid = $DB->get_field('user', 'id', array('mnethostid'=>$CFG->mnet_localhost_id, 'username'=>$username));
01036 
01037         $returnstring = '';
01038 
01039         $mnetsessions = $DB->get_records('mnet_session', array('userid' => $userid, 'useragent' => $useragent));
01040 
01041         if (false == $mnetsessions) {
01042             $returnstring .= "Could find no remote sessions\n";
01043             $mnetsessions = array();
01044         }
01045 
01046         foreach($mnetsessions as $mnetsession) {
01047             // If this script is being executed by a remote peer, that means the user has clicked
01048             // logout on that peer, and the session on that peer can be deleted natively.
01049             // Skip over it.
01050             if (isset($remoteclient->id) && ($mnetsession->mnethostid == $remoteclient->id)) {
01051                 continue;
01052             }
01053             $returnstring .=  "Deleting session\n";
01054 
01055             $mnet_peer = new mnet_peer();
01056             $mnet_peer->set_id($mnetsession->mnethostid);
01057 
01058             $mnet_request = new mnet_xmlrpc_client();
01059             $mnet_request->set_method('auth/mnet/auth.php/kill_child');
01060 
01061             // set $token and $useragent parameters
01062             $mnet_request->add_param($username);
01063             $mnet_request->add_param($useragent);
01064             if ($mnet_request->send($mnet_peer) === false) {
01065                 debugging("Server side error has occured on host $mnetsession->mnethostid: " .
01066                           join("\n", $mnet_request->error));
01067             }
01068         }
01069 
01070         $ignore = $DB->delete_records('mnet_session',
01071                                  array('useragent'=>$useragent, 'userid'=>$userid));
01072 
01073         if (isset($remoteclient) && isset($remoteclient->id)) {
01074             session_kill_user($userid);
01075         }
01076         return $returnstring;
01077     }
01078 
01088     function kill_child($username, $useragent) {
01089         global $CFG, $DB;
01090         $remoteclient = get_mnet_remote_client();
01091         $session = $DB->get_record('mnet_session', array('username'=>$username, 'mnethostid'=>$remoteclient->id, 'useragent'=>$useragent));
01092         $DB->delete_records('mnet_session', array('username'=>$username, 'mnethostid'=>$remoteclient->id, 'useragent'=>$useragent));
01093         if (false != $session) {
01094             session_kill($session->session_id);
01095             return true;
01096         }
01097         return false;
01098     }
01099 
01107     function end_local_sessions(&$sessionArray) {
01108         global $CFG;
01109         if (is_array($sessionArray)) {
01110             while($session = array_pop($sessionArray)) {
01111                 session_kill($session->session_id);
01112             }
01113             return true;
01114         }
01115         return false;
01116     }
01117 
01134     function fetch_user_image($username) {
01135         global $CFG, $DB;
01136 
01137         if ($user = $DB->get_record('user', array('username' => $username, 'mnethostid' => $CFG->mnet_localhost_id))) {
01138             $fs = get_file_storage();
01139             $usercontext = get_context_instance(CONTEXT_USER, $user->id, MUST_EXIST);
01140             $return = array();
01141             if ($f1 = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f1.png')) {
01142                 $return['f1'] = base64_encode($f1->get_content());
01143                 $return['f1_mimetype'] = $f1->get_mimetype();
01144             } else if ($f1 = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f1.jpg')) {
01145                 $return['f1'] = base64_encode($f1->get_content());
01146                 $return['f1_mimetype'] = $f1->get_mimetype();
01147             }
01148             if ($f2 = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f2.png')) {
01149                 $return['f2'] = base64_encode($f2->get_content());
01150                 $return['f2_mimetype'] = $f2->get_mimetype();
01151             } else if ($f2 = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f2.jpg')) {
01152                 $return['f2'] = base64_encode($f2->get_content());
01153                 $return['f2_mimetype'] = $f2->get_mimetype();
01154             }
01155             return $return;
01156         }
01157         return false;
01158     }
01159 
01165     function fetch_theme_info() {
01166         global $CFG;
01167 
01168         $themename = "$CFG->theme";
01169         $logourl   = "$CFG->wwwroot/theme/$CFG->theme/images/logo.jpg";
01170 
01171         $return['themename'] = $themename;
01172         $return['logourl'] = $logourl;
01173         return $return;
01174     }
01175 
01183     function has_service($mnethostid, $servicename) {
01184         global $CFG, $DB;
01185 
01186         $sql = "
01187             SELECT
01188                 svc.id as serviceid,
01189                 svc.name,
01190                 svc.description,
01191                 svc.offer,
01192                 svc.apiversion,
01193                 h2s.id as h2s_id
01194             FROM
01195                 {mnet_host} h,
01196                 {mnet_service} svc,
01197                 {mnet_host2service} h2s
01198             WHERE
01199                 h.deleted = '0' AND
01200                 h.id = h2s.hostid AND
01201                 h2s.hostid = ? AND
01202                 h2s.serviceid = svc.id AND
01203                 svc.name = ? AND
01204                 h2s.subscribe = '1'";
01205 
01206         return $DB->get_records_sql($sql, array($mnethostid, $servicename));
01207     }
01208 
01217     function can_login_remotely($username, $mnethostid) {
01218         global $DB;
01219 
01220         $accessctrl = 'allow';
01221         $aclrecord = $DB->get_record('mnet_sso_access_control', array('username'=>$username, 'mnet_host_id'=>$mnethostid));
01222         if (!empty($aclrecord)) {
01223             $accessctrl = $aclrecord->accessctrl;
01224         }
01225         return $accessctrl == 'allow';
01226     }
01227 
01228     function logoutpage_hook() {
01229         global $USER, $CFG, $redirect, $DB;
01230 
01231         if (!empty($USER->mnethostid) and $USER->mnethostid != $CFG->mnet_localhost_id) {
01232             $host = $DB->get_record('mnet_host', array('id'=>$USER->mnethostid));
01233             $redirect = $host->wwwroot.'/';
01234         }
01235     }
01236 
01243     function trim_logline ($logline) {
01244         $limits = array('ip' => 15, 'coursename' => 40, 'module' => 20, 'action' => 40,
01245                         'url' => 255);
01246         foreach ($limits as $property => $limit) {
01247             if (isset($logline->$property)) {
01248                 $logline->$property = substr($logline->$property, 0, $limit);
01249             }
01250         }
01251 
01252         return $logline;
01253     }
01254 
01270     function loginpage_idp_list($wantsurl) {
01271         global $DB, $CFG;
01272 
01273         // strip off wwwroot, since the remote site will prefix it's return url with this
01274         $wantsurl = preg_replace('/(' . preg_quote($CFG->wwwroot, '/') . '|' . preg_quote($CFG->httpswwwroot, '/') . ')/', '', $wantsurl);
01275 
01276         $sql = "SELECT DISTINCT h.id, h.wwwroot, h.name, a.sso_jump_url, a.name as application
01277                   FROM {mnet_host} h
01278                   JOIN {mnet_host2service} m ON h.id = m.hostid
01279                   JOIN {mnet_service} s ON s.id = m.serviceid
01280                   JOIN {mnet_application} a ON h.applicationid = a.id
01281                  WHERE s.name = ? AND h.deleted = ? AND m.publish = ?";
01282         $params = array('sso_sp', 0, 1);
01283 
01284         if (!empty($CFG->mnet_all_hosts_id)) {
01285             $sql .= " AND h.id <> ?";
01286             $params[] = $CFG->mnet_all_hosts_id;
01287         }
01288 
01289         if (!$hosts = $DB->get_records_sql($sql, $params)) {
01290             return array();
01291         }
01292 
01293         $idps = array();
01294         foreach ($hosts as $host) {
01295             $idps[] = array(
01296                 'url'  => new moodle_url($host->wwwroot . $host->sso_jump_url, array('hostwwwroot' => $CFG->wwwroot, 'wantsurl' => $wantsurl, 'remoteurl' => 1)),
01297                 'icon' => new pix_icon('i/' . $host->application . '_host', $host->name),
01298                 'name' => $host->name,
01299             );
01300         }
01301         return $idps;
01302     }
01303 }
 All Data Structures Namespaces Files Functions Variables Enumerations