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