auth/mnet - MDL-16872 Fix incorrect use of clone() on arrays
[moodle.git] / auth / mnet / auth.php
CommitLineData
6817efbc 1<?php // $Id$
c72fe801 2
3/**
4 * @author Martin Dougiamas
5 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
6 * @package moodle multiauth
7 *
8 * Authentication Plugin: Moodle Network Authentication
9 *
10 * Multiple host authentication support for Moodle Network.
11 *
12 * 2006-11-01 File created.
13 */
14
139ebfdb 15if (!defined('MOODLE_INTERNAL')) {
16 die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
c72fe801 17}
18
6bc1e5d5 19require_once($CFG->libdir.'/authlib.php');
20
c72fe801 21/**
22 * Moodle Network authentication plugin.
23 */
6bc1e5d5 24class auth_plugin_mnet extends auth_plugin_base {
c72fe801 25
26 /**
27 * Constructor.
28 */
29 function auth_plugin_mnet() {
6bc1e5d5 30 $this->authtype = 'mnet';
c72fe801 31 $this->config = get_config('auth/mnet');
32 }
33
34 /**
35 * Provides the allowed RPC services from this class as an array.
36 * @return array Allowed RPC services.
37 */
38 function mnet_publishes() {
39
40 $sso_idp = array();
41 $sso_idp['name'] = 'sso_idp'; // Name & Description go in lang file
42 $sso_idp['apiversion'] = 1;
139ebfdb 43 $sso_idp['methods'] = array('user_authorise','keepalive_server', 'kill_children',
44 'refresh_log', 'fetch_user_image', 'fetch_theme_info',
62d78bf5 45 'update_enrolments');
c72fe801 46
47 $sso_sp = array();
48 $sso_sp['name'] = 'sso_sp'; // Name & Description go in lang file
49 $sso_sp['apiversion'] = 1;
0a127169 50 $sso_sp['methods'] = array('keepalive_client','kill_child');
c72fe801 51
52 return array($sso_idp, $sso_sp);
53 }
54
55 /**
56 * This function is normally used to determine if the username and password
57 * are correct for local logins. Always returns false, as local users do not
58 * need to login over mnet xmlrpc.
59 *
60 * @param string $username The username
61 * @param string $password The password
139ebfdb 62 * @return bool Authentication success or failure.
c72fe801 63 */
64 function user_login($username, $password) {
3db241b3 65 return false; // print_error("mnetlocal");
c72fe801 66 }
67
68 /**
69 * Return user data for the provided token, compare with user_agent string.
70 *
71 * @param string $token The unique ID provided by remotehost.
72 * @param string $UA User Agent string.
73 * @return array $userdata Array of user info for remote host
74 */
75 function user_authorise($token, $useragent) {
7b0d12b2 76 global $CFG, $MNET, $SITE, $MNET_REMOTE_CLIENT, $DB;
c72fe801 77 require_once $CFG->dirroot . '/mnet/xmlrpc/server.php';
78
7b0d12b2 79 $mnet_session = $DB->get_record('mnet_session', array('token'=>$token, 'useragent'=>$useragent));
c72fe801 80 if (empty($mnet_session)) {
81 echo mnet_server_fault(1, get_string('authfail_nosessionexists', 'mnet'));
82 exit;
83 }
84
85 // check session confirm timeout
86 if ($mnet_session->confirm_timeout < time()) {
87 echo mnet_server_fault(2, get_string('authfail_sessiontimedout', 'mnet'));
88 exit;
89 }
90
91 // session okay, try getting the user
7b0d12b2 92 if (!$user = $DB->get_record('user', array('id'=>$mnet_session->userid))) {
c72fe801 93 echo mnet_server_fault(3, get_string('authfail_usermismatch', 'mnet'));
94 exit;
95 }
96
97 $userdata = array();
98 $userdata['username'] = $user->username;
99 $userdata['email'] = $user->email;
100 $userdata['auth'] = 'mnet';
101 $userdata['confirmed'] = $user->confirmed;
102 $userdata['deleted'] = $user->deleted;
103 $userdata['firstname'] = $user->firstname;
104 $userdata['lastname'] = $user->lastname;
105 $userdata['city'] = $user->city;
106 $userdata['country'] = $user->country;
107 $userdata['lang'] = $user->lang;
108 $userdata['timezone'] = $user->timezone;
109 $userdata['description'] = $user->description;
110 $userdata['mailformat'] = $user->mailformat;
111 $userdata['maildigest'] = $user->maildigest;
112 $userdata['maildisplay'] = $user->maildisplay;
113 $userdata['htmleditor'] = $user->htmleditor;
114 $userdata['wwwroot'] = $MNET->wwwroot;
115 $userdata['session.gc_maxlifetime'] = ini_get('session.gc_maxlifetime');
116 $userdata['picture'] = $user->picture;
117 if (!empty($user->picture)) {
56a1a882 118 $imagefile = make_user_directory($user->id, true) . "/f1.jpg";
c72fe801 119 if (file_exists($imagefile)) {
120 $userdata['imagehash'] = sha1(file_get_contents($imagefile));
121 }
122 }
4d8c087e 123
124 $userdata['myhosts'] = array();
125 if($courses = get_my_courses($user->id, 'id', 'id, visible')) {
126 $userdata['myhosts'][] = array('name'=> $SITE->shortname, 'url' => $CFG->wwwroot, 'count' => count($courses));
127 }
128
129 $sql = "
130 SELECT
131 h.name as hostname,
132 h.wwwroot,
133 h.id as hostid,
134 count(c.id) as count
139ebfdb 135 FROM
7b0d12b2 136 {mnet_enrol_course} c,
137 {mnet_enrol_assignments} a,
138 {mnet_host} h
4d8c087e 139 WHERE
140 c.id = a.courseid AND
141 c.hostid = h.id AND
7b0d12b2 142 a.userid = ? AND
143 c.hostid != ?
4d8c087e 144 GROUP BY
145 h.name,
146 h.id,
147 h.wwwroot";
7b0d12b2 148 if ($courses = $DB->get_records_sql($sql, array($user->id, $MNET_REMOTE_CLIENT->id))) {
4d8c087e 149 foreach($courses as $course) {
150 $userdata['myhosts'][] = array('name'=> $course->hostname, 'url' => $CFG->wwwroot.'/auth/mnet/jump.php?hostid='.$course->hostid, 'count' => $course->count);
151 }
152 }
153
c72fe801 154 return $userdata;
155 }
156
157 /**
158 * Generate a random string for use as an RPC session token.
159 */
160 function generate_token() {
161 return sha1(str_shuffle('' . mt_rand() . time()));
162 }
163
164 /**
165 * Starts an RPC jump session and returns the jump redirect URL.
d9be2106 166 *
167 * @param int $mnethostid id of the mnet host to jump to
168 * @param string $wantsurl url to redirect to after the jump (usually on remote system)
169 * @param boolean $wantsurlbackhere defaults to false, means that the remote system should bounce us back here
170 * rather than somewhere inside *its* wwwroot
c72fe801 171 */
d9be2106 172 function start_jump_session($mnethostid, $wantsurl, $wantsurlbackhere=false) {
7b0d12b2 173 global $CFG, $USER, $MNET, $DB;
c72fe801 174 require_once $CFG->dirroot . '/mnet/xmlrpc/client.php';
175
176 // check remote login permissions
957f6fc9 177 if (! has_capability('moodle/site:mnetlogintoremote', get_context_instance(CONTEXT_SYSTEM))
c72fe801 178 or is_mnet_remote_user($USER)
179 or $USER->username == 'guest'
180 or empty($USER->id)) {
5a2a5331 181 print_error('notpermittedtojump', 'mnet');
c72fe801 182 }
183
184 // check for SSO publish permission first
185 if ($this->has_service($mnethostid, 'sso_sp') == false) {
5a2a5331 186 print_error('hostnotconfiguredforsso', 'mnet');
c72fe801 187 }
188
189 // set RPC timeout to 30 seconds if not configured
190 // TODO: Is this needed/useful/problematic?
191 if (empty($this->config->rpc_negotiation_timeout)) {
192 set_config('rpc_negotiation_timeout', '30', 'auth/mnet');
193 }
194
195 // get the host info
196 $mnet_peer = new mnet_peer();
197 $mnet_peer->set_id($mnethostid);
198
199 // set up the session
7b0d12b2 200 $mnet_session = $DB->get_record('mnet_session',
201 array('userid'=>$USER->id, 'mnethostid'=>$mnethostid,
202 'useragent'=>sha1($_SERVER['HTTP_USER_AGENT'])));
c72fe801 203 if ($mnet_session == false) {
204 $mnet_session = new object();
205 $mnet_session->mnethostid = $mnethostid;
206 $mnet_session->userid = $USER->id;
207 $mnet_session->username = $USER->username;
208 $mnet_session->useragent = sha1($_SERVER['HTTP_USER_AGENT']);
209 $mnet_session->token = $this->generate_token();
210 $mnet_session->confirm_timeout = time() + $this->config->rpc_negotiation_timeout;
211 $mnet_session->expires = time() + (integer)ini_get('session.gc_maxlifetime');
212 $mnet_session->session_id = session_id();
979425b5 213 $mnet_session->id = $DB->insert_record('mnet_session', $mnet_session);
c72fe801 214 } else {
215 $mnet_session->useragent = sha1($_SERVER['HTTP_USER_AGENT']);
216 $mnet_session->token = $this->generate_token();
217 $mnet_session->confirm_timeout = time() + $this->config->rpc_negotiation_timeout;
218 $mnet_session->expires = time() + (integer)ini_get('session.gc_maxlifetime');
219 $mnet_session->session_id = session_id();
979425b5 220 $DB->update_record('mnet_session', $mnet_session);
c72fe801 221 }
222
223 // construct the redirection URL
224 //$transport = mnet_get_protocol($mnet_peer->transport);
225 $wantsurl = urlencode($wantsurl);
25202581 226 $url = "{$mnet_peer->wwwroot}{$mnet_peer->application->sso_land_url}?token={$mnet_session->token}&idp={$MNET->wwwroot}&wantsurl={$wantsurl}";
d9be2106 227 if ($wantsurlbackhere) {
228 $url .= '&remoteurl=1';
229 }
c72fe801 230
231 return $url;
232 }
233
234 /**
235 * This function confirms the remote (ID provider) host's mnet session
236 * by communicating the token and UA over the XMLRPC transport layer, and
237 * returns the local user record on success.
238 *
239 * @param string $token The random session token.
240 * @param string $remotewwwroot The ID provider wwwroot.
139ebfdb 241 * @return array The local user record.
c72fe801 242 */
243 function confirm_mnet_session($token, $remotewwwroot) {
a5d424df 244 global $CFG, $MNET, $SESSION, $DB;
c72fe801 245 require_once $CFG->dirroot . '/mnet/xmlrpc/client.php';
246
247 // verify the remote host is configured locally before attempting RPC call
dbca4e44 248 if (! $remotehost = $DB->get_record('mnet_host', array('wwwroot' => $remotewwwroot, 'deleted' => 0))) {
5a2a5331 249 print_error('notpermittedtoland', 'mnet');
c72fe801 250 }
251
252 // get the originating (ID provider) host info
253 $remotepeer = new mnet_peer();
254 $remotepeer->set_wwwroot($remotewwwroot);
255
256 // set up the RPC request
257 $mnetrequest = new mnet_xmlrpc_client();
258 $mnetrequest->set_method('auth/mnet/auth.php/user_authorise');
259
260 // set $token and $useragent parameters
261 $mnetrequest->add_param($token);
262 $mnetrequest->add_param(sha1($_SERVER['HTTP_USER_AGENT']));
263
264 // Thunderbirds are go! Do RPC call and store response
265 if ($mnetrequest->send($remotepeer) === true) {
266 $remoteuser = (object) $mnetrequest->response;
267 } else {
016bac47 268 foreach ($mnetrequest->error as $errormessage) {
269 list($code, $message) = array_map('trim',explode(':', $errormessage, 2));
270 if($code == 702) {
271 $site = get_site();
5a2a5331 272 print_error('mnet_session_prohibited', 'mnet', $remotewwwroot, format_string($site->fullname));
016bac47 273 exit;
274 }
71502268 275 $message .= "ERROR $code:<br/>$errormessage<br/>";
c72fe801 276 }
e2490433 277 print_error("rpcerror", '', '', $message);
c72fe801 278 }
15e47723 279 unset($mnetrequest);
c72fe801 280
281 if (empty($remoteuser) or empty($remoteuser->username)) {
016bac47 282 print_error('unknownerror', 'mnet');
283 exit;
c72fe801 284 }
285
15e47723 286 $firsttime = false;
287
c72fe801 288 // get the local record for the remote user
7b0d12b2 289 $localuser = $DB->get_record('user', array('username'=>$remoteuser->username, 'mnethostid'=>$remotehost->id));
c72fe801 290
291 // add the remote user to the database if necessary, and if allowed
292 // TODO: refactor into a separate function
32d651c8 293 if (empty($localuser) || ! $localuser->id) {
c72fe801 294 if (empty($this->config->auto_add_remote_users)) {
5a2a5331 295 print_error('nolocaluser', 'mnet');
c72fe801 296 }
297 $remoteuser->mnethostid = $remotehost->id;
979425b5 298 $DB->insert_record('user', $remoteuser);
15e47723 299 $firsttime = true;
7b0d12b2 300 if (! $localuser = $DB->get_record('user', array('username'=>$remoteuser->username, 'mnethostid'=>$remotehost->id))) {
5a2a5331 301 print_error('nolocaluser', 'mnet');
c72fe801 302 }
303 }
304
305 // check sso access control list for permission first
306 if (!$this->can_login_remotely($localuser->username, $remotehost->id)) {
573f8b02 307 print_error('sso_mnet_login_refused', 'mnet', '', array($localuser->username, $remotehost->name));
c72fe801 308 }
309
310 $session_gc_maxlifetime = 1440;
311
312 // update the local user record with remote user data
313 foreach ((array) $remoteuser as $key => $val) {
314 if ($key == 'session.gc_maxlifetime') {
315 $session_gc_maxlifetime = $val;
316 continue;
317 }
318
319 // TODO: fetch image if it has changed
320 if ($key == 'imagehash') {
56a1a882 321 $dirname = make_user_directory($localuser->id, true);
c72fe801 322 $filename = "$dirname/f1.jpg";
323
324 $localhash = '';
325 if (file_exists($filename)) {
326 $localhash = sha1(file_get_contents($filename));
327 } elseif (!file_exists($dirname)) {
328 mkdir($dirname);
329 }
330
331 if ($localhash != $val) {
332 // fetch image from remote host
333 $fetchrequest = new mnet_xmlrpc_client();
334 $fetchrequest->set_method('auth/mnet/auth.php/fetch_user_image');
335 $fetchrequest->add_param($localuser->username);
336 if ($fetchrequest->send($remotepeer) === true) {
337 if (strlen($fetchrequest->response['f1']) > 0) {
338 $imagecontents = base64_decode($fetchrequest->response['f1']);
339 file_put_contents($filename, $imagecontents);
25202581 340 $localuser->picture = 1;
c72fe801 341 }
342 if (strlen($fetchrequest->response['f2']) > 0) {
343 $imagecontents = base64_decode($fetchrequest->response['f2']);
344 file_put_contents($dirname.'/f2.jpg', $imagecontents);
345 }
346 }
347 }
348 }
349
4d8c087e 350 if($key == 'myhosts') {
0743661e 351 $localuser->mnet_foreign_host_array = array();
15e47723 352 foreach($val as $rhost) {
353 $name = clean_param($rhost['name'], PARAM_ALPHANUM);
354 $url = clean_param($rhost['url'], PARAM_URL);
355 $count = clean_param($rhost['count'], PARAM_INT);
4d8c087e 356 $url_is_local = stristr($url , $CFG->wwwroot);
357 if (!empty($name) && !empty($count) && empty($url_is_local)) {
139ebfdb 358 $localuser->mnet_foreign_host_array[] = array('name' => $name,
359 'url' => $url,
0743661e 360 'count' => $count);
4d8c087e 361 }
362 }
363 }
364
c72fe801 365 $localuser->{$key} = $val;
366 }
367
368 $localuser->mnethostid = $remotepeer->id;
369
a8c31db2 370 $DB->update_record('user', $localuser);
c72fe801 371
372 // set up the session
7b0d12b2 373 $mnet_session = $DB->get_record('mnet_session',
374 array('userid'=>$localuser->id, 'mnethostid'=>$remotepeer->id,
375 'useragent'=>sha1($_SERVER['HTTP_USER_AGENT'])));
c72fe801 376 if ($mnet_session == false) {
377 $mnet_session = new object();
378 $mnet_session->mnethostid = $remotepeer->id;
379 $mnet_session->userid = $localuser->id;
380 $mnet_session->username = $localuser->username;
381 $mnet_session->useragent = sha1($_SERVER['HTTP_USER_AGENT']);
4e047727 382 $mnet_session->token = $token; // Needed to support simultaneous sessions
383 // and preserving DB rec uniqueness
c72fe801 384 $mnet_session->confirm_timeout = time();
385 $mnet_session->expires = time() + (integer)$session_gc_maxlifetime;
386 $mnet_session->session_id = session_id();
979425b5 387 $mnet_session->id = $DB->insert_record('mnet_session', $mnet_session);
c72fe801 388 } else {
389 $mnet_session->expires = time() + (integer)$session_gc_maxlifetime;
7b0d12b2 390 $DB->update_record('mnet_session', $mnet_session);
c72fe801 391 }
392
15e47723 393 if (!$firsttime) {
394 // repeat customer! let the IDP know about enrolments
139ebfdb 395 // we have for this user.
15e47723 396 // set up the RPC request
397 $mnetrequest = new mnet_xmlrpc_client();
398 $mnetrequest->set_method('auth/mnet/auth.php/update_enrolments');
399
400 // pass username and an assoc array of "my courses"
401 // with info so that the IDP can maintain mnet_enrol_assignments
402 $mnetrequest->add_param($remoteuser->username);
139ebfdb 403 $fields = 'id, category, sortorder, fullname, shortname, idnumber, summary,
15e47723 404 startdate, cost, currency, defaultrole, visible';
405 $courses = get_my_courses($localuser->id, 'visible DESC,sortorder ASC', $fields);
406 if (is_array($courses) && !empty($courses)) {
407 // Second request to do the JOINs that we'd have done
408 // inside get_my_courses() if we had been allowed
139ebfdb 409 $sql = "SELECT c.id,
15e47723 410 cc.name AS cat_name, cc.description AS cat_description,
411 r.shortname as defaultrolename
7b0d12b2 412 FROM {course} c
413 JOIN {course_categories} cc ON c.category = cc.id
414 LEFT OUTER JOIN {role} r ON c.defaultrole = r.id
415 WHERE c.id IN (" . join(',',array_keys($courses)) . ')';
416 $extra = $DB->get_records_sql($sql);
15e47723 417
418 $keys = array_keys($courses);
a5d424df 419 $defaultrolename = $DB->get_field('role', 'shortname', array('id'=>$CFG->defaultcourseroleid));
15e47723 420 foreach ($keys AS $id) {
573f8b02 421 if ($courses[$id]->visible == 0) {
422 unset($courses[$id]);
423 continue;
424 }
560b3acc 425 $courses[$id]->cat_id = $courses[$id]->category;
426 $courses[$id]->defaultroleid = $courses[$id]->defaultrole;
573f8b02 427 unset($courses[$id]->category);
428 unset($courses[$id]->defaultrole);
429 unset($courses[$id]->visible);
430
15e47723 431 $courses[$id]->cat_name = $extra[$id]->cat_name;
432 $courses[$id]->cat_description = $extra[$id]->cat_description;
433 if (!empty($extra[$id]->defaultrolename)) {
434 $courses[$id]->defaultrolename = $extra[$id]->defaultrolename;
435 } else {
436 $courses[$id]->defaultrolename = $defaultrolename;
437 }
438 // coerce to array
439 $courses[$id] = (array)$courses[$id];
440 }
62d78bf5 441 } else {
442 // if the array is empty, send it anyway
443 // we may be clearing out stale entries
139ebfdb 444 $courses = array();
62d78bf5 445 }
446 $mnetrequest->add_param($courses);
15e47723 447
62d78bf5 448 // Call 0800-RPC Now! -- we don't care too much if it fails
449 // as it's just informational.
450 if ($mnetrequest->send($remotepeer) === false) {
451 // error_log(print_r($mnetrequest->error,1));
15e47723 452 }
453 }
454
c72fe801 455 return $localuser;
456 }
457
62d78bf5 458 /**
459 * Invoke this function _on_ the IDP to update it with enrolment info local to
460 * the SP right after calling user_authorise()
461 *
462 * Normally called by the SP after calling
463 *
464 * @param string $username The username
465 * @param string $courses Assoc array of courses following the structure of mnet_enrol_course
139ebfdb 466 * @return bool
62d78bf5 467 */
468 function update_enrolments($username, $courses) {
8618fd2a 469 global $MNET_REMOTE_CLIENT, $CFG, $DB;
62d78bf5 470
471 if (empty($username) || !is_array($courses)) {
472 return false;
473 }
474 // make sure it is a user we have an in active session
475 // with that host...
7b0d12b2 476 $userid = $DB->get_field('mnet_session', 'userid',
477 array('username'=>$username, 'mnethostid'=>$MNET_REMOTE_CLIENT->id));
62d78bf5 478 if (!$userid) {
479 return false;
480 }
481
482 if (empty($courses)) { // no courses? clear out quickly
8618fd2a 483 $DB->delete_records('mnet_enrol_assignments', array('hostid'=>$MNET_REMOTE_CLIENT->id, 'userid'=>$userid));
62d78bf5 484 return true;
485 }
486
573f8b02 487 // IMPORTANT: Ask for remoteid as the first element in the query, so
488 // that the array that comes back is indexed on the same field as the
489 // array that we have received from the remote client
490 $sql = '
491 SELECT
492 c.remoteid,
493 c.id,
494 c.cat_id,
495 c.cat_name,
496 c.cat_description,
497 c.sortorder,
498 c.fullname,
499 c.shortname,
500 c.idnumber,
501 c.summary,
502 c.startdate,
503 c.cost,
504 c.currency,
505 c.defaultroleid,
506 c.defaultrolename,
507 a.id as assignmentid
508 FROM
7b0d12b2 509 {mnet_enrol_course} c
510 LEFT JOIN {mnet_enrol_assignments} a
573f8b02 511 ON
512 (a.courseid = c.id AND
513 a.hostid = c.hostid AND
7b0d12b2 514 a.userid = ?)
573f8b02 515 WHERE
7b0d12b2 516 c.hostid = ?';
573f8b02 517
7b0d12b2 518 $currentcourses = $DB->get_records_sql($sql, array($userid, $MNET_REMOTE_CLIENT->id));
573f8b02 519
520 $local_courseid_array = array();
521 foreach($courses as $course) {
522
523 $course['remoteid'] = $course['id'];
524 $course['hostid'] = (int)$MNET_REMOTE_CLIENT->id;
525 $userisregd = false;
526
527 // First up - do we have a record for this course?
528 if (!array_key_exists($course['remoteid'], $currentcourses)) {
529 // No record - we must create it
7b0d12b2 530 $course['id'] = $DB->insert_record('mnet_enrol_course', (object)$course);
573f8b02 531 $currentcourse = (object)$course;
532 } else {
533 // Pointer to current course:
534 $currentcourse =& $currentcourses[$course['remoteid']];
535 // We have a record - is it up-to-date?
536 $course['id'] = $currentcourse->id;
537
538 $saveflag = false;
539
540 foreach($course as $key => $value) {
541 if ($currentcourse->$key != $value) {
542 $saveflag = true;
543 $currentcourse->$key = $value;
544 }
545 }
546
547 if ($saveflag) {
7b0d12b2 548 $DB->update_record('mnet_enrol_course', $currentcourse);
573f8b02 549 }
139ebfdb 550
573f8b02 551 if (isset($currentcourse->assignmentid) && is_numeric($currentcourse->assignmentid)) {
552 $userisregd = true;
553 }
554 }
555
556 // By this point, we should always have a $dataObj->id
557 $local_courseid_array[] = $course['id'];
558
559 // Do we have a record for this assignment?
560 if ($userisregd) {
561 // Yes - we know about this one already
562 // We don't want to do updates because the new data is probably
563 // 'less complete' than the data we have.
564 } else {
565 // No - create a record
566 $assignObj = new stdClass();
567 $assignObj->userid = $userid;
568 $assignObj->hostid = (int)$MNET_REMOTE_CLIENT->id;
569 $assignObj->courseid = $course['id'];
570 $assignObj->rolename = $course['defaultrolename'];
7b0d12b2 571 $assignObj->id = $DB->insert_record('mnet_enrol_assignments', $assignObj);
573f8b02 572 }
573 }
62d78bf5 574
573f8b02 575 // Clean up courses that the user is no longer enrolled in.
576 $local_courseid_string = implode(', ', $local_courseid_array);
7b0d12b2 577 $whereclause = " userid = ? AND hostid = ? AND courseid NOT IN ($local_courseid_string)";
578 $DB->delete_records_select('mnet_enrol_assignments', $whereclause, array($userid, $MNET_REMOTE_CLIENT->id));
62d78bf5 579 }
580
c72fe801 581 /**
582 * Returns true if this authentication plugin is 'internal'.
583 *
139ebfdb 584 * @return bool
c72fe801 585 */
586 function is_internal() {
587 return false;
588 }
589
590 /**
591 * Returns true if this authentication plugin can change the user's
592 * password.
593 *
139ebfdb 594 * @return bool
c72fe801 595 */
596 function can_change_password() {
430759a5 597 //TODO: it should be able to redirect, right?
c72fe801 598 return false;
599 }
600
601 /**
602 * Returns the URL for changing the user's pw, or false if the default can
603 * be used.
604 *
430759a5 605 * @return string
c72fe801 606 */
607 function change_password_url() {
430759a5 608 return '';
c72fe801 609 }
610
611 /**
612 * Prints a form for configuring this authentication plugin.
613 *
614 * This function is called from admin/auth.php, and outputs a full page with
615 * a form for configuring this plugin.
616 *
617 * @param array $page An object containing all the data for this page.
618 */
139ebfdb 619 function config_form($config, $err, $user_fields) {
7b0d12b2 620 global $CFG, $DB;
14518364 621
622 $query = "
623 SELECT
624 h.id,
625 h.name as hostname,
626 h.wwwroot,
627 h2idp.publish as idppublish,
628 h2idp.subscribe as idpsubscribe,
629 idp.name as idpname,
630 h2sp.publish as sppublish,
631 h2sp.subscribe as spsubscribe,
632 sp.name as spname
633 FROM
7b0d12b2 634 {mnet_host} h
14518364 635 LEFT JOIN
7b0d12b2 636 {mnet_host2service} h2idp
14518364 637 ON
638 (h.id = h2idp.hostid AND
639 (h2idp.publish = 1 OR
640 h2idp.subscribe = 1))
641 INNER JOIN
7b0d12b2 642 {mnet_service} idp
14518364 643 ON
644 (h2idp.serviceid = idp.id AND
645 idp.name = 'sso_idp')
646 LEFT JOIN
7b0d12b2 647 {mnet_host2service} h2sp
14518364 648 ON
649 (h.id = h2sp.hostid AND
650 (h2sp.publish = 1 OR
651 h2sp.subscribe = 1))
652 INNER JOIN
7b0d12b2 653 {mnet_service} sp
14518364 654 ON
655 (h2sp.serviceid = sp.id AND
656 sp.name = 'sso_sp')
657 WHERE
658 ((h2idp.publish = 1 AND h2sp.subscribe = 1) OR
659 (h2sp.publish = 1 AND h2idp.subscribe = 1)) AND
7b0d12b2 660 h.id != ?
14518364 661 ORDER BY
662 h.name ASC";
663
14518364 664 $id_providers = array();
665 $service_providers = array();
7b0d12b2 666 if ($resultset = $DB->get_records_sql($query, array($CFG->mnet_localhost_id))) {
d525ca25 667 foreach($resultset as $hostservice) {
668 if(!empty($hostservice->idppublish) && !empty($hostservice->spsubscribe)) {
669 $service_providers[]= array('id' => $hostservice->id, 'name' => $hostservice->hostname, 'wwwroot' => $hostservice->wwwroot);
670 }
671 if(!empty($hostservice->idpsubscribe) && !empty($hostservice->sppublish)) {
672 $id_providers[]= array('id' => $hostservice->id, 'name' => $hostservice->hostname, 'wwwroot' => $hostservice->wwwroot);
673 }
14518364 674 }
675 }
139ebfdb 676
c72fe801 677 include "config.html";
678 }
679
680 /**
681 * Processes and stores configuration data for this authentication plugin.
682 */
683 function process_config($config) {
684 // set to defaults if undefined
685 if (!isset ($config->rpc_negotiation_timeout)) {
5671e77f 686 $config->rpc_negotiation_timeout = '30';
c72fe801 687 }
688 if (!isset ($config->auto_add_remote_users)) {
689 $config->auto_add_remote_users = '0';
690 }
691
692 // save settings
693 set_config('rpc_negotiation_timeout', $config->rpc_negotiation_timeout, 'auth/mnet');
694 set_config('auto_add_remote_users', $config->auto_add_remote_users, 'auth/mnet');
695
696 return true;
697 }
698
699 /**
700 * Poll the IdP server to let it know that a user it has authenticated is still
701 * online
702 *
703 * @return void
704 */
705 function keepalive_client() {
7b0d12b2 706 global $CFG, $MNET, $DB;
c72fe801 707 $cutoff = time() - 300; // TODO - find out what the remote server's session
708 // cutoff is, and preempt that
709
710 $sql = "
711 select
712 id,
713 username,
714 mnethostid
715 from
7b0d12b2 716 {user}
c72fe801 717 where
7b0d12b2 718 lastaccess > ? AND
719 mnethostid != ?
c72fe801 720 order by
721 mnethostid";
722
7b0d12b2 723 $immigrants = $DB->get_records_sql($sql, array($cutoff, $CFG->mnet_localhost_id));
c72fe801 724
725 if ($immigrants == false) {
726 return true;
727 }
728
729 $usersArray = array();
730 foreach($immigrants as $immigrant) {
731 $usersArray[$immigrant->mnethostid][] = $immigrant->username;
732 }
733
734 require_once $CFG->dirroot . '/mnet/xmlrpc/client.php';
735 foreach($usersArray as $mnethostid => $users) {
736 $mnet_peer = new mnet_peer();
737 $mnet_peer->set_id($mnethostid);
738
739 $mnet_request = new mnet_xmlrpc_client();
740 $mnet_request->set_method('auth/mnet/auth.php/keepalive_server');
741
742 // set $token and $useragent parameters
743 $mnet_request->add_param($users);
744
745 if ($mnet_request->send($mnet_peer) === true) {
746 if (!isset($mnet_request->response['code'])) {
747 debugging("Server side error has occured on host $mnethostid");
748 continue;
749 } elseif ($mnet_request->response['code'] > 0) {
750 debugging($mnet_request->response['message']);
751 }
139ebfdb 752
c72fe801 753 if (!isset($mnet_request->response['last log id'])) {
754 debugging("Server side error has occured on host $mnethostid\nNo log ID was received.");
755 continue;
756 }
757 } else {
139ebfdb 758 debugging("Server side error has occured on host $mnethostid: " .
c72fe801 759 join("\n", $mnet_request->error));
3d7e4468 760 break;
c72fe801 761 }
28c3e7d8 762 $mnethostlogssql = "
6ff7d16b 763 SELECT
764 mhostlogs.remoteid, mhostlogs.time, mhostlogs.userid, mhostlogs.ip,
765 mhostlogs.course, mhostlogs.module, mhostlogs.cmid, mhostlogs.action,
766 mhostlogs.url, mhostlogs.info, mhostlogs.username, c.fullname as coursename,
767 c.modinfo
768 FROM
769 (
770 SELECT
771 l.id as remoteid, l.time, l.userid, l.ip, l.course, l.module, l.cmid,
772 l.action, l.url, l.info, u.username
773 FROM
774 {user} u
775 INNER JOIN {log} l on l.userid = u.id
776 WHERE
777 u.mnethostid = ?
778 AND l.id > ?
779 ORDER BY remoteid ASC
780 LIMIT 500
781 ) mhostlogs
782 INNER JOIN {course} c on c.id = mhostlogs.course
783 ORDER by mhostlogs.remoteid ASC";
c72fe801 784
995087b9 785 $mnethostlogs = $DB->get_records_sql($mnethostlogssql, array($mnethostid, $mnet_request->response['last log id']));
c72fe801 786
6da155db 787 if ($mnethostlogs == false) {
788 continue;
789 }
c72fe801 790
995087b9 791 $processedlogs = array();
c72fe801 792
995087b9 793 foreach($mnethostlogs as $hostlog) {
794 // Extract the name of the relevant module instance from the
795 // course modinfo if possible.
796 if (!empty($hostlog->modinfo) && !empty($hostlog->cmid)) {
797 $modinfo = unserialize($hostlog->modinfo);
798 unset($hostlog->modinfo);
c72fe801 799 $modulearray = array();
800 foreach($modinfo as $module) {
801 $modulearray[$module->cm] = urldecode($module->name);
802 }
995087b9 803 $hostlog->resource_name = $modulearray[$hostlog->cmid];
c72fe801 804 } else {
995087b9 805 $hostlog->resource_name = '';
c72fe801 806 }
807
995087b9 808 $processedlogs[] = array (
809 'remoteid' => $hostlog->remoteid,
810 'time' => $hostlog->time,
811 'userid' => $hostlog->userid,
812 'ip' => $hostlog->ip,
813 'course' => $hostlog->course,
814 'coursename' => $hostlog->coursename,
815 'module' => $hostlog->module,
816 'cmid' => $hostlog->cmid,
817 'action' => $hostlog->action,
818 'url' => $hostlog->url,
819 'info' => $hostlog->info,
820 'resource_name' => $hostlog->resource_name,
821 'username' => $hostlog->username
c72fe801 822 );
823 }
824
995087b9 825 unset($hostlog);
c72fe801 826
827 $mnet_request = new mnet_xmlrpc_client();
828 $mnet_request->set_method('auth/mnet/auth.php/refresh_log');
829
830 // set $token and $useragent parameters
995087b9 831 $mnet_request->add_param($processedlogs);
c72fe801 832
833 if ($mnet_request->send($mnet_peer) === true) {
834 if ($mnet_request->response['code'] > 0) {
835 debugging($mnet_request->response['message']);
836 }
837 } else {
838 debugging("Server side error has occured on host $mnet_peer->ip: " .join("\n", $mnet_request->error));
839 }
840 }
841 }
842
843 /**
844 * Receives an array of log entries from an SP and adds them to the mnet_log
845 * table
846 *
847 * @param array $array An array of usernames
848 * @return string "All ok" or an error message
849 */
850 function refresh_log($array) {
7b0d12b2 851 global $CFG, $MNET_REMOTE_CLIENT, $DB;
c72fe801 852
853 // We don't want to output anything to the client machine
854 $start = ob_start();
855
856 $returnString = '';
7b0d12b2 857 $DB->begin_sql();
c72fe801 858 $useridarray = array();
859
860 foreach($array as $logEntry) {
861 $logEntryObj = (object)$logEntry;
862 $logEntryObj->hostid = $MNET_REMOTE_CLIENT->id;
863
864 if (isset($useridarray[$logEntryObj->username])) {
865 $logEntryObj->userid = $useridarray[$logEntryObj->username];
866 } else {
457c9729 867 $logEntryObj->userid = $DB->get_field('user', 'id', array('username'=>$logEntryObj->username, 'mnethostid'=>(int)$logEntryObj->hostid));
c72fe801 868 if ($logEntryObj->userid == false) {
869 $logEntryObj->userid = 0;
870 }
871 $useridarray[$logEntryObj->username] = $logEntryObj->userid;
872 }
873
874 unset($logEntryObj->username);
875
9dbc81ef 876 $logEntryObj = $this->trim_logline($logEntryObj);
877 $insertok = $DB->insert_record('mnet_log', $logEntryObj, false);
c72fe801 878
879 if ($insertok) {
880 $MNET_REMOTE_CLIENT->last_log_id = $logEntryObj->remoteid;
881 } else {
882 $returnString .= 'Record with id '.$logEntryObj->remoteid." failed to insert.\n";
883 }
884 }
885 $MNET_REMOTE_CLIENT->commit();
7b0d12b2 886 $DB->commit_sql();
c72fe801 887
888 $end = ob_end_clean();
889
890 if (empty($returnString)) return array('code' => 0, 'message' => 'All ok');
891 return array('code' => 1, 'message' => $returnString);
892 }
893
894 /**
895 * Receives an array of usernames from a remote machine and prods their
896 * sessions to keep them alive
897 *
898 * @param array $array An array of usernames
899 * @return string "All ok" or an error message
900 */
901 function keepalive_server($array) {
7b0d12b2 902 global $MNET_REMOTE_CLIENT, $CFG, $DB;
c72fe801 903
904 $CFG->usesid = true;
c72fe801 905
906 // We don't want to output anything to the client machine
907 $start = ob_start();
908
909 // We'll get session records in batches of 30
910 $superArray = array_chunk($array, 30);
911
912 $returnString = '';
913
914 foreach($superArray as $subArray) {
915 $subArray = array_values($subArray);
916 $instring = "('".implode("', '",$subArray)."')";
7b0d12b2 917 $query = "select id, session_id, username from {mnet_session} where username in $instring";
918 $results = $DB->get_records_sql($query);
c72fe801 919
920 if ($results == false) {
921 // We seem to have a username that breaks our query:
922 // TODO: Handle this error appropriately
923 $returnString .= "We failed to refresh the session for the following usernames: \n".implode("\n", $subArray)."\n\n";
924 } else {
925 // TODO: This process of killing and re-starting the session
926 // will cause PHP to forget any custom session_set_save_handler
927 // stuff. Subsequent attempts to prod existing sessions will
928 // fail, because PHP will look in wherever the default place
929 // may be (files?) and probably create a new session with the
930 // right session ID in that location. If it doesn't have write-
931 // access to that location, then it will fail... not sure how
932 // apparent that will be.
933 // There is no way to capture what the custom session handler
934 // is and then reset it on each pass - I checked that out
935 // already.
d87234ce 936 $sesscache = $_SESSION;
c72fe801 937 $sessidcache = session_id();
938 session_write_close();
939 unset($_SESSION);
940
941 $uc = ini_get('session.use_cookies');
942 ini_set('session.use_cookies', false);
943 foreach($results as $emigrant) {
944
945 unset($_SESSION);
946 session_name('MoodleSession'.$CFG->sessioncookie);
947 session_id($emigrant->session_id);
948 session_start();
949 session_write_close();
950 }
951
952 ini_set('session.use_cookies', $uc);
953 session_name('MoodleSession'.$CFG->sessioncookie);
954 session_id($sessidcache);
955 session_start();
d87234ce 956 $_SESSION = $sesscache;
c72fe801 957 session_write_close();
958 }
959 }
960
961 $end = ob_end_clean();
962
963 if (empty($returnString)) return array('code' => 0, 'message' => 'All ok', 'last log id' => $MNET_REMOTE_CLIENT->last_log_id);
964 return array('code' => 1, 'message' => $returnString, 'last log id' => $MNET_REMOTE_CLIENT->last_log_id);
965 }
966
967 /**
968 * Cron function will be called automatically by cron.php every 5 minutes
969 *
970 * @return void
971 */
972 function cron() {
7b0d12b2 973 global $DB;
4c1c5d26 974
975 // run the keepalive client
c72fe801 976 $this->keepalive_client();
4c1c5d26 977
978 // admin/cron.php should have run srand for us
979 $random100 = rand(0,100);
980 if ($random100 < 10) { // Approximately 10% of the time.
981 // nuke olden sessions
f71a7f8f 982 $longtime = time() - (1 * 3600 * 24);
7b0d12b2 983 $DB->delete_records_select('mnet_session', "expires < ?", array($longtime));
4c1c5d26 984 }
c72fe801 985 }
986
987 /**
988 * Cleanup any remote mnet_sessions, kill the local mnet_session data
989 *
990 * This is called by require_logout in moodlelib
991 *
992 * @return void
993 */
f5fd4347 994 function prelogout_hook() {
c72fe801 995 global $MNET, $CFG, $USER;
23a94798 996 if (!is_enabled_auth('mnet')) {
f5fd4347 997 return;
998 }
999
c72fe801 1000 require_once $CFG->dirroot.'/mnet/xmlrpc/client.php';
1001
1002 // If the user is local to this Moodle:
1003 if ($USER->mnethostid == $MNET->id) {
1004 $this->kill_children($USER->username, sha1($_SERVER['HTTP_USER_AGENT']));
1005
1006 // Else the user has hit 'logout' at a Service Provider Moodle:
1007 } else {
1008 $this->kill_parent($USER->username, sha1($_SERVER['HTTP_USER_AGENT']));
1009
1010 }
1011 }
1012
1013 /**
1014 * The SP uses this function to kill the session on the parent IdP
1015 *
1016 * @param string $username Username for session to kill
1017 * @param string $useragent SHA1 hash of user agent to look for
1018 * @return string A plaintext report of what has happened
1019 */
1020 function kill_parent($username, $useragent) {
7b0d12b2 1021 global $CFG, $USER, $DB;
1022
c72fe801 1023 require_once $CFG->dirroot.'/mnet/xmlrpc/client.php';
1024 $sql = "
1025 select
1026 *
1027 from
7b0d12b2 1028 {mnet_session} s
c72fe801 1029 where
7b0d12b2 1030 s.username = ? AND
1031 s.useragent = ? AND
1032 s.mnethostid = ?";
c72fe801 1033
7b0d12b2 1034 $mnetsessions = $DB->get_records_sql($sql, array($username, $useragent, $USER->mnethostid));
c72fe801 1035
7b0d12b2 1036 $ignore = $DB->delete_records('mnet_session',
1037 array('username'=>$username,
1038 'useragent'=>$useragent,
1039 'mnethostid'=>$USER->mnethostid));
c72fe801 1040
1041 if (false != $mnetsessions) {
1042 $mnet_peer = new mnet_peer();
1043 $mnet_peer->set_id($USER->mnethostid);
1044
1045 $mnet_request = new mnet_xmlrpc_client();
1046 $mnet_request->set_method('auth/mnet/auth.php/kill_children');
1047
1048 // set $token and $useragent parameters
1049 $mnet_request->add_param($username);
1050 $mnet_request->add_param($useragent);
1051 if ($mnet_request->send($mnet_peer) === false) {
1052 debugging(join("\n", $mnet_request->error));
139ebfdb 1053 return false;
c72fe801 1054 }
1055 }
1056
1057 $_SESSION = array();
1058 return true;
1059 }
1060
1061 /**
1062 * The IdP uses this function to kill child sessions on other hosts
1063 *
1064 * @param string $username Username for session to kill
1065 * @param string $useragent SHA1 hash of user agent to look for
1066 * @return string A plaintext report of what has happened
1067 */
1068 function kill_children($username, $useragent) {
7b0d12b2 1069 global $CFG, $USER, $MNET_REMOTE_CLIENT, $DB;
c72fe801 1070 require_once $CFG->dirroot.'/mnet/xmlrpc/client.php';
1071
7b0d12b2 1072 $userid = $DB->get_field('user', 'id', array('mnethostid'=>$CFG->mnet_localhost_id, 'username'=>$username));
c72fe801 1073
1074 $returnstring = '';
1c85006c 1075
1076 $mnetsessions = $DB->get_records('mnet_session', array('userid' => $userid, 'useragent' => $useragent));
c72fe801 1077
c72fe801 1078 if (false == $mnetsessions) {
f213ba93 1079 $returnstring .= "Could find no remote sessions\n";
c72fe801 1080 $mnetsessions = array();
1081 }
1082
1083 foreach($mnetsessions as $mnetsession) {
4711957d 1084 // If this script is being executed by a remote peer, that means the user has clicked
1085 // logout on that peer, and the session on that peer can be deleted natively.
1086 // Skip over it.
1087 if (isset($MNET_REMOTE_CLIENT->id) && ($mnetsession->mnethostid == $MNET_REMOTE_CLIENT->id)) {
1088 continue;
1089 }
c72fe801 1090 $returnstring .= "Deleting session\n";
1091
c72fe801 1092 $mnet_peer = new mnet_peer();
1093 $mnet_peer->set_id($mnetsession->mnethostid);
1094
1095 $mnet_request = new mnet_xmlrpc_client();
1096 $mnet_request->set_method('auth/mnet/auth.php/kill_child');
1097
1098 // set $token and $useragent parameters
1099 $mnet_request->add_param($username);
1100 $mnet_request->add_param($useragent);
1101 if ($mnet_request->send($mnet_peer) === false) {
1a7601ca 1102 debugging("Server side error has occured on host $mnetsession->mnethostid: " .
c72fe801 1103 join("\n", $mnet_request->error));
1104 }
1105 }
1106
7b0d12b2 1107 $ignore = $DB->delete_records('mnet_session',
1108 array('useragent'=>$useragent, 'userid'=>$userid));
c72fe801 1109
1110 if (isset($MNET_REMOTE_CLIENT) && isset($MNET_REMOTE_CLIENT->id)) {
1111 $start = ob_start();
1112
ae18d3e6 1113 // Save current session and cookie-use status
a01ee313 1114 $cookieuse = ini_get('session.use_cookies');
c72fe801 1115 ini_set('session.use_cookies', false);
210d7a46 1116 $sesscache = $_SESSION;
c72fe801 1117 $sessidcache = session_id();
a01ee313 1118
1119 // Replace existing mnet session with user session & unset
c72fe801 1120 session_write_close();
1121 unset($_SESSION);
c72fe801 1122 session_id($mnetsession->session_id);
1123 session_start();
1124 session_unregister("USER");
1125 session_unregister("SESSION");
1126 unset($_SESSION);
1127 $_SESSION = array();
1128 session_write_close();
1129
a01ee313 1130 // Restore previous info
1131 ini_set('session.use_cookies', $cookieuse);
c72fe801 1132 session_name('MoodleSession'.$CFG->sessioncookie);
1133 session_id($sessidcache);
1134 session_start();
210d7a46 1135 $_SESSION = $sesscache;
c72fe801 1136 session_write_close();
1137
1138 $end = ob_end_clean();
1139 } else {
1140 $_SESSION = array();
1141 }
1142 return $returnstring;
1143 }
1144
1145 /**
1146 * TODO:Untested When the IdP requests that child sessions are terminated,
1147 * this function will be called on each of the child hosts. The machine that
1148 * calls the function (over xmlrpc) provides us with the mnethostid we need.
1149 *
1150 * @param string $username Username for session to kill
1151 * @param string $useragent SHA1 hash of user agent to look for
1152 * @return bool True on success
1153 */
1154 function kill_child($username, $useragent) {
7b0d12b2 1155 global $CFG, $MNET_REMOTE_CLIENT, $DB;
1156 $session = $DB->get_record('mnet_session', array('username'=>$username, 'mnethostid'=>$MNET_REMOTE_CLIENT->id, 'useragent'=>$useragent));
c72fe801 1157 if (false != $session) {
1158 $start = ob_start();
1159
1160 $uc = ini_get('session.use_cookies');
1161 ini_set('session.use_cookies', false);
d87234ce 1162 $sesscache = $_SESSION;
c72fe801 1163 $sessidcache = session_id();
1164 session_write_close();
1165 unset($_SESSION);
1166
1167
1168 session_id($session->session_id);
1169 session_start();
1170 session_unregister("USER");
1171 session_unregister("SESSION");
1172 unset($_SESSION);
1173 $_SESSION = array();
1174 session_write_close();
1175
1176
1177 ini_set('session.use_cookies', $uc);
1178 session_name('MoodleSession'.$CFG->sessioncookie);
1179 session_id($sessidcache);
1180 session_start();
d87234ce 1181 $_SESSION = $sesscache;
c72fe801 1182 session_write_close();
1183
1184 $end = ob_end_clean();
1185 return true;
1186 }
1187 return false;
1188 }
1189
1190 /**
1191 * To delete a host, we must delete all current sessions that users from
1192 * that host are currently engaged in.
1193 *
1194 * @param string $sessionidarray An array of session hashes
1195 * @return bool True on success
1196 */
1197 function end_local_sessions(&$sessionArray) {
1198 global $CFG;
1199 if (is_array($sessionArray)) {
1200 $start = ob_start();
1201
1202 $uc = ini_get('session.use_cookies');
1203 ini_set('session.use_cookies', false);
d87234ce 1204 $sesscache = $_SESSION;
c72fe801 1205 $sessidcache = session_id();
1206 session_write_close();
1207 unset($_SESSION);
1208
1209 while($session = array_pop($sessionArray)) {
1210 session_id($session->session_id);
1211 session_start();
1212 session_unregister("USER");
1213 session_unregister("SESSION");
1214 unset($_SESSION);
1215 $_SESSION = array();
1216 session_write_close();
1217 }
1218
1219 ini_set('session.use_cookies', $uc);
1220 session_name('MoodleSession'.$CFG->sessioncookie);
1221 session_id($sessidcache);
1222 session_start();
d87234ce 1223 $_SESSION = $sesscache;
c72fe801 1224
1225 $end = ob_end_clean();
1226 return true;
1227 }
1228 return false;
1229 }
1230
1231 /**
1232 * Returns the user's image as a base64 encoded string.
1233 *
1234 * @param int $userid The id of the user
1235 * @return string The encoded image
1236 */
1237 function fetch_user_image($username) {
7b0d12b2 1238 global $CFG, $DB;
c72fe801 1239
7b0d12b2 1240 if ($user = $DB->get_record('user', array('username'=>$username, 'mnethostid'=>$CFG->mnet_localhost_id))) {
56a1a882 1241 $filename1 = make_user_directory($user->id, true) . "/f1.jpg";
1242 $filename2 = make_user_directory($user->id, true) . "/f2.jpg";
c72fe801 1243 $return = array();
1244 if (file_exists($filename1)) {
1245 $return['f1'] = base64_encode(file_get_contents($filename1));
1246 }
1247 if (file_exists($filename2)) {
1248 $return['f2'] = base64_encode(file_get_contents($filename2));
1249 }
1250 return $return;
1251 }
1252 return false;
1253 }
1254
1255 /**
1256 * Returns the theme information and logo url as strings.
1257 *
1258 * @return string The theme info
1259 */
1260 function fetch_theme_info() {
1261 global $CFG;
1262
1263 $themename = "$CFG->theme";
1264 $logourl = "$CFG->wwwroot/theme/$CFG->theme/images/logo.jpg";
1265
1266 $return['themename'] = $themename;
1267 $return['logourl'] = $logourl;
1268 return $return;
1269 }
1270
1271 /**
1272 * Determines if an MNET host is providing the nominated service.
1273 *
1274 * @param int $mnethostid The id of the remote host
1275 * @param string $servicename The name of the service
1276 * @return bool Whether the service is available on the remote host
1277 */
1278 function has_service($mnethostid, $servicename) {
7b0d12b2 1279 global $CFG, $DB;
c72fe801 1280
1281 $sql = "
1282 SELECT
1283 svc.id as serviceid,
1284 svc.name,
1285 svc.description,
1286 svc.offer,
1287 svc.apiversion,
1288 h2s.id as h2s_id
1289 FROM
dbca4e44 1290 {mnet_host} h,
7b0d12b2 1291 {mnet_service} svc,
1292 {mnet_host2service} h2s
c72fe801 1293 WHERE
dbca4e44 1294 h.deleted = '0' AND
1295 h.id = h2s.hostid AND
7b0d12b2 1296 h2s.hostid = ? AND
c72fe801 1297 h2s.serviceid = svc.id AND
7b0d12b2 1298 svc.name = ? AND
c72fe801 1299 h2s.subscribe = '1'";
1300
7b0d12b2 1301 return $DB->get_records_sql($sql, array($mnethostid, $servicename));
c72fe801 1302 }
1303
1304 /**
1305 * Checks the MNET access control table to see if the username/mnethost
1306 * is permitted to login to this moodle.
1307 *
1308 * @param string $username The username
1309 * @param int $mnethostid The id of the remote mnethost
1310 * @return bool Whether the user can login from the remote host
1311 */
1312 function can_login_remotely($username, $mnethostid) {
7b0d12b2 1313 global $DB;
1314
cdf22329 1315 $accessctrl = 'allow';
7b0d12b2 1316 $aclrecord = $DB->get_record('mnet_sso_access_control', array('username'=>$username, 'mnet_host_id'=>$mnethostid));
c72fe801 1317 if (!empty($aclrecord)) {
cdf22329 1318 $accessctrl = $aclrecord->accessctrl;
c72fe801 1319 }
cdf22329 1320 return $accessctrl == 'allow';
c72fe801 1321 }
6bc1e5d5 1322
f5fd4347 1323 function logoutpage_hook() {
7b0d12b2 1324 global $USER, $CFG, $redirect, $DB;
6bc1e5d5 1325
1326 if (!empty($USER->mnethostid) and $USER->mnethostid != $CFG->mnet_localhost_id) {
7b0d12b2 1327 $host = $DB->get_record('mnet_host', array('id'=>$USER->mnethostid));
6bc1e5d5 1328 $redirect = $host->wwwroot.'/';
1329 }
1330 }
1331
9dbc81ef 1332 /**
1333 * Trims a log line from mnet peer to limit each part to a length which can be stored in our DB
1334 *
1335 * @param object $logline The log information to be trimmed
1336 * @return object The passed logline object trimmed to not exceed storable limits
1337 */
1338 function trim_logline ($logline) {
1339 $limits = array('ip' => 15, 'coursename' => 40, 'module' => 20, 'action' => 40,
1340 'url' => 255);
1341 foreach ($limits as $property => $limit) {
1342 if (isset($logline->$property)) {
1343 $logline->$property = substr($logline->$property, 0, $limit);
1344 }
1345 }
1346
1347 return $logline;
1348 }
1349
1350
c72fe801 1351}
1352
1353?>