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