2009-11-01 11:55:14 +00:00
|
|
|
<?php
|
2013-04-27 15:06:40 +02:00
|
|
|
// This file is part of Moodle - http://moodle.org/
|
|
|
|
//
|
|
|
|
// Moodle is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// Moodle is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
2007-01-04 03:26:04 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Authentication Plugin: Moodle Network Authentication
|
|
|
|
* Multiple host authentication support for Moodle Network.
|
|
|
|
*
|
2013-04-27 15:06:40 +02:00
|
|
|
* @package auth_mnet
|
|
|
|
* @author Martin Dougiamas
|
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
2007-01-04 03:26:04 +00:00
|
|
|
*/
|
|
|
|
|
2013-04-27 15:09:05 +02:00
|
|
|
defined('MOODLE_INTERNAL') || die();
|
2007-01-04 03:26:04 +00:00
|
|
|
|
2007-03-22 12:27:52 +00:00
|
|
|
require_once($CFG->libdir.'/authlib.php');
|
|
|
|
|
2007-01-04 03:26:04 +00:00
|
|
|
/**
|
|
|
|
* Moodle Network authentication plugin.
|
|
|
|
*/
|
2007-03-22 12:27:52 +00:00
|
|
|
class auth_plugin_mnet extends auth_plugin_base {
|
2007-01-04 03:26:04 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
*/
|
2015-11-27 09:01:25 +08:00
|
|
|
public function __construct() {
|
2007-03-22 12:27:52 +00:00
|
|
|
$this->authtype = 'mnet';
|
2010-07-13 11:14:29 +00:00
|
|
|
$this->config = get_config('auth_mnet');
|
2010-02-02 03:13:40 +00:00
|
|
|
$this->mnet = get_mnet_environment();
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
2015-11-27 09:01:25 +08:00
|
|
|
/**
|
|
|
|
* Old syntax of class constructor. Deprecated in PHP7.
|
|
|
|
*
|
|
|
|
* @deprecated since Moodle 3.1
|
|
|
|
*/
|
|
|
|
public function auth_plugin_mnet() {
|
|
|
|
debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
|
|
|
|
self::__construct();
|
|
|
|
}
|
|
|
|
|
2007-01-04 03:26:04 +00:00
|
|
|
/**
|
|
|
|
* This function is normally used to determine if the username and password
|
|
|
|
* are correct for local logins. Always returns false, as local users do not
|
|
|
|
* need to login over mnet xmlrpc.
|
|
|
|
*
|
|
|
|
* @param string $username The username
|
|
|
|
* @param string $password The password
|
2007-02-20 17:03:36 +00:00
|
|
|
* @return bool Authentication success or failure.
|
2007-01-04 03:26:04 +00:00
|
|
|
*/
|
|
|
|
function user_login($username, $password) {
|
2008-05-08 06:27:28 +00:00
|
|
|
return false; // print_error("mnetlocal");
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2012-11-30 09:23:17 +08:00
|
|
|
* Return user data for the provided token, compare with user_agent string.
|
2007-01-04 03:26:04 +00:00
|
|
|
*
|
|
|
|
* @param string $token The unique ID provided by remotehost.
|
2016-03-21 11:03:24 +08:00
|
|
|
* @param string $useragent User Agent string.
|
2007-01-04 03:26:04 +00:00
|
|
|
* @return array $userdata Array of user info for remote host
|
|
|
|
*/
|
|
|
|
function user_authorise($token, $useragent) {
|
2010-02-02 03:13:40 +00:00
|
|
|
global $CFG, $SITE, $DB;
|
|
|
|
$remoteclient = get_mnet_remote_client();
|
mnet MDL-21261 large overhaul. This commit changes:
- The way that mnet rpc functions are registered. Plugins must now
create db/mnet.php which is an array, similar to services.php. This
*replaces* the old mnet_publishes() functions. version.php must be
bumped to trigger this.
- More information about each rpc-available function is stored in the
database, including the class it belongs to, the file it is found in,
and whether or not it is static. Methods that are not static must be
in a class with a constructor that takes no arguments (this can easily
be achieved with a small wrapper if necessary)
- The xmlrpc dispatcher has been rewritten to remove all the
dependencies on hardcoded information about auth,mnet,portfolio and
repository, and just use the information in the database.
- The old hardcoded hidden mnet/testclient.php has been moved to the
Admin menu under "Development" and rewritten.
- The xmlrpc introspection method profiling is now using php and zend
reflection - which is a lot nicer than the old way, which was using a
php-based php parser. This fixes some inconsistent handling of
methods without arguments that were advertising their return value as
the only method parameter. While this is a *fix*, it breaks BC
slightly - the old 1.9 broken mnet/testclient.php will now not work
properly with 2.0
- Dangerous mode is still supported, but old mod/*/rpclib.php is
now unsupported, due to the fact that any plugin can export mnet
functions with db/mnet.php. This is a slight BC break.
Still TODO:
- TEST TEST TEST
- Document the two small BC breaks in release notes
- Document the contract for db/mnet.php
2010-01-28 05:25:50 +00:00
|
|
|
require_once $CFG->dirroot . '/mnet/xmlrpc/serverlib.php';
|
2007-01-04 03:26:04 +00:00
|
|
|
|
2012-11-30 09:23:17 +08:00
|
|
|
$mnet_session = $DB->get_record('mnet_session', array('token'=>$token, 'useragent'=>$useragent));
|
2007-01-04 03:26:04 +00:00
|
|
|
if (empty($mnet_session)) {
|
2010-05-01 15:53:45 +00:00
|
|
|
throw new mnet_server_exception(1, 'authfail_nosessionexists');
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// check session confirm timeout
|
|
|
|
if ($mnet_session->confirm_timeout < time()) {
|
2010-05-01 15:53:45 +00:00
|
|
|
throw new mnet_server_exception(2, 'authfail_sessiontimedout');
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// session okay, try getting the user
|
2008-06-04 21:54:47 +00:00
|
|
|
if (!$user = $DB->get_record('user', array('id'=>$mnet_session->userid))) {
|
2010-05-01 15:53:45 +00:00
|
|
|
throw new mnet_server_exception(3, 'authfail_usermismatch');
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
2010-02-16 02:05:30 +00:00
|
|
|
$userdata = mnet_strip_user((array)$user, mnet_fields_to_send($remoteclient));
|
|
|
|
|
|
|
|
// extra special ones
|
2007-01-04 03:26:04 +00:00
|
|
|
$userdata['auth'] = 'mnet';
|
2010-02-02 03:13:40 +00:00
|
|
|
$userdata['wwwroot'] = $this->mnet->wwwroot;
|
2007-01-04 03:26:04 +00:00
|
|
|
$userdata['session.gc_maxlifetime'] = ini_get('session.gc_maxlifetime');
|
2010-02-16 02:05:30 +00:00
|
|
|
|
|
|
|
if (array_key_exists('picture', $userdata) && !empty($user->picture)) {
|
2010-11-26 09:19:55 +00:00
|
|
|
$fs = get_file_storage();
|
2012-08-02 11:20:48 +08:00
|
|
|
$usercontext = context_user::instance($user->id, MUST_EXIST);
|
2010-11-26 09:19:55 +00:00
|
|
|
if ($usericonfile = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f1.png')) {
|
|
|
|
$userdata['_mnet_userpicture_timemodified'] = $usericonfile->get_timemodified();
|
|
|
|
$userdata['_mnet_userpicture_mimetype'] = $usericonfile->get_mimetype();
|
|
|
|
} else if ($usericonfile = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f1.jpg')) {
|
|
|
|
$userdata['_mnet_userpicture_timemodified'] = $usericonfile->get_timemodified();
|
|
|
|
$userdata['_mnet_userpicture_mimetype'] = $usericonfile->get_mimetype();
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
}
|
2007-01-16 05:00:18 +00:00
|
|
|
|
|
|
|
$userdata['myhosts'] = array();
|
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
|
|
|
if ($courses = enrol_get_users_courses($user->id, false)) {
|
2007-01-16 05:00:18 +00:00
|
|
|
$userdata['myhosts'][] = array('name'=> $SITE->shortname, 'url' => $CFG->wwwroot, 'count' => count($courses));
|
|
|
|
}
|
|
|
|
|
2010-07-17 22:34:12 +00:00
|
|
|
$sql = "SELECT h.name AS hostname, h.wwwroot, h.id AS hostid,
|
|
|
|
COUNT(c.id) AS count
|
|
|
|
FROM {mnetservice_enrol_courses} c
|
|
|
|
JOIN {mnetservice_enrol_enrolments} e ON (e.hostid = c.hostid AND e.remotecourseid = c.remoteid)
|
|
|
|
JOIN {mnet_host} h ON h.id = c.hostid
|
|
|
|
WHERE e.userid = ? AND c.hostid = ?
|
|
|
|
GROUP BY h.name, h.wwwroot, h.id";
|
|
|
|
|
2010-02-02 03:13:40 +00:00
|
|
|
if ($courses = $DB->get_records_sql($sql, array($user->id, $remoteclient->id))) {
|
2007-01-16 05:00:18 +00:00
|
|
|
foreach($courses as $course) {
|
|
|
|
$userdata['myhosts'][] = array('name'=> $course->hostname, 'url' => $CFG->wwwroot.'/auth/mnet/jump.php?hostid='.$course->hostid, 'count' => $course->count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-04 03:26:04 +00:00
|
|
|
return $userdata;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate a random string for use as an RPC session token.
|
|
|
|
*/
|
|
|
|
function generate_token() {
|
|
|
|
return sha1(str_shuffle('' . mt_rand() . time()));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Starts an RPC jump session and returns the jump redirect URL.
|
2008-08-29 12:42:39 +00:00
|
|
|
*
|
|
|
|
* @param int $mnethostid id of the mnet host to jump to
|
|
|
|
* @param string $wantsurl url to redirect to after the jump (usually on remote system)
|
|
|
|
* @param boolean $wantsurlbackhere defaults to false, means that the remote system should bounce us back here
|
|
|
|
* rather than somewhere inside *its* wwwroot
|
2007-01-04 03:26:04 +00:00
|
|
|
*/
|
2008-08-29 12:42:39 +00:00
|
|
|
function start_jump_session($mnethostid, $wantsurl, $wantsurlbackhere=false) {
|
2010-02-02 03:13:40 +00:00
|
|
|
global $CFG, $USER, $DB;
|
2007-01-04 03:26:04 +00:00
|
|
|
require_once $CFG->dirroot . '/mnet/xmlrpc/client.php';
|
|
|
|
|
2013-09-08 08:38:52 +02:00
|
|
|
if (\core\session\manager::is_loggedinas()) {
|
2011-11-04 09:33:58 +01:00
|
|
|
print_error('notpermittedtojumpas', 'mnet');
|
|
|
|
}
|
|
|
|
|
2007-01-04 03:26:04 +00:00
|
|
|
// check remote login permissions
|
2013-07-03 14:39:10 +08:00
|
|
|
if (! has_capability('moodle/site:mnetlogintoremote', context_system::instance())
|
2007-01-04 03:26:04 +00:00
|
|
|
or is_mnet_remote_user($USER)
|
2010-03-31 07:41:31 +00:00
|
|
|
or isguestuser()
|
|
|
|
or !isloggedin()) {
|
2008-04-04 02:54:20 +00:00
|
|
|
print_error('notpermittedtojump', 'mnet');
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// check for SSO publish permission first
|
|
|
|
if ($this->has_service($mnethostid, 'sso_sp') == false) {
|
2008-04-04 02:54:20 +00:00
|
|
|
print_error('hostnotconfiguredforsso', 'mnet');
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// set RPC timeout to 30 seconds if not configured
|
|
|
|
if (empty($this->config->rpc_negotiation_timeout)) {
|
2010-07-13 11:29:35 +00:00
|
|
|
$this->config->rpc_negotiation_timeout = 30;
|
2010-07-13 11:14:29 +00:00
|
|
|
set_config('rpc_negotiation_timeout', '30', 'auth_mnet');
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// get the host info
|
|
|
|
$mnet_peer = new mnet_peer();
|
|
|
|
$mnet_peer->set_id($mnethostid);
|
|
|
|
|
|
|
|
// set up the session
|
2008-06-04 21:54:47 +00:00
|
|
|
$mnet_session = $DB->get_record('mnet_session',
|
|
|
|
array('userid'=>$USER->id, 'mnethostid'=>$mnethostid,
|
|
|
|
'useragent'=>sha1($_SERVER['HTTP_USER_AGENT'])));
|
2007-01-04 03:26:04 +00:00
|
|
|
if ($mnet_session == false) {
|
2010-09-21 08:09:22 +00:00
|
|
|
$mnet_session = new stdClass();
|
2007-01-04 03:26:04 +00:00
|
|
|
$mnet_session->mnethostid = $mnethostid;
|
|
|
|
$mnet_session->userid = $USER->id;
|
|
|
|
$mnet_session->username = $USER->username;
|
|
|
|
$mnet_session->useragent = sha1($_SERVER['HTTP_USER_AGENT']);
|
|
|
|
$mnet_session->token = $this->generate_token();
|
|
|
|
$mnet_session->confirm_timeout = time() + $this->config->rpc_negotiation_timeout;
|
|
|
|
$mnet_session->expires = time() + (integer)ini_get('session.gc_maxlifetime');
|
|
|
|
$mnet_session->session_id = session_id();
|
2009-06-13 18:04:21 +00:00
|
|
|
$mnet_session->id = $DB->insert_record('mnet_session', $mnet_session);
|
2007-01-04 03:26:04 +00:00
|
|
|
} else {
|
|
|
|
$mnet_session->useragent = sha1($_SERVER['HTTP_USER_AGENT']);
|
|
|
|
$mnet_session->token = $this->generate_token();
|
|
|
|
$mnet_session->confirm_timeout = time() + $this->config->rpc_negotiation_timeout;
|
|
|
|
$mnet_session->expires = time() + (integer)ini_get('session.gc_maxlifetime');
|
|
|
|
$mnet_session->session_id = session_id();
|
2009-06-13 18:04:21 +00:00
|
|
|
$DB->update_record('mnet_session', $mnet_session);
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// construct the redirection URL
|
|
|
|
//$transport = mnet_get_protocol($mnet_peer->transport);
|
|
|
|
$wantsurl = urlencode($wantsurl);
|
2010-02-02 03:13:40 +00:00
|
|
|
$url = "{$mnet_peer->wwwroot}{$mnet_peer->application->sso_land_url}?token={$mnet_session->token}&idp={$this->mnet->wwwroot}&wantsurl={$wantsurl}";
|
2008-08-29 12:42:39 +00:00
|
|
|
if ($wantsurlbackhere) {
|
|
|
|
$url .= '&remoteurl=1';
|
|
|
|
}
|
2007-01-04 03:26:04 +00:00
|
|
|
|
|
|
|
return $url;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function confirms the remote (ID provider) host's mnet session
|
|
|
|
* by communicating the token and UA over the XMLRPC transport layer, and
|
|
|
|
* returns the local user record on success.
|
|
|
|
*
|
2010-02-05 03:56:00 +00:00
|
|
|
* @param string $token The random session token.
|
|
|
|
* @param mnet_peer $remotepeer The ID provider mnet_peer object.
|
2007-02-20 17:03:36 +00:00
|
|
|
* @return array The local user record.
|
2007-01-04 03:26:04 +00:00
|
|
|
*/
|
2010-02-05 03:56:00 +00:00
|
|
|
function confirm_mnet_session($token, $remotepeer) {
|
2010-02-02 03:13:40 +00:00
|
|
|
global $CFG, $DB;
|
2007-01-04 03:26:04 +00:00
|
|
|
require_once $CFG->dirroot . '/mnet/xmlrpc/client.php';
|
2010-11-26 09:19:55 +00:00
|
|
|
require_once $CFG->libdir . '/gdlib.php';
|
2013-08-19 17:03:39 +08:00
|
|
|
require_once($CFG->dirroot.'/user/lib.php');
|
2007-01-04 03:26:04 +00:00
|
|
|
|
|
|
|
// verify the remote host is configured locally before attempting RPC call
|
2010-02-05 03:56:00 +00:00
|
|
|
if (! $remotehost = $DB->get_record('mnet_host', array('wwwroot' => $remotepeer->wwwroot, 'deleted' => 0))) {
|
2008-04-04 02:54:20 +00:00
|
|
|
print_error('notpermittedtoland', 'mnet');
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// set up the RPC request
|
|
|
|
$mnetrequest = new mnet_xmlrpc_client();
|
|
|
|
$mnetrequest->set_method('auth/mnet/auth.php/user_authorise');
|
|
|
|
|
|
|
|
// set $token and $useragent parameters
|
|
|
|
$mnetrequest->add_param($token);
|
|
|
|
$mnetrequest->add_param(sha1($_SERVER['HTTP_USER_AGENT']));
|
|
|
|
|
|
|
|
// Thunderbirds are go! Do RPC call and store response
|
|
|
|
if ($mnetrequest->send($remotepeer) === true) {
|
|
|
|
$remoteuser = (object) $mnetrequest->response;
|
|
|
|
} else {
|
2007-01-11 04:16:34 +00:00
|
|
|
foreach ($mnetrequest->error as $errormessage) {
|
|
|
|
list($code, $message) = array_map('trim',explode(':', $errormessage, 2));
|
|
|
|
if($code == 702) {
|
|
|
|
$site = get_site();
|
2010-02-05 03:56:00 +00:00
|
|
|
print_error('mnet_session_prohibited', 'mnet', $remotepeer->wwwroot, format_string($site->fullname));
|
2007-01-11 04:16:34 +00:00
|
|
|
exit;
|
|
|
|
}
|
2007-01-04 23:38:17 +00:00
|
|
|
$message .= "ERROR $code:<br/>$errormessage<br/>";
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
2008-05-08 07:06:41 +00:00
|
|
|
print_error("rpcerror", '', '', $message);
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
2007-01-22 04:41:17 +00:00
|
|
|
unset($mnetrequest);
|
2007-01-04 03:26:04 +00:00
|
|
|
|
|
|
|
if (empty($remoteuser) or empty($remoteuser->username)) {
|
2007-01-11 04:16:34 +00:00
|
|
|
print_error('unknownerror', 'mnet');
|
|
|
|
exit;
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
2016-09-08 22:45:33 +02:00
|
|
|
if (user_not_fully_set_up($remoteuser, false)) {
|
2010-01-12 02:25:31 +00:00
|
|
|
print_error('notenoughidpinfo', 'mnet');
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
2010-02-16 02:05:30 +00:00
|
|
|
$remoteuser = mnet_strip_user($remoteuser, mnet_fields_to_import($remotepeer));
|
|
|
|
|
|
|
|
$remoteuser->auth = 'mnet';
|
|
|
|
$remoteuser->wwwroot = $remotepeer->wwwroot;
|
|
|
|
|
2010-07-01 15:11:44 +00:00
|
|
|
// the user may roam from Moodle 1.x where lang has _utf8 suffix
|
|
|
|
// also, make sure that the lang is actually installed, otherwise set site default
|
2010-07-13 13:14:37 +00:00
|
|
|
if (isset($remoteuser->lang)) {
|
|
|
|
$remoteuser->lang = clean_param(str_replace('_utf8', '', $remoteuser->lang), PARAM_LANG);
|
|
|
|
}
|
2010-07-01 15:11:44 +00:00
|
|
|
if (empty($remoteuser->lang)) {
|
|
|
|
if (!empty($CFG->lang)) {
|
|
|
|
$remoteuser->lang = $CFG->lang;
|
|
|
|
} else {
|
|
|
|
$remoteuser->lang = 'en';
|
|
|
|
}
|
|
|
|
}
|
2007-01-22 04:41:17 +00:00
|
|
|
$firsttime = false;
|
|
|
|
|
2007-01-04 03:26:04 +00:00
|
|
|
// get the local record for the remote user
|
2008-06-04 21:54:47 +00:00
|
|
|
$localuser = $DB->get_record('user', array('username'=>$remoteuser->username, 'mnethostid'=>$remotehost->id));
|
2007-01-04 03:26:04 +00:00
|
|
|
|
|
|
|
// add the remote user to the database if necessary, and if allowed
|
|
|
|
// TODO: refactor into a separate function
|
2007-11-01 06:11:08 +00:00
|
|
|
if (empty($localuser) || ! $localuser->id) {
|
2010-02-16 03:03:30 +00:00
|
|
|
/*
|
2007-01-04 03:26:04 +00:00
|
|
|
if (empty($this->config->auto_add_remote_users)) {
|
2008-04-04 02:54:20 +00:00
|
|
|
print_error('nolocaluser', 'mnet');
|
2010-02-16 03:03:30 +00:00
|
|
|
} See MDL-21327 for why this is commented out
|
|
|
|
*/
|
2007-01-04 03:26:04 +00:00
|
|
|
$remoteuser->mnethostid = $remotehost->id;
|
2014-11-19 14:16:41 +13:00
|
|
|
$remoteuser->firstaccess = 0;
|
2011-08-28 02:28:12 +02:00
|
|
|
$remoteuser->confirmed = 1;
|
2010-01-13 06:23:54 +00:00
|
|
|
|
2016-03-22 10:19:16 +01:00
|
|
|
$remoteuser->id = user_create_user($remoteuser, false);
|
2007-01-22 04:41:17 +00:00
|
|
|
$firsttime = true;
|
2010-01-11 22:20:11 +00:00
|
|
|
$localuser = $remoteuser;
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// check sso access control list for permission first
|
|
|
|
if (!$this->can_login_remotely($localuser->username, $remotehost->id)) {
|
2010-04-11 16:58:28 +00:00
|
|
|
print_error('sso_mnet_login_refused', 'mnet', '', array('user'=>$localuser->username, 'host'=>$remotehost->name));
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
2010-11-26 09:19:55 +00:00
|
|
|
$fs = get_file_storage();
|
|
|
|
|
2007-01-04 03:26:04 +00:00
|
|
|
// update the local user record with remote user data
|
|
|
|
foreach ((array) $remoteuser as $key => $val) {
|
|
|
|
|
2010-11-26 09:19:55 +00:00
|
|
|
if ($key == '_mnet_userpicture_timemodified' and empty($CFG->disableuserimages) and isset($remoteuser->picture)) {
|
|
|
|
// update the user picture if there is a newer verion at the identity provider
|
2012-08-02 11:20:48 +08:00
|
|
|
$usercontext = context_user::instance($localuser->id, MUST_EXIST);
|
2010-11-26 09:19:55 +00:00
|
|
|
if ($usericonfile = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f1.png')) {
|
|
|
|
$localtimemodified = $usericonfile->get_timemodified();
|
|
|
|
} else if ($usericonfile = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f1.jpg')) {
|
|
|
|
$localtimemodified = $usericonfile->get_timemodified();
|
|
|
|
} else {
|
|
|
|
$localtimemodified = 0;
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
2010-11-26 09:19:55 +00:00
|
|
|
if (!empty($val) and $localtimemodified < $val) {
|
|
|
|
mnet_debug('refetching the user picture from the identity provider host');
|
2007-01-04 03:26:04 +00:00
|
|
|
$fetchrequest = new mnet_xmlrpc_client();
|
|
|
|
$fetchrequest->set_method('auth/mnet/auth.php/fetch_user_image');
|
|
|
|
$fetchrequest->add_param($localuser->username);
|
|
|
|
if ($fetchrequest->send($remotepeer) === true) {
|
|
|
|
if (strlen($fetchrequest->response['f1']) > 0) {
|
2011-08-11 03:03:58 +09:30
|
|
|
$imagefilename = $CFG->tempdir . '/mnet-usericon-' . $localuser->id;
|
2007-01-04 03:26:04 +00:00
|
|
|
$imagecontents = base64_decode($fetchrequest->response['f1']);
|
2010-11-26 09:19:55 +00:00
|
|
|
file_put_contents($imagefilename, $imagecontents);
|
2012-04-30 23:36:47 +02:00
|
|
|
if ($newrev = process_new_icon($usercontext, 'user', 'icon', 0, $imagefilename)) {
|
|
|
|
$localuser->picture = $newrev;
|
2010-11-26 09:19:55 +00:00
|
|
|
}
|
|
|
|
unlink($imagefilename);
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
2010-11-26 09:19:55 +00:00
|
|
|
// note that since Moodle 2.0 we ignore $fetchrequest->response['f2']
|
|
|
|
// the mimetype information provided is ignored and the type of the file is detected
|
|
|
|
// by process_new_icon()
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-16 05:00:18 +00:00
|
|
|
if($key == 'myhosts') {
|
2007-01-19 08:36:02 +00:00
|
|
|
$localuser->mnet_foreign_host_array = array();
|
2007-01-22 04:41:17 +00:00
|
|
|
foreach($val as $rhost) {
|
|
|
|
$name = clean_param($rhost['name'], PARAM_ALPHANUM);
|
|
|
|
$url = clean_param($rhost['url'], PARAM_URL);
|
|
|
|
$count = clean_param($rhost['count'], PARAM_INT);
|
2007-01-16 05:00:18 +00:00
|
|
|
$url_is_local = stristr($url , $CFG->wwwroot);
|
|
|
|
if (!empty($name) && !empty($count) && empty($url_is_local)) {
|
2007-02-20 17:03:36 +00:00
|
|
|
$localuser->mnet_foreign_host_array[] = array('name' => $name,
|
|
|
|
'url' => $url,
|
2007-01-19 08:36:02 +00:00
|
|
|
'count' => $count);
|
2007-01-16 05:00:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-04 03:26:04 +00:00
|
|
|
$localuser->{$key} = $val;
|
|
|
|
}
|
|
|
|
|
|
|
|
$localuser->mnethostid = $remotepeer->id;
|
2013-08-19 17:03:39 +08:00
|
|
|
user_update_user($localuser, false);
|
2007-01-04 03:26:04 +00:00
|
|
|
|
2007-01-22 04:41:17 +00:00
|
|
|
if (!$firsttime) {
|
|
|
|
// repeat customer! let the IDP know about enrolments
|
2007-02-20 17:03:36 +00:00
|
|
|
// we have for this user.
|
2007-01-22 04:41:17 +00:00
|
|
|
// set up the RPC request
|
|
|
|
$mnetrequest = new mnet_xmlrpc_client();
|
|
|
|
$mnetrequest->set_method('auth/mnet/auth.php/update_enrolments');
|
|
|
|
|
|
|
|
// pass username and an assoc array of "my courses"
|
2010-07-17 22:34:12 +00:00
|
|
|
// with info so that the IDP can maintain mnetservice_enrol_enrolments
|
2007-01-22 04:41:17 +00:00
|
|
|
$mnetrequest->add_param($remoteuser->username);
|
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
|
|
|
$fields = 'id, category, sortorder, fullname, shortname, idnumber, summary, startdate, visible';
|
|
|
|
$courses = enrol_get_users_courses($localuser->id, false, $fields, 'visible DESC,sortorder ASC');
|
2007-01-22 04:41:17 +00:00
|
|
|
if (is_array($courses) && !empty($courses)) {
|
|
|
|
// Second request to do the JOINs that we'd have done
|
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
|
|
|
// inside enrol_get_users_courses() if we had been allowed
|
2007-02-20 17:03:36 +00:00
|
|
|
$sql = "SELECT c.id,
|
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
|
|
|
cc.name AS cat_name, cc.description AS cat_description
|
2008-06-04 21:54:47 +00:00
|
|
|
FROM {course} c
|
|
|
|
JOIN {course_categories} cc ON c.category = cc.id
|
|
|
|
WHERE c.id IN (" . join(',',array_keys($courses)) . ')';
|
|
|
|
$extra = $DB->get_records_sql($sql);
|
2007-01-22 04:41:17 +00:00
|
|
|
|
|
|
|
$keys = array_keys($courses);
|
2012-10-04 16:11:09 +08:00
|
|
|
$studentroles = get_archetype_roles('student');
|
2012-10-09 15:22:03 +08:00
|
|
|
if (!empty($studentroles)) {
|
|
|
|
$defaultrole = reset($studentroles);
|
|
|
|
//$defaultrole = get_default_course_role($ccache[$shortname]); //TODO: rewrite this completely, there is no default course role any more!!!
|
|
|
|
foreach ($keys AS $id) {
|
|
|
|
if ($courses[$id]->visible == 0) {
|
|
|
|
unset($courses[$id]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$courses[$id]->cat_id = $courses[$id]->category;
|
|
|
|
$courses[$id]->defaultroleid = $defaultrole->id;
|
|
|
|
unset($courses[$id]->category);
|
|
|
|
unset($courses[$id]->visible);
|
|
|
|
|
|
|
|
$courses[$id]->cat_name = $extra[$id]->cat_name;
|
|
|
|
$courses[$id]->cat_description = $extra[$id]->cat_description;
|
|
|
|
$courses[$id]->defaultrolename = $defaultrole->name;
|
|
|
|
// coerce to array
|
|
|
|
$courses[$id] = (array)$courses[$id];
|
2007-01-23 02:38:54 +00:00
|
|
|
}
|
2012-10-09 15:22:03 +08:00
|
|
|
} else {
|
|
|
|
throw new moodle_exception('unknownrole', 'error', '', 'student');
|
2007-01-22 04:41:17 +00:00
|
|
|
}
|
2007-01-22 05:46:40 +00:00
|
|
|
} else {
|
|
|
|
// if the array is empty, send it anyway
|
|
|
|
// we may be clearing out stale entries
|
2007-02-20 17:03:36 +00:00
|
|
|
$courses = array();
|
2007-01-22 05:46:40 +00:00
|
|
|
}
|
|
|
|
$mnetrequest->add_param($courses);
|
2007-01-22 04:41:17 +00:00
|
|
|
|
2007-01-22 05:46:40 +00:00
|
|
|
// Call 0800-RPC Now! -- we don't care too much if it fails
|
|
|
|
// as it's just informational.
|
|
|
|
if ($mnetrequest->send($remotepeer) === false) {
|
|
|
|
// error_log(print_r($mnetrequest->error,1));
|
2007-01-22 04:41:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-01-04 03:26:04 +00:00
|
|
|
return $localuser;
|
|
|
|
}
|
|
|
|
|
2010-02-05 03:56:00 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* creates (or updates) the mnet session once
|
|
|
|
* {@see confirm_mnet_session} and {@see complete_user_login} have both been called
|
|
|
|
*
|
|
|
|
* @param stdclass $user the local user (must exist already
|
|
|
|
* @param string $token the jump/land token
|
|
|
|
* @param mnet_peer $remotepeer the mnet_peer object of this users's idp
|
|
|
|
*/
|
|
|
|
public function update_mnet_session($user, $token, $remotepeer) {
|
|
|
|
global $DB;
|
|
|
|
$session_gc_maxlifetime = 1440;
|
|
|
|
if (isset($user->session_gc_maxlifetime)) {
|
|
|
|
$session_gc_maxlifetime = $user->session_gc_maxlifetime;
|
|
|
|
}
|
|
|
|
if (!$mnet_session = $DB->get_record('mnet_session',
|
|
|
|
array('userid'=>$user->id, 'mnethostid'=>$remotepeer->id,
|
|
|
|
'useragent'=>sha1($_SERVER['HTTP_USER_AGENT'])))) {
|
2010-09-21 08:09:22 +00:00
|
|
|
$mnet_session = new stdClass();
|
2010-02-05 03:56:00 +00:00
|
|
|
$mnet_session->mnethostid = $remotepeer->id;
|
|
|
|
$mnet_session->userid = $user->id;
|
|
|
|
$mnet_session->username = $user->username;
|
|
|
|
$mnet_session->useragent = sha1($_SERVER['HTTP_USER_AGENT']);
|
|
|
|
$mnet_session->token = $token; // Needed to support simultaneous sessions
|
|
|
|
// and preserving DB rec uniqueness
|
|
|
|
$mnet_session->confirm_timeout = time();
|
|
|
|
$mnet_session->expires = time() + (integer)$session_gc_maxlifetime;
|
|
|
|
$mnet_session->session_id = session_id();
|
|
|
|
$mnet_session->id = $DB->insert_record('mnet_session', $mnet_session);
|
|
|
|
} else {
|
|
|
|
$mnet_session->expires = time() + (integer)$session_gc_maxlifetime;
|
|
|
|
$DB->update_record('mnet_session', $mnet_session);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-01-22 05:46:40 +00:00
|
|
|
/**
|
|
|
|
* Invoke this function _on_ the IDP to update it with enrolment info local to
|
|
|
|
* the SP right after calling user_authorise()
|
|
|
|
*
|
mnet MDL-21261 large overhaul. This commit changes:
- The way that mnet rpc functions are registered. Plugins must now
create db/mnet.php which is an array, similar to services.php. This
*replaces* the old mnet_publishes() functions. version.php must be
bumped to trigger this.
- More information about each rpc-available function is stored in the
database, including the class it belongs to, the file it is found in,
and whether or not it is static. Methods that are not static must be
in a class with a constructor that takes no arguments (this can easily
be achieved with a small wrapper if necessary)
- The xmlrpc dispatcher has been rewritten to remove all the
dependencies on hardcoded information about auth,mnet,portfolio and
repository, and just use the information in the database.
- The old hardcoded hidden mnet/testclient.php has been moved to the
Admin menu under "Development" and rewritten.
- The xmlrpc introspection method profiling is now using php and zend
reflection - which is a lot nicer than the old way, which was using a
php-based php parser. This fixes some inconsistent handling of
methods without arguments that were advertising their return value as
the only method parameter. While this is a *fix*, it breaks BC
slightly - the old 1.9 broken mnet/testclient.php will now not work
properly with 2.0
- Dangerous mode is still supported, but old mod/*/rpclib.php is
now unsupported, due to the fact that any plugin can export mnet
functions with db/mnet.php. This is a slight BC break.
Still TODO:
- TEST TEST TEST
- Document the two small BC breaks in release notes
- Document the contract for db/mnet.php
2010-01-28 05:25:50 +00:00
|
|
|
* Normally called by the SP after calling user_authorise()
|
2007-01-22 05:46:40 +00:00
|
|
|
*
|
mnet MDL-21261 large overhaul. This commit changes:
- The way that mnet rpc functions are registered. Plugins must now
create db/mnet.php which is an array, similar to services.php. This
*replaces* the old mnet_publishes() functions. version.php must be
bumped to trigger this.
- More information about each rpc-available function is stored in the
database, including the class it belongs to, the file it is found in,
and whether or not it is static. Methods that are not static must be
in a class with a constructor that takes no arguments (this can easily
be achieved with a small wrapper if necessary)
- The xmlrpc dispatcher has been rewritten to remove all the
dependencies on hardcoded information about auth,mnet,portfolio and
repository, and just use the information in the database.
- The old hardcoded hidden mnet/testclient.php has been moved to the
Admin menu under "Development" and rewritten.
- The xmlrpc introspection method profiling is now using php and zend
reflection - which is a lot nicer than the old way, which was using a
php-based php parser. This fixes some inconsistent handling of
methods without arguments that were advertising their return value as
the only method parameter. While this is a *fix*, it breaks BC
slightly - the old 1.9 broken mnet/testclient.php will now not work
properly with 2.0
- Dangerous mode is still supported, but old mod/*/rpclib.php is
now unsupported, due to the fact that any plugin can export mnet
functions with db/mnet.php. This is a slight BC break.
Still TODO:
- TEST TEST TEST
- Document the two small BC breaks in release notes
- Document the contract for db/mnet.php
2010-01-28 05:25:50 +00:00
|
|
|
* @param string $username The username
|
2010-09-17 10:44:56 +00:00
|
|
|
* @param array $courses Assoc array of courses following the structure of mnetservice_enrol_courses
|
mnet MDL-21261 large overhaul. This commit changes:
- The way that mnet rpc functions are registered. Plugins must now
create db/mnet.php which is an array, similar to services.php. This
*replaces* the old mnet_publishes() functions. version.php must be
bumped to trigger this.
- More information about each rpc-available function is stored in the
database, including the class it belongs to, the file it is found in,
and whether or not it is static. Methods that are not static must be
in a class with a constructor that takes no arguments (this can easily
be achieved with a small wrapper if necessary)
- The xmlrpc dispatcher has been rewritten to remove all the
dependencies on hardcoded information about auth,mnet,portfolio and
repository, and just use the information in the database.
- The old hardcoded hidden mnet/testclient.php has been moved to the
Admin menu under "Development" and rewritten.
- The xmlrpc introspection method profiling is now using php and zend
reflection - which is a lot nicer than the old way, which was using a
php-based php parser. This fixes some inconsistent handling of
methods without arguments that were advertising their return value as
the only method parameter. While this is a *fix*, it breaks BC
slightly - the old 1.9 broken mnet/testclient.php will now not work
properly with 2.0
- Dangerous mode is still supported, but old mod/*/rpclib.php is
now unsupported, due to the fact that any plugin can export mnet
functions with db/mnet.php. This is a slight BC break.
Still TODO:
- TEST TEST TEST
- Document the two small BC breaks in release notes
- Document the contract for db/mnet.php
2010-01-28 05:25:50 +00:00
|
|
|
* @return bool
|
2007-01-22 05:46:40 +00:00
|
|
|
*/
|
|
|
|
function update_enrolments($username, $courses) {
|
2010-02-02 03:13:40 +00:00
|
|
|
global $CFG, $DB;
|
|
|
|
$remoteclient = get_mnet_remote_client();
|
2007-01-22 05:46:40 +00:00
|
|
|
|
|
|
|
if (empty($username) || !is_array($courses)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// make sure it is a user we have an in active session
|
|
|
|
// with that host...
|
2010-11-26 09:20:06 +00:00
|
|
|
$mnetsessions = $DB->get_records('mnet_session', array('username' => $username, 'mnethostid' => $remoteclient->id), '', 'id, userid');
|
|
|
|
$userid = null;
|
|
|
|
foreach ($mnetsessions as $mnetsession) {
|
|
|
|
if (is_null($userid)) {
|
|
|
|
$userid = $mnetsession->userid;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ($userid != $mnetsession->userid) {
|
|
|
|
throw new mnet_server_exception(3, 'authfail_usermismatch');
|
|
|
|
}
|
2007-01-22 05:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (empty($courses)) { // no courses? clear out quickly
|
2010-07-17 22:34:12 +00:00
|
|
|
$DB->delete_records('mnetservice_enrol_enrolments', array('hostid'=>$remoteclient->id, 'userid'=>$userid));
|
2007-01-22 05:46:40 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-01-23 02:38:54 +00:00
|
|
|
// IMPORTANT: Ask for remoteid as the first element in the query, so
|
|
|
|
// that the array that comes back is indexed on the same field as the
|
|
|
|
// array that we have received from the remote client
|
2010-07-17 22:34:12 +00:00
|
|
|
$sql = "SELECT c.remoteid, c.id, c.categoryid AS cat_id, c.categoryname AS cat_name, c.sortorder,
|
|
|
|
c.fullname, c.shortname, c.idnumber, c.summary, c.summaryformat, c.startdate,
|
|
|
|
e.id AS enrolmentid
|
|
|
|
FROM {mnetservice_enrol_courses} c
|
|
|
|
LEFT JOIN {mnetservice_enrol_enrolments} e ON (e.hostid = c.hostid AND e.remotecourseid = c.remoteid)
|
|
|
|
WHERE e.userid = ? AND c.hostid = ?";
|
2007-01-23 02:38:54 +00:00
|
|
|
|
2010-02-02 03:13:40 +00:00
|
|
|
$currentcourses = $DB->get_records_sql($sql, array($userid, $remoteclient->id));
|
2007-01-23 02:38:54 +00:00
|
|
|
|
|
|
|
$local_courseid_array = array();
|
2010-07-17 22:34:12 +00:00
|
|
|
foreach($courses as $ix => $course) {
|
2007-01-23 02:38:54 +00:00
|
|
|
|
|
|
|
$course['remoteid'] = $course['id'];
|
2010-02-02 03:13:40 +00:00
|
|
|
$course['hostid'] = (int)$remoteclient->id;
|
2007-01-23 02:38:54 +00:00
|
|
|
$userisregd = false;
|
|
|
|
|
2010-07-17 22:34:12 +00:00
|
|
|
// if we do not have the the information about the remote course, it is not available
|
|
|
|
// to us for remote enrolment - skip
|
|
|
|
if (array_key_exists($course['remoteid'], $currentcourses)) {
|
2007-01-23 02:38:54 +00:00
|
|
|
// Pointer to current course:
|
|
|
|
$currentcourse =& $currentcourses[$course['remoteid']];
|
|
|
|
// We have a record - is it up-to-date?
|
|
|
|
$course['id'] = $currentcourse->id;
|
|
|
|
|
|
|
|
$saveflag = false;
|
|
|
|
|
|
|
|
foreach($course as $key => $value) {
|
|
|
|
if ($currentcourse->$key != $value) {
|
|
|
|
$saveflag = true;
|
|
|
|
$currentcourse->$key = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($saveflag) {
|
2010-07-17 22:34:12 +00:00
|
|
|
$DB->update_record('mnetervice_enrol_courses', $currentcourse);
|
2007-01-23 02:38:54 +00:00
|
|
|
}
|
2007-02-20 17:03:36 +00:00
|
|
|
|
2010-07-17 22:34:12 +00:00
|
|
|
if (isset($currentcourse->enrolmentid) && is_numeric($currentcourse->enrolmentid)) {
|
2007-01-23 02:38:54 +00:00
|
|
|
$userisregd = true;
|
|
|
|
}
|
2010-07-17 22:34:12 +00:00
|
|
|
} else {
|
|
|
|
unset ($courses[$ix]);
|
|
|
|
continue;
|
2007-01-23 02:38:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// By this point, we should always have a $dataObj->id
|
|
|
|
$local_courseid_array[] = $course['id'];
|
|
|
|
|
|
|
|
// Do we have a record for this assignment?
|
|
|
|
if ($userisregd) {
|
|
|
|
// Yes - we know about this one already
|
|
|
|
// We don't want to do updates because the new data is probably
|
|
|
|
// 'less complete' than the data we have.
|
|
|
|
} else {
|
|
|
|
// No - create a record
|
|
|
|
$assignObj = new stdClass();
|
|
|
|
$assignObj->userid = $userid;
|
2010-02-02 03:13:40 +00:00
|
|
|
$assignObj->hostid = (int)$remoteclient->id;
|
2010-07-17 22:34:12 +00:00
|
|
|
$assignObj->remotecourseid = $course['remoteid'];
|
2007-01-23 02:38:54 +00:00
|
|
|
$assignObj->rolename = $course['defaultrolename'];
|
2010-07-17 22:34:35 +00:00
|
|
|
$assignObj->id = $DB->insert_record('mnetservice_enrol_enrolments', $assignObj);
|
2007-01-23 02:38:54 +00:00
|
|
|
}
|
|
|
|
}
|
2007-01-22 05:46:40 +00:00
|
|
|
|
2007-01-23 02:38:54 +00:00
|
|
|
// Clean up courses that the user is no longer enrolled in.
|
2010-11-26 09:20:16 +00:00
|
|
|
if (!empty($local_courseid_array)) {
|
|
|
|
$local_courseid_string = implode(', ', $local_courseid_array);
|
|
|
|
$whereclause = " userid = ? AND hostid = ? AND remotecourseid NOT IN ($local_courseid_string)";
|
|
|
|
$DB->delete_records_select('mnetservice_enrol_enrolments', $whereclause, array($userid, $remoteclient->id));
|
|
|
|
}
|
2007-01-22 05:46:40 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 21:50:40 +00:00
|
|
|
function prevent_local_passwords() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-01-04 03:26:04 +00:00
|
|
|
/**
|
|
|
|
* Returns true if this authentication plugin is 'internal'.
|
|
|
|
*
|
2007-02-20 17:03:36 +00:00
|
|
|
* @return bool
|
2007-01-04 03:26:04 +00:00
|
|
|
*/
|
|
|
|
function is_internal() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns true if this authentication plugin can change the user's
|
|
|
|
* password.
|
|
|
|
*
|
2007-02-20 17:03:36 +00:00
|
|
|
* @return bool
|
2007-01-04 03:26:04 +00:00
|
|
|
*/
|
|
|
|
function can_change_password() {
|
2007-02-21 21:42:10 +00:00
|
|
|
//TODO: it should be able to redirect, right?
|
2007-01-04 03:26:04 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the URL for changing the user's pw, or false if the default can
|
|
|
|
* be used.
|
|
|
|
*
|
2010-08-18 22:07:00 +00:00
|
|
|
* @return moodle_url
|
2007-01-04 03:26:04 +00:00
|
|
|
*/
|
|
|
|
function change_password_url() {
|
2010-08-18 22:07:00 +00:00
|
|
|
return null;
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Poll the IdP server to let it know that a user it has authenticated is still
|
|
|
|
* online
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
function keepalive_client() {
|
2010-02-02 03:13:40 +00:00
|
|
|
global $CFG, $DB;
|
2007-01-04 03:26:04 +00:00
|
|
|
$cutoff = time() - 300; // TODO - find out what the remote server's session
|
|
|
|
// cutoff is, and preempt that
|
|
|
|
|
|
|
|
$sql = "
|
|
|
|
select
|
|
|
|
id,
|
|
|
|
username,
|
|
|
|
mnethostid
|
|
|
|
from
|
2008-06-04 21:54:47 +00:00
|
|
|
{user}
|
2007-01-04 03:26:04 +00:00
|
|
|
where
|
2008-06-04 21:54:47 +00:00
|
|
|
lastaccess > ? AND
|
|
|
|
mnethostid != ?
|
2007-01-04 03:26:04 +00:00
|
|
|
order by
|
|
|
|
mnethostid";
|
|
|
|
|
2008-06-04 21:54:47 +00:00
|
|
|
$immigrants = $DB->get_records_sql($sql, array($cutoff, $CFG->mnet_localhost_id));
|
2007-01-04 03:26:04 +00:00
|
|
|
|
|
|
|
if ($immigrants == false) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
$usersArray = array();
|
|
|
|
foreach($immigrants as $immigrant) {
|
|
|
|
$usersArray[$immigrant->mnethostid][] = $immigrant->username;
|
|
|
|
}
|
|
|
|
|
|
|
|
require_once $CFG->dirroot . '/mnet/xmlrpc/client.php';
|
|
|
|
foreach($usersArray as $mnethostid => $users) {
|
|
|
|
$mnet_peer = new mnet_peer();
|
|
|
|
$mnet_peer->set_id($mnethostid);
|
|
|
|
|
|
|
|
$mnet_request = new mnet_xmlrpc_client();
|
|
|
|
$mnet_request->set_method('auth/mnet/auth.php/keepalive_server');
|
|
|
|
|
|
|
|
// set $token and $useragent parameters
|
|
|
|
$mnet_request->add_param($users);
|
|
|
|
|
|
|
|
if ($mnet_request->send($mnet_peer) === true) {
|
|
|
|
if (!isset($mnet_request->response['code'])) {
|
|
|
|
debugging("Server side error has occured on host $mnethostid");
|
|
|
|
continue;
|
|
|
|
} elseif ($mnet_request->response['code'] > 0) {
|
|
|
|
debugging($mnet_request->response['message']);
|
|
|
|
}
|
2007-02-20 17:03:36 +00:00
|
|
|
|
2007-01-04 03:26:04 +00:00
|
|
|
if (!isset($mnet_request->response['last log id'])) {
|
|
|
|
debugging("Server side error has occured on host $mnethostid\nNo log ID was received.");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
2007-02-20 17:03:36 +00:00
|
|
|
debugging("Server side error has occured on host $mnethostid: " .
|
2007-01-04 03:26:04 +00:00
|
|
|
join("\n", $mnet_request->error));
|
2007-01-11 05:38:45 +00:00
|
|
|
break;
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Receives an array of log entries from an SP and adds them to the mnet_log
|
|
|
|
* table
|
|
|
|
*
|
2014-08-14 15:58:35 +08:00
|
|
|
* @deprecated since Moodle 2.8 Please don't use this function for recording mnet logs.
|
2007-01-04 03:26:04 +00:00
|
|
|
* @param array $array An array of usernames
|
|
|
|
* @return string "All ok" or an error message
|
|
|
|
*/
|
|
|
|
function refresh_log($array) {
|
2014-08-14 15:58:35 +08:00
|
|
|
debugging('refresh_log() is deprecated, The transfer of logs through mnet are no longer recorded.', DEBUG_DEVELOPER);
|
|
|
|
return array('code' => 0, 'message' => 'All ok');
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Receives an array of usernames from a remote machine and prods their
|
|
|
|
* sessions to keep them alive
|
|
|
|
*
|
|
|
|
* @param array $array An array of usernames
|
|
|
|
* @return string "All ok" or an error message
|
|
|
|
*/
|
|
|
|
function keepalive_server($array) {
|
2010-02-02 03:13:40 +00:00
|
|
|
global $CFG, $DB;
|
|
|
|
$remoteclient = get_mnet_remote_client();
|
2007-01-04 03:26:04 +00:00
|
|
|
|
|
|
|
// We don't want to output anything to the client machine
|
|
|
|
$start = ob_start();
|
|
|
|
|
|
|
|
// We'll get session records in batches of 30
|
|
|
|
$superArray = array_chunk($array, 30);
|
|
|
|
|
|
|
|
$returnString = '';
|
|
|
|
|
|
|
|
foreach($superArray as $subArray) {
|
|
|
|
$subArray = array_values($subArray);
|
|
|
|
$instring = "('".implode("', '",$subArray)."')";
|
2008-06-04 21:54:47 +00:00
|
|
|
$query = "select id, session_id, username from {mnet_session} where username in $instring";
|
|
|
|
$results = $DB->get_records_sql($query);
|
2007-01-04 03:26:04 +00:00
|
|
|
|
|
|
|
if ($results == false) {
|
|
|
|
// We seem to have a username that breaks our query:
|
|
|
|
// TODO: Handle this error appropriately
|
|
|
|
$returnString .= "We failed to refresh the session for the following usernames: \n".implode("\n", $subArray)."\n\n";
|
|
|
|
} else {
|
|
|
|
foreach($results as $emigrant) {
|
2013-09-08 08:38:52 +02:00
|
|
|
\core\session\manager::touch_session($emigrant->session_id);
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$end = ob_end_clean();
|
|
|
|
|
2010-02-02 03:13:40 +00:00
|
|
|
if (empty($returnString)) return array('code' => 0, 'message' => 'All ok', 'last log id' => $remoteclient->last_log_id);
|
|
|
|
return array('code' => 1, 'message' => $returnString, 'last log id' => $remoteclient->last_log_id);
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Cron function will be called automatically by cron.php every 5 minutes
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
function cron() {
|
2008-06-04 21:54:47 +00:00
|
|
|
global $DB;
|
2007-01-24 04:25:56 +00:00
|
|
|
|
|
|
|
// run the keepalive client
|
2007-01-04 03:26:04 +00:00
|
|
|
$this->keepalive_client();
|
2007-01-24 04:25:56 +00:00
|
|
|
|
|
|
|
$random100 = rand(0,100);
|
|
|
|
if ($random100 < 10) { // Approximately 10% of the time.
|
|
|
|
// nuke olden sessions
|
2007-04-10 22:23:37 +00:00
|
|
|
$longtime = time() - (1 * 3600 * 24);
|
2008-06-04 21:54:47 +00:00
|
|
|
$DB->delete_records_select('mnet_session', "expires < ?", array($longtime));
|
2007-01-24 04:25:56 +00:00
|
|
|
}
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Cleanup any remote mnet_sessions, kill the local mnet_session data
|
|
|
|
*
|
|
|
|
* This is called by require_logout in moodlelib
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
2007-03-28 08:28:02 +00:00
|
|
|
function prelogout_hook() {
|
2010-02-02 03:13:40 +00:00
|
|
|
global $CFG, $USER;
|
|
|
|
|
2007-04-11 14:01:59 +00:00
|
|
|
if (!is_enabled_auth('mnet')) {
|
2007-03-28 08:28:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-01-04 03:26:04 +00:00
|
|
|
// If the user is local to this Moodle:
|
2010-02-02 03:13:40 +00:00
|
|
|
if ($USER->mnethostid == $this->mnet->id) {
|
2007-01-04 03:26:04 +00:00
|
|
|
$this->kill_children($USER->username, sha1($_SERVER['HTTP_USER_AGENT']));
|
|
|
|
|
|
|
|
// Else the user has hit 'logout' at a Service Provider Moodle:
|
|
|
|
} else {
|
|
|
|
$this->kill_parent($USER->username, sha1($_SERVER['HTTP_USER_AGENT']));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The SP uses this function to kill the session on the parent IdP
|
|
|
|
*
|
|
|
|
* @param string $username Username for session to kill
|
|
|
|
* @param string $useragent SHA1 hash of user agent to look for
|
|
|
|
* @return string A plaintext report of what has happened
|
|
|
|
*/
|
|
|
|
function kill_parent($username, $useragent) {
|
2008-06-04 21:54:47 +00:00
|
|
|
global $CFG, $USER, $DB;
|
|
|
|
|
2007-01-04 03:26:04 +00:00
|
|
|
require_once $CFG->dirroot.'/mnet/xmlrpc/client.php';
|
|
|
|
$sql = "
|
|
|
|
select
|
|
|
|
*
|
|
|
|
from
|
2008-06-04 21:54:47 +00:00
|
|
|
{mnet_session} s
|
2007-01-04 03:26:04 +00:00
|
|
|
where
|
2008-06-04 21:54:47 +00:00
|
|
|
s.username = ? AND
|
|
|
|
s.useragent = ? AND
|
|
|
|
s.mnethostid = ?";
|
2007-01-04 03:26:04 +00:00
|
|
|
|
2008-06-04 21:54:47 +00:00
|
|
|
$mnetsessions = $DB->get_records_sql($sql, array($username, $useragent, $USER->mnethostid));
|
2007-01-04 03:26:04 +00:00
|
|
|
|
2008-06-04 21:54:47 +00:00
|
|
|
$ignore = $DB->delete_records('mnet_session',
|
|
|
|
array('username'=>$username,
|
|
|
|
'useragent'=>$useragent,
|
|
|
|
'mnethostid'=>$USER->mnethostid));
|
2007-01-04 03:26:04 +00:00
|
|
|
|
|
|
|
if (false != $mnetsessions) {
|
|
|
|
$mnet_peer = new mnet_peer();
|
|
|
|
$mnet_peer->set_id($USER->mnethostid);
|
|
|
|
|
|
|
|
$mnet_request = new mnet_xmlrpc_client();
|
|
|
|
$mnet_request->set_method('auth/mnet/auth.php/kill_children');
|
|
|
|
|
|
|
|
// set $token and $useragent parameters
|
|
|
|
$mnet_request->add_param($username);
|
|
|
|
$mnet_request->add_param($useragent);
|
|
|
|
if ($mnet_request->send($mnet_peer) === false) {
|
|
|
|
debugging(join("\n", $mnet_request->error));
|
2007-02-20 17:03:36 +00:00
|
|
|
return false;
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The IdP uses this function to kill child sessions on other hosts
|
|
|
|
*
|
|
|
|
* @param string $username Username for session to kill
|
|
|
|
* @param string $useragent SHA1 hash of user agent to look for
|
|
|
|
* @return string A plaintext report of what has happened
|
|
|
|
*/
|
|
|
|
function kill_children($username, $useragent) {
|
2010-02-02 03:13:40 +00:00
|
|
|
global $CFG, $USER, $DB;
|
2010-02-05 03:56:22 +00:00
|
|
|
$remoteclient = null;
|
|
|
|
if (defined('MNET_SERVER')) {
|
|
|
|
$remoteclient = get_mnet_remote_client();
|
|
|
|
}
|
2007-01-04 03:26:04 +00:00
|
|
|
require_once $CFG->dirroot.'/mnet/xmlrpc/client.php';
|
|
|
|
|
2008-06-04 21:54:47 +00:00
|
|
|
$userid = $DB->get_field('user', 'id', array('mnethostid'=>$CFG->mnet_localhost_id, 'username'=>$username));
|
2007-01-04 03:26:04 +00:00
|
|
|
|
|
|
|
$returnstring = '';
|
2008-09-07 03:22:34 +00:00
|
|
|
|
|
|
|
$mnetsessions = $DB->get_records('mnet_session', array('userid' => $userid, 'useragent' => $useragent));
|
2007-01-04 03:26:04 +00:00
|
|
|
|
|
|
|
if (false == $mnetsessions) {
|
2008-09-07 03:26:10 +00:00
|
|
|
$returnstring .= "Could find no remote sessions\n";
|
2007-01-04 03:26:04 +00:00
|
|
|
$mnetsessions = array();
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach($mnetsessions as $mnetsession) {
|
2008-09-07 03:24:56 +00:00
|
|
|
// If this script is being executed by a remote peer, that means the user has clicked
|
|
|
|
// logout on that peer, and the session on that peer can be deleted natively.
|
|
|
|
// Skip over it.
|
2010-02-02 03:13:40 +00:00
|
|
|
if (isset($remoteclient->id) && ($mnetsession->mnethostid == $remoteclient->id)) {
|
2008-09-07 03:24:56 +00:00
|
|
|
continue;
|
|
|
|
}
|
2007-01-04 03:26:04 +00:00
|
|
|
$returnstring .= "Deleting session\n";
|
|
|
|
|
|
|
|
$mnet_peer = new mnet_peer();
|
|
|
|
$mnet_peer->set_id($mnetsession->mnethostid);
|
|
|
|
|
|
|
|
$mnet_request = new mnet_xmlrpc_client();
|
|
|
|
$mnet_request->set_method('auth/mnet/auth.php/kill_child');
|
|
|
|
|
|
|
|
// set $token and $useragent parameters
|
|
|
|
$mnet_request->add_param($username);
|
|
|
|
$mnet_request->add_param($useragent);
|
|
|
|
if ($mnet_request->send($mnet_peer) === false) {
|
2008-03-26 15:13:25 +00:00
|
|
|
debugging("Server side error has occured on host $mnetsession->mnethostid: " .
|
2007-01-04 03:26:04 +00:00
|
|
|
join("\n", $mnet_request->error));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-04 21:54:47 +00:00
|
|
|
$ignore = $DB->delete_records('mnet_session',
|
|
|
|
array('useragent'=>$useragent, 'userid'=>$userid));
|
2007-01-04 03:26:04 +00:00
|
|
|
|
2010-02-02 03:13:40 +00:00
|
|
|
if (isset($remoteclient) && isset($remoteclient->id)) {
|
2013-09-08 08:38:52 +02:00
|
|
|
\core\session\manager::kill_user_sessions($userid);
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
return $returnstring;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2010-02-01 02:01:18 +00:00
|
|
|
* When the IdP requests that child sessions are terminated,
|
2007-01-04 03:26:04 +00:00
|
|
|
* this function will be called on each of the child hosts. The machine that
|
|
|
|
* calls the function (over xmlrpc) provides us with the mnethostid we need.
|
|
|
|
*
|
|
|
|
* @param string $username Username for session to kill
|
2012-11-30 09:23:17 +08:00
|
|
|
* @param string $useragent SHA1 hash of user agent to look for
|
2007-01-04 03:26:04 +00:00
|
|
|
* @return bool True on success
|
|
|
|
*/
|
|
|
|
function kill_child($username, $useragent) {
|
2010-02-02 03:13:40 +00:00
|
|
|
global $CFG, $DB;
|
|
|
|
$remoteclient = get_mnet_remote_client();
|
2012-11-30 09:23:17 +08:00
|
|
|
$session = $DB->get_record('mnet_session', array('username'=>$username, 'mnethostid'=>$remoteclient->id, 'useragent'=>$useragent));
|
|
|
|
$DB->delete_records('mnet_session', array('username'=>$username, 'mnethostid'=>$remoteclient->id, 'useragent'=>$useragent));
|
2007-01-04 03:26:04 +00:00
|
|
|
if (false != $session) {
|
2013-09-08 08:38:52 +02:00
|
|
|
\core\session\manager::kill_session($session->session_id);
|
2007-01-04 03:26:04 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* To delete a host, we must delete all current sessions that users from
|
|
|
|
* that host are currently engaged in.
|
|
|
|
*
|
|
|
|
* @param string $sessionidarray An array of session hashes
|
|
|
|
* @return bool True on success
|
|
|
|
*/
|
|
|
|
function end_local_sessions(&$sessionArray) {
|
|
|
|
global $CFG;
|
|
|
|
if (is_array($sessionArray)) {
|
|
|
|
while($session = array_pop($sessionArray)) {
|
2013-09-08 08:38:52 +02:00
|
|
|
\core\session\manager::kill_session($session->session_id);
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2010-11-26 09:19:55 +00:00
|
|
|
* Returns the user's profile image info
|
2007-01-04 03:26:04 +00:00
|
|
|
*
|
2010-11-26 09:19:55 +00:00
|
|
|
* If the user exists and has a profile picture, the returned array will contain keys:
|
|
|
|
* f1 - the content of the default 100x100px image
|
|
|
|
* f1_mimetype - the mimetype of the f1 file
|
|
|
|
* f2 - the content of the 35x35px variant of the image
|
|
|
|
* f2_mimetype - the mimetype of the f2 file
|
|
|
|
*
|
|
|
|
* The mimetype information was added in Moodle 2.0. In Moodle 1.x, images are always jpegs.
|
|
|
|
*
|
|
|
|
* @see process_new_icon()
|
|
|
|
* @uses mnet_remote_client callable via MNet XML-RPC
|
2016-03-21 11:03:24 +08:00
|
|
|
* @param int $username The id of the user
|
2010-11-26 09:19:55 +00:00
|
|
|
* @return false|array false if user not found, empty array if no picture exists, array with data otherwise
|
2007-01-04 03:26:04 +00:00
|
|
|
*/
|
|
|
|
function fetch_user_image($username) {
|
2008-06-04 21:54:47 +00:00
|
|
|
global $CFG, $DB;
|
2007-01-04 03:26:04 +00:00
|
|
|
|
2010-11-26 09:19:55 +00:00
|
|
|
if ($user = $DB->get_record('user', array('username' => $username, 'mnethostid' => $CFG->mnet_localhost_id))) {
|
|
|
|
$fs = get_file_storage();
|
2012-08-02 11:20:48 +08:00
|
|
|
$usercontext = context_user::instance($user->id, MUST_EXIST);
|
2007-01-04 03:26:04 +00:00
|
|
|
$return = array();
|
2010-11-26 09:19:55 +00:00
|
|
|
if ($f1 = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f1.png')) {
|
|
|
|
$return['f1'] = base64_encode($f1->get_content());
|
|
|
|
$return['f1_mimetype'] = $f1->get_mimetype();
|
|
|
|
} else if ($f1 = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f1.jpg')) {
|
|
|
|
$return['f1'] = base64_encode($f1->get_content());
|
|
|
|
$return['f1_mimetype'] = $f1->get_mimetype();
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
2010-11-26 09:19:55 +00:00
|
|
|
if ($f2 = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f2.png')) {
|
|
|
|
$return['f2'] = base64_encode($f2->get_content());
|
|
|
|
$return['f2_mimetype'] = $f2->get_mimetype();
|
|
|
|
} else if ($f2 = $fs->get_file($usercontext->id, 'user', 'icon', 0, '/', 'f2.jpg')) {
|
|
|
|
$return['f2'] = base64_encode($f2->get_content());
|
|
|
|
$return['f2_mimetype'] = $f2->get_mimetype();
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
return $return;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the theme information and logo url as strings.
|
|
|
|
*
|
|
|
|
* @return string The theme info
|
|
|
|
*/
|
|
|
|
function fetch_theme_info() {
|
|
|
|
global $CFG;
|
|
|
|
|
|
|
|
$themename = "$CFG->theme";
|
|
|
|
$logourl = "$CFG->wwwroot/theme/$CFG->theme/images/logo.jpg";
|
|
|
|
|
|
|
|
$return['themename'] = $themename;
|
|
|
|
$return['logourl'] = $logourl;
|
|
|
|
return $return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determines if an MNET host is providing the nominated service.
|
|
|
|
*
|
|
|
|
* @param int $mnethostid The id of the remote host
|
|
|
|
* @param string $servicename The name of the service
|
|
|
|
* @return bool Whether the service is available on the remote host
|
|
|
|
*/
|
|
|
|
function has_service($mnethostid, $servicename) {
|
2008-06-04 21:54:47 +00:00
|
|
|
global $CFG, $DB;
|
2007-01-04 03:26:04 +00:00
|
|
|
|
|
|
|
$sql = "
|
|
|
|
SELECT
|
|
|
|
svc.id as serviceid,
|
|
|
|
svc.name,
|
|
|
|
svc.description,
|
|
|
|
svc.offer,
|
|
|
|
svc.apiversion,
|
|
|
|
h2s.id as h2s_id
|
|
|
|
FROM
|
2008-08-11 04:48:00 +00:00
|
|
|
{mnet_host} h,
|
2008-06-04 21:54:47 +00:00
|
|
|
{mnet_service} svc,
|
|
|
|
{mnet_host2service} h2s
|
2007-01-04 03:26:04 +00:00
|
|
|
WHERE
|
2008-08-11 04:48:00 +00:00
|
|
|
h.deleted = '0' AND
|
|
|
|
h.id = h2s.hostid AND
|
2008-06-04 21:54:47 +00:00
|
|
|
h2s.hostid = ? AND
|
2007-01-04 03:26:04 +00:00
|
|
|
h2s.serviceid = svc.id AND
|
2008-06-04 21:54:47 +00:00
|
|
|
svc.name = ? AND
|
2007-01-04 03:26:04 +00:00
|
|
|
h2s.subscribe = '1'";
|
|
|
|
|
2008-06-04 21:54:47 +00:00
|
|
|
return $DB->get_records_sql($sql, array($mnethostid, $servicename));
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks the MNET access control table to see if the username/mnethost
|
|
|
|
* is permitted to login to this moodle.
|
|
|
|
*
|
|
|
|
* @param string $username The username
|
|
|
|
* @param int $mnethostid The id of the remote mnethost
|
|
|
|
* @return bool Whether the user can login from the remote host
|
|
|
|
*/
|
|
|
|
function can_login_remotely($username, $mnethostid) {
|
2008-06-04 21:54:47 +00:00
|
|
|
global $DB;
|
|
|
|
|
2007-01-23 21:27:50 +00:00
|
|
|
$accessctrl = 'allow';
|
2008-06-04 21:54:47 +00:00
|
|
|
$aclrecord = $DB->get_record('mnet_sso_access_control', array('username'=>$username, 'mnet_host_id'=>$mnethostid));
|
2007-01-04 03:26:04 +00:00
|
|
|
if (!empty($aclrecord)) {
|
2007-01-23 21:27:50 +00:00
|
|
|
$accessctrl = $aclrecord->accessctrl;
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
2007-01-23 21:27:50 +00:00
|
|
|
return $accessctrl == 'allow';
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|
2007-03-22 12:27:52 +00:00
|
|
|
|
2007-03-28 08:28:02 +00:00
|
|
|
function logoutpage_hook() {
|
2008-06-04 21:54:47 +00:00
|
|
|
global $USER, $CFG, $redirect, $DB;
|
2007-03-22 12:27:52 +00:00
|
|
|
|
|
|
|
if (!empty($USER->mnethostid) and $USER->mnethostid != $CFG->mnet_localhost_id) {
|
2008-06-04 21:54:47 +00:00
|
|
|
$host = $DB->get_record('mnet_host', array('id'=>$USER->mnethostid));
|
2007-03-22 12:27:52 +00:00
|
|
|
$redirect = $host->wwwroot.'/';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-30 01:17:55 +00:00
|
|
|
/**
|
|
|
|
* Trims a log line from mnet peer to limit each part to a length which can be stored in our DB
|
|
|
|
*
|
|
|
|
* @param object $logline The log information to be trimmed
|
|
|
|
* @return object The passed logline object trimmed to not exceed storable limits
|
|
|
|
*/
|
|
|
|
function trim_logline ($logline) {
|
|
|
|
$limits = array('ip' => 15, 'coursename' => 40, 'module' => 20, 'action' => 40,
|
|
|
|
'url' => 255);
|
|
|
|
foreach ($limits as $property => $limit) {
|
|
|
|
if (isset($logline->$property)) {
|
|
|
|
$logline->$property = substr($logline->$property, 0, $limit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $logline;
|
|
|
|
}
|
|
|
|
|
2010-02-18 01:30:13 +00:00
|
|
|
/**
|
2017-04-18 16:23:11 +02:00
|
|
|
* Returns a list of MNet IdPs that the user can roam from.
|
2010-02-18 01:30:13 +00:00
|
|
|
*
|
2017-04-18 16:23:11 +02:00
|
|
|
* @param string $wantsurl The relative url fragment the user wants to get to.
|
|
|
|
* @return array List of arrays with keys url, icon and name.
|
2010-02-18 01:30:13 +00:00
|
|
|
*/
|
|
|
|
function loginpage_idp_list($wantsurl) {
|
|
|
|
global $DB, $CFG;
|
2010-11-09 15:39:07 +00:00
|
|
|
|
2010-02-18 01:30:13 +00:00
|
|
|
// strip off wwwroot, since the remote site will prefix it's return url with this
|
|
|
|
$wantsurl = preg_replace('/(' . preg_quote($CFG->wwwroot, '/') . '|' . preg_quote($CFG->httpswwwroot, '/') . ')/', '', $wantsurl);
|
2010-11-09 15:39:07 +00:00
|
|
|
|
|
|
|
$sql = "SELECT DISTINCT h.id, h.wwwroot, h.name, a.sso_jump_url, a.name as application
|
|
|
|
FROM {mnet_host} h
|
|
|
|
JOIN {mnet_host2service} m ON h.id = m.hostid
|
|
|
|
JOIN {mnet_service} s ON s.id = m.serviceid
|
|
|
|
JOIN {mnet_application} a ON h.applicationid = a.id
|
|
|
|
WHERE s.name = ? AND h.deleted = ? AND m.publish = ?";
|
|
|
|
$params = array('sso_sp', 0, 1);
|
|
|
|
|
|
|
|
if (!empty($CFG->mnet_all_hosts_id)) {
|
|
|
|
$sql .= " AND h.id <> ?";
|
|
|
|
$params[] = $CFG->mnet_all_hosts_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$hosts = $DB->get_records_sql($sql, $params)) {
|
2010-02-18 01:30:13 +00:00
|
|
|
return array();
|
|
|
|
}
|
2010-11-09 15:39:07 +00:00
|
|
|
|
2010-02-18 01:30:13 +00:00
|
|
|
$idps = array();
|
|
|
|
foreach ($hosts as $host) {
|
|
|
|
$idps[] = array(
|
|
|
|
'url' => new moodle_url($host->wwwroot . $host->sso_jump_url, array('hostwwwroot' => $CFG->wwwroot, 'wantsurl' => $wantsurl, 'remoteurl' => 1)),
|
|
|
|
'icon' => new pix_icon('i/' . $host->application . '_host', $host->name),
|
|
|
|
'name' => $host->name,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return $idps;
|
|
|
|
}
|
2017-04-03 10:50:09 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Test if settings are correct, print info to output.
|
|
|
|
*/
|
|
|
|
public function test_settings() {
|
|
|
|
global $CFG, $OUTPUT, $DB;
|
|
|
|
|
|
|
|
// Generate warning if MNET is disabled.
|
|
|
|
if (empty($CFG->mnet_dispatcher_mode) || $CFG->mnet_dispatcher_mode !== 'strict') {
|
|
|
|
echo $OUTPUT->notification(get_string('mnetdisabled', 'mnet'), 'notifyproblem');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate full list of ID and service providers.
|
|
|
|
$query = "
|
|
|
|
SELECT
|
|
|
|
h.id,
|
|
|
|
h.name as hostname,
|
|
|
|
h.wwwroot,
|
|
|
|
h2idp.publish as idppublish,
|
|
|
|
h2idp.subscribe as idpsubscribe,
|
|
|
|
idp.name as idpname,
|
|
|
|
h2sp.publish as sppublish,
|
|
|
|
h2sp.subscribe as spsubscribe,
|
|
|
|
sp.name as spname
|
|
|
|
FROM
|
|
|
|
{mnet_host} h
|
|
|
|
LEFT JOIN
|
|
|
|
{mnet_host2service} h2idp
|
|
|
|
ON
|
|
|
|
(h.id = h2idp.hostid AND
|
|
|
|
(h2idp.publish = 1 OR
|
|
|
|
h2idp.subscribe = 1))
|
|
|
|
INNER JOIN
|
|
|
|
{mnet_service} idp
|
|
|
|
ON
|
|
|
|
(h2idp.serviceid = idp.id AND
|
|
|
|
idp.name = 'sso_idp')
|
|
|
|
LEFT JOIN
|
|
|
|
{mnet_host2service} h2sp
|
|
|
|
ON
|
|
|
|
(h.id = h2sp.hostid AND
|
|
|
|
(h2sp.publish = 1 OR
|
|
|
|
h2sp.subscribe = 1))
|
|
|
|
INNER JOIN
|
|
|
|
{mnet_service} sp
|
|
|
|
ON
|
|
|
|
(h2sp.serviceid = sp.id AND
|
|
|
|
sp.name = 'sso_sp')
|
|
|
|
WHERE
|
|
|
|
((h2idp.publish = 1 AND h2sp.subscribe = 1) OR
|
|
|
|
(h2sp.publish = 1 AND h2idp.subscribe = 1)) AND
|
|
|
|
h.id != ?
|
|
|
|
ORDER BY
|
|
|
|
h.name ASC";
|
|
|
|
|
|
|
|
$idproviders = array();
|
|
|
|
$serviceproviders = array();
|
|
|
|
if ($resultset = $DB->get_records_sql($query, array($CFG->mnet_localhost_id))) {
|
|
|
|
foreach ($resultset as $hostservice) {
|
|
|
|
if (!empty($hostservice->idppublish) && !empty($hostservice->spsubscribe)) {
|
|
|
|
$serviceproviders[] = array('id' => $hostservice->id,
|
|
|
|
'name' => $hostservice->hostname,
|
|
|
|
'wwwroot' => $hostservice->wwwroot);
|
|
|
|
}
|
|
|
|
if (!empty($hostservice->idpsubscribe) && !empty($hostservice->sppublish)) {
|
|
|
|
$idproviders[] = array('id' => $hostservice->id,
|
|
|
|
'name' => $hostservice->hostname,
|
|
|
|
'wwwroot' => $hostservice->wwwroot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ID Providers.
|
|
|
|
$table = html_writer::start_tag('table', array('class' => 'generaltable'));
|
|
|
|
|
|
|
|
$count = 0;
|
|
|
|
foreach ($idproviders as $host) {
|
|
|
|
$table .= html_writer::start_tag('tr');
|
|
|
|
$table .= html_writer::start_tag('td');
|
|
|
|
$table .= $host['name'];
|
|
|
|
$table .= html_writer::end_tag('td');
|
|
|
|
$table .= html_writer::start_tag('td');
|
|
|
|
$table .= $host['wwwroot'];
|
|
|
|
$table .= html_writer::end_tag('td');
|
|
|
|
$table .= html_writer::end_tag('tr');
|
|
|
|
$count++;
|
|
|
|
}
|
|
|
|
$table .= html_writer::end_tag('table');
|
|
|
|
|
|
|
|
if ($count > 0) {
|
|
|
|
echo html_writer::tag('h3', get_string('auth_mnet_roamin', 'auth_mnet'));
|
|
|
|
echo $table;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Service Providers.
|
|
|
|
unset($table);
|
|
|
|
$table = html_writer::start_tag('table', array('class' => 'generaltable'));
|
|
|
|
$count = 0;
|
|
|
|
foreach ($serviceproviders as $host) {
|
|
|
|
$table .= html_writer::start_tag('tr');
|
|
|
|
$table .= html_writer::start_tag('td');
|
|
|
|
$table .= $host['name'];
|
|
|
|
$table .= html_writer::end_tag('td');
|
|
|
|
$table .= html_writer::start_tag('td');
|
|
|
|
$table .= $host['wwwroot'];
|
|
|
|
$table .= html_writer::end_tag('td');
|
|
|
|
$table .= html_writer::end_tag('tr');
|
|
|
|
$count++;
|
|
|
|
}
|
|
|
|
$table .= html_writer::end_tag('table');
|
|
|
|
if ($count > 0) {
|
|
|
|
echo html_writer::tag('h3', get_string('auth_mnet_roamout', 'auth_mnet'));
|
|
|
|
echo $table;
|
|
|
|
}
|
|
|
|
}
|
2007-01-04 03:26:04 +00:00
|
|
|
}
|