MDL-14123 Full IPv6 support - replaced mnet ip_in_range() by standard ipv6 compatible...
[moodle.git] / mnet / lib.php
CommitLineData
b16393cb 1<?php // $Id$
71558f85 2/**
3 * Library functions for mnet
4 *
5 * @author Donal McMullan donal@catalyst.net.nz
6 * @version 0.0.1
7 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
8 * @package mnet
9 */
10require_once $CFG->dirroot.'/mnet/xmlrpc/xmlparser.php';
11require_once $CFG->dirroot.'/mnet/peer.php';
12require_once $CFG->dirroot.'/mnet/environment.php';
13
14/// CONSTANTS ///////////////////////////////////////////////////////////
15
16define('RPC_OK', 0);
17define('RPC_NOSUCHFILE', 1);
18define('RPC_NOSUCHCLASS', 2);
19define('RPC_NOSUCHFUNCTION', 3);
20define('RPC_FORBIDDENFUNCTION', 4);
21define('RPC_NOSUCHMETHOD', 5);
22define('RPC_FORBIDDENMETHOD', 6);
23
24$MNET = new mnet_environment();
25$MNET->init();
26
27/**
28 * Strip extraneous detail from a URL or URI and return the hostname
29 *
30 * @param string $uri The URI of a file on the remote computer, optionally
31 * including its http:// prefix like
32 * http://www.example.com/index.html
33 * @return string Just the hostname
34 */
35function mnet_get_hostname_from_uri($uri = null) {
36 $count = preg_match("@^(?:http[s]?://)?([A-Z0-9\-\.]+).*@i", $uri, $matches);
37 if ($count > 0) return $matches[1];
38 return false;
39}
40
41/**
42 * Get the remote machine's SSL Cert
43 *
44 * @param string $uri The URI of a file on the remote computer, including
45 * its http:// or https:// prefix
71558f85 46 * @return string A PEM formatted SSL Certificate.
47 */
25202581 48function mnet_get_public_key($uri, $application=null) {
cc38ff5d 49 global $CFG, $MNET, $DB;
71558f85 50 // The key may be cached in the mnet_set_public_key function...
51 // check this first
52 $key = mnet_set_public_key($uri);
53 if ($key != false) {
54 return $key;
55 }
56
25202581 57 if (empty($application)) {
cc38ff5d 58 $application = $DB->get_record('mnet_application', array('name'=>'moodle'));
25202581 59 }
60
61 $rq = xmlrpc_encode_request('system/keyswap', array($CFG->wwwroot, $MNET->public_key, $application->name), array("encoding" => "utf-8"));
62 $ch = curl_init($uri . $application->xmlrpc_server_url);
71558f85 63
64 curl_setopt($ch, CURLOPT_TIMEOUT, 60);
65 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
66 curl_setopt($ch, CURLOPT_POST, true);
67 curl_setopt($ch, CURLOPT_USERAGENT, 'Moodle');
68 curl_setopt($ch, CURLOPT_POSTFIELDS, $rq);
69 curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: text/xml charset=UTF-8"));
6bed4299 70 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
71 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
71558f85 72
2e34d3f9 73 // check for proxy
15c31560 74 if (!empty($CFG->proxyhost) and !is_proxybypass($uri)) {
2e34d3f9 75 // SOCKS supported in PHP5 only
76 if (!empty($CFG->proxytype) and ($CFG->proxytype == 'SOCKS5')) {
77 if (defined('CURLPROXY_SOCKS5')) {
78 curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
79 } else {
80 curl_close($ch);
81 print_error( 'socksnotsupported','mnet' );
82 }
83 }
84
85 curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, false);
86
87 if (empty($CFG->proxyport)) {
88 curl_setopt($ch, CURLOPT_PROXY, $CFG->proxyhost);
89 } else {
90 curl_setopt($ch, CURLOPT_PROXY, $CFG->proxyhost.':'.$CFG->proxyport);
91 }
92
93 if (!empty($CFG->proxyuser) and !empty($CFG->proxypassword)) {
94 curl_setopt($ch, CURLOPT_PROXYUSERPWD, $CFG->proxyuser.':'.$CFG->proxypassword);
95 if (defined('CURLOPT_PROXYAUTH')) {
96 // any proxy authentication if PHP 5.1
97 curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC | CURLAUTH_NTLM);
98 }
99 }
100 }
101
71558f85 102 $res = xmlrpc_decode(curl_exec($ch));
90715d7a 103
104 // check for curl errors
105 $curlerrno = curl_errno($ch);
106 if ($curlerrno!=0) {
107 debugging("Request for $uri failed with curl error $curlerrno");
108 }
109
110 // check HTTP error code
111 $info = curl_getinfo($ch);
112 if (!empty($info['http_code']) and ($info['http_code'] != 200)) {
113 debugging("Request for $uri failed with HTTP code ".$info['http_code']);
114 }
115
71558f85 116 curl_close($ch);
117
118 if (!is_array($res)) { // ! error
119 $public_certificate = $res;
120 $credentials=array();
121 if (strlen(trim($public_certificate))) {
122 $credentials = openssl_x509_parse($public_certificate);
123 $host = $credentials['subject']['CN'];
77ba5810 124 if (array_key_exists( 'subjectAltName', $credentials['subject'])) {
125 $host = $credentials['subject']['subjectAltName'];
126 }
71558f85 127 if (strpos($uri, $host) !== false) {
128 mnet_set_public_key($uri, $public_certificate);
129 return $public_certificate;
130 }
90715d7a 131 else {
132 debugging("Request for $uri returned public key for different URI - $host");
133 }
134 }
135 else {
136 debugging("Request for $uri returned empty response");
71558f85 137 }
138 }
90715d7a 139 else {
140 debugging( "Request for $uri returned unexpected result");
141 }
71558f85 142 return false;
143}
144
145/**
146 * Store a URI's public key in a static variable, or retrieve the key for a URI
147 *
148 * @param string $uri The URI of a file on the remote computer, including its
149 * https:// prefix
150 * @param mixed $key A public key to store in the array OR null. If the key
151 * is null, the function will return the previously stored
152 * key for the supplied URI, should it exist.
153 * @return mixed A public key OR true/false.
154 */
155function mnet_set_public_key($uri, $key = null) {
156 static $keyarray = array();
157 if (isset($keyarray[$uri]) && empty($key)) {
158 return $keyarray[$uri];
159 } elseif (!empty($key)) {
160 $keyarray[$uri] = $key;
161 return true;
162 }
163 return false;
164}
165
166/**
167 * Sign a message and return it in an XML-Signature document
168 *
169 * This function can sign any content, but it was written to provide a system of
170 * signing XML-RPC request and response messages. The message will be base64
171 * encoded, so it does not need to be text.
172 *
173 * We compute the SHA1 digest of the message.
174 * We compute a signature on that digest with our private key.
175 * We link to the public key that can be used to verify our signature.
176 * We base64 the message data.
177 * We identify our wwwroot - this must match our certificate's CN
178 *
179 * The XML-RPC document will be parceled inside an XML-SIG document, which holds
180 * the base64_encoded XML as an object, the SHA1 digest of that document, and a
181 * signature of that document using the local private key. This signature will
182 * uniquely identify the RPC document as having come from this server.
183 *
184 * See the {@Link http://www.w3.org/TR/xmldsig-core/ XML-DSig spec} at the W3c
185 * site
186 *
187 * @param string $message The data you want to sign
09f0abb2 188 * @param resource $privatekey The private key to sign the response with
71558f85 189 * @return string An XML-DSig document
190 */
09f0abb2 191function mnet_sign_message($message, $privatekey = null) {
71558f85 192 global $CFG, $MNET;
193 $digest = sha1($message);
09f0abb2 194
195 // If the user hasn't supplied a private key (for example, one of our older,
196 // expired private keys, we get the current default private key and use that.
197 if ($privatekey == null) {
198 $privatekey = $MNET->get_private_key();
199 }
200
201 // The '$sig' value below is returned by reference.
202 // We initialize it first to stop my IDE from complaining.
203 $sig = '';
204 $bool = openssl_sign($message, $sig, $privatekey); // TODO: On failure?
71558f85 205
206 $message = '<?xml version="1.0" encoding="iso-8859-1"?>
207 <signedMessage>
208 <Signature Id="MoodleSignature" xmlns="http://www.w3.org/2000/09/xmldsig#">
209 <SignedInfo>
210 <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
211 <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/>
212 <Reference URI="#XMLRPC-MSG">
213 <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
214 <DigestValue>'.$digest.'</DigestValue>
215 </Reference>
216 </SignedInfo>
217 <SignatureValue>'.base64_encode($sig).'</SignatureValue>
218 <KeyInfo>
219 <RetrievalMethod URI="'.$CFG->wwwroot.'/mnet/publickey.php"/>
220 </KeyInfo>
221 </Signature>
222 <object ID="XMLRPC-MSG">'.base64_encode($message).'</object>
223 <wwwroot>'.$MNET->wwwroot.'</wwwroot>
13c9d7e0 224 <timestamp>'.time().'</timestamp>
71558f85 225 </signedMessage>';
226 return $message;
227}
228
229/**
230 * Encrypt a message and return it in an XML-Encrypted document
231 *
232 * This function can encrypt any content, but it was written to provide a system
233 * of encrypting XML-RPC request and response messages. The message will be
234 * base64 encoded, so it does not need to be text - binary data should work.
235 *
236 * We compute the SHA1 digest of the message.
237 * We compute a signature on that digest with our private key.
238 * We link to the public key that can be used to verify our signature.
239 * We base64 the message data.
240 * We identify our wwwroot - this must match our certificate's CN
241 *
242 * The XML-RPC document will be parceled inside an XML-SIG document, which holds
243 * the base64_encoded XML as an object, the SHA1 digest of that document, and a
244 * signature of that document using the local private key. This signature will
245 * uniquely identify the RPC document as having come from this server.
246 *
247 * See the {@Link http://www.w3.org/TR/xmlenc-core/ XML-ENC spec} at the W3c
248 * site
249 *
250 * @param string $message The data you want to sign
251 * @param string $remote_certificate Peer's certificate in PEM format
252 * @return string An XML-ENC document
253 */
254function mnet_encrypt_message($message, $remote_certificate) {
255 global $MNET;
256
257 // Generate a key resource from the remote_certificate text string
258 $publickey = openssl_get_publickey($remote_certificate);
259
260 if ( gettype($publickey) != 'resource' ) {
261 // Remote certificate is faulty.
262 return false;
263 }
264
265 // Initialize vars
266 $encryptedstring = '';
267 $symmetric_keys = array();
268
269 // passed by ref -> &$encryptedstring &$symmetric_keys
270 $bool = openssl_seal($message, $encryptedstring, $symmetric_keys, array($publickey));
271 $message = $encryptedstring;
272 $symmetrickey = array_pop($symmetric_keys);
273
274 $message = '<?xml version="1.0" encoding="iso-8859-1"?>
275 <encryptedMessage>
276 <EncryptedData Id="ED" xmlns="http://www.w3.org/2001/04/xmlenc#">
277 <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#arcfour"/>
278 <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
279 <ds:RetrievalMethod URI="#EK" Type="http://www.w3.org/2001/04/xmlenc#EncryptedKey"/>
280 <ds:KeyName>XMLENC</ds:KeyName>
281 </ds:KeyInfo>
282 <CipherData>
283 <CipherValue>'.base64_encode($message).'</CipherValue>
284 </CipherData>
285 </EncryptedData>
286 <EncryptedKey Id="EK" xmlns="http://www.w3.org/2001/04/xmlenc#">
287 <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
288 <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
289 <ds:KeyName>SSLKEY</ds:KeyName>
290 </ds:KeyInfo>
291 <CipherData>
292 <CipherValue>'.base64_encode($symmetrickey).'</CipherValue>
293 </CipherData>
294 <ReferenceList>
295 <DataReference URI="#ED"/>
296 </ReferenceList>
297 <CarriedKeyName>XMLENC</CarriedKeyName>
298 </EncryptedKey>
299 <wwwroot>'.$MNET->wwwroot.'</wwwroot>
300 </encryptedMessage>';
301 return $message;
302}
303
304/**
305 * Get your SSL keys from the database, or create them (if they don't exist yet)
306 *
307 * Get your SSL keys from the database, or (if they don't exist yet) call
308 * mnet_generate_keypair to create them
309 *
310 * @param string $string The text you want to sign
311 * @return string The signature over that text
312 */
313function mnet_get_keypair() {
a5d424df 314 global $CFG, $DB;;
71558f85 315 static $keypair = null;
316 if (!is_null($keypair)) return $keypair;
a5d424df 317 if ($result = $DB->get_field('config_plugins', 'value', array('plugin'=>'mnet', 'name'=>'openssl'))) {
e945004f 318 list($keypair['certificate'], $keypair['keypair_PEM']) = explode('@@@@@@@@', $result);
71558f85 319 $keypair['privatekey'] = openssl_pkey_get_private($keypair['keypair_PEM']);
320 $keypair['publickey'] = openssl_pkey_get_public($keypair['certificate']);
321 return $keypair;
322 } else {
323 $keypair = mnet_generate_keypair();
324 return $keypair;
325 }
326}
327
328/**
329 * Generate public/private keys and store in the config table
330 *
331 * Use the distinguished name provided to create a CSR, and then sign that CSR
332 * with the same credentials. Store the keypair you create in the config table.
333 * If a distinguished name is not provided, create one using the fullname of
334 * 'the course with ID 1' as your organization name, and your hostname (as
335 * detailed in $CFG->wwwroot).
336 *
337 * @param array $dn The distinguished name of the server
338 * @return string The signature over that text
339 */
735c7beb 340function mnet_generate_keypair($dn = null, $days=28) {
cc38ff5d 341 global $CFG, $USER, $DB;
38612df8 342
343 // check if lifetime has been overriden
344 if (!empty($CFG->mnetkeylifetime)) {
345 $days = $CFG->mnetkeylifetime;
346 }
347
71558f85 348 $host = strtolower($CFG->wwwroot);
349 $host = ereg_replace("^http(s)?://",'',$host);
350 $break = strpos($host.'/' , '/');
351 $host = substr($host, 0, $break);
352
cc38ff5d 353 if ($result = $DB->get_record('course', array("id"=>SITEID))) {
71558f85 354 $organization = $result->fullname;
355 } else {
356 $organization = 'None';
357 }
358
359 $keypair = array();
13c9d7e0 360
361 $country = 'NZ';
362 $province = 'Wellington';
363 $locality = 'Wellington';
364 $email = $CFG->noreplyaddress;
365
366 if(!empty($USER->country)) {
367 $country = $USER->country;
368 }
369 if(!empty($USER->city)) {
370 $province = $USER->city;
371 $locality = $USER->city;
372 }
373 if(!empty($USER->email)) {
374 $email = $USER->email;
375 }
71558f85 376
377 if (is_null($dn)) {
378 $dn = array(
13c9d7e0 379 "countryName" => $country,
380 "stateOrProvinceName" => $province,
381 "localityName" => $locality,
71558f85 382 "organizationName" => $organization,
383 "organizationalUnitName" => 'Moodle',
77ba5810 384 "commonName" => substr($CFG->wwwroot, 0, 64),
385 "subjectAltName" => $CFG->wwwroot,
13c9d7e0 386 "emailAddress" => $email
71558f85 387 );
388 }
389
a4d967a4 390 // ensure we remove trailing slashes
391 $dn["commonName"] = preg_replace(':/$:', '', $dn["commonName"]);
392
71558f85 393 $new_key = openssl_pkey_new();
eb7f89bc 394 if ($new_key === false) {
395 // can not generate keys - missing openssl.cnf??
396 return null;
397 }
71558f85 398 $csr_rsc = openssl_csr_new($dn, $new_key, array('private_key_bits',2048));
735c7beb 399 $selfSignedCert = openssl_csr_sign($csr_rsc, null, $new_key, $days);
71558f85 400 unset($csr_rsc); // Free up the resource
401
13c9d7e0 402 // We export our self-signed certificate to a string.
71558f85 403 openssl_x509_export($selfSignedCert, $keypair['certificate']);
404 openssl_x509_free($selfSignedCert);
405
406 // Export your public/private key pair as a PEM encoded string. You
407 // can protect it with an optional passphrase if you wish.
408 $export = openssl_pkey_export($new_key, $keypair['keypair_PEM'] /* , $passphrase */);
409 openssl_pkey_free($new_key);
410 unset($new_key); // Free up the resource
411
71558f85 412 return $keypair;
413}
414
71558f85 415/**
416 * Check that a given function (or method) in an include file has been designated
417 * ok for export
418 *
419 * @param string $includefile The path to the include file
420 * @param string $functionname The name of the function (or method) to
421 * execute
422 * @param mixed $class A class name, or false if we're just testing
423 * a function
424 * @return int Zero (RPC_OK) if all ok - appropriate
425 * constant otherwise
426 */
427function mnet_permit_rpc_call($includefile, $functionname, $class=false) {
bd2bf451 428 global $CFG, $MNET_REMOTE_CLIENT, $DB;
71558f85 429
430 if (file_exists($CFG->dirroot . $includefile)) {
431 include_once $CFG->dirroot . $includefile;
432 // $callprefix matches the rpc convention
433 // of not having a leading slash
434 $callprefix = preg_replace('!^/!', '', $includefile);
435 } else {
436 return RPC_NOSUCHFILE;
437 }
438
439 if ($functionname != clean_param($functionname, PARAM_PATH)) {
440 // Under attack?
441 // Todo: Should really return a much more BROKEN! response
442 return RPC_FORBIDDENMETHOD;
443 }
444
445 $id_list = $MNET_REMOTE_CLIENT->id;
446 if (!empty($CFG->mnet_all_hosts_id)) {
447 $id_list .= ', '.$CFG->mnet_all_hosts_id;
448 }
449
450 // TODO: change to left-join so we can disambiguate:
451 // 1. method doesn't exist
452 // 2. method exists but is prohibited
453 $sql = "
454 SELECT
455 count(r.id)
456 FROM
cc38ff5d 457 {mnet_host2service} h2s,
458 {mnet_service2rpc} s2r,
459 {mnet_rpc} r
71558f85 460 WHERE
461 h2s.serviceid = s2r.serviceid AND
462 s2r.rpcid = r.id AND
cc38ff5d 463 r.xmlrpc_path = ? AND
71558f85 464 h2s.hostid in ($id_list) AND
465 h2s.publish = '1'";
cc38ff5d 466 $params = array("$callprefix/$functionname");
467 $permissionobj = $DB->record_exists_sql($sql, $params);
71558f85 468
68bcd355 469 if ($permissionobj === false && 'dangerous' != $CFG->mnet_dispatcher_mode) {
71558f85 470 return RPC_FORBIDDENMETHOD;
471 }
472
473 // WE'RE LOOKING AT A CLASS/METHOD
474 if (false != $class) {
475 if (!class_exists($class)) {
476 // Generate error response - unable to locate class
477 return RPC_NOSUCHCLASS;
478 }
479
b91b274b 480 $object = false;
481 $static = false;
482
483 try {
484 // @todo set here whatever we can to ensure that errors cause exceptions :(
485 // see MDL-16175 - long term solution is teaching the dispatcher about:
486 // a: the difference between static and class methods
487 // b: object constructor arguments
488 $object = @new $class();
489 if (!method_exists($object, $functionname)) {
490 // Generate error response - unable to locate method
491 return RPC_NOSUCHMETHOD;
492 }
71558f85 493
b91b274b 494 if (!method_exists($object, 'mnet_publishes')) {
495 // Generate error response - the class doesn't publish
496 // *any* methods, because it doesn't have an mnet_publishes
497 // method
498 return RPC_FORBIDDENMETHOD;
499 }
71558f85 500
b91b274b 501 // Get the list of published services - initialise method array
502 $servicelist = $object->mnet_publishes();
503 }
504 catch (Exception $e) {
505 if (method_exists($class, $functionname)) {
506 // static... don't try to instantiate it.
507 if (!method_exists($class, 'mnet_publishes')) {
508 return RPC_FORBIDDENMETHOD;
509 } else {
510 $servicelist = call_user_func(array($class, 'mnet_publishes'));
511 }
512 $static = $class;
513 }
71558f85 514 }
515
71558f85 516 $methodapproved = false;
517
518 // If the method is in the list of approved methods, set the
519 // methodapproved flag to true and break
520 foreach($servicelist as $service) {
521 if (in_array($functionname, $service['methods'])) {
522 $methodapproved = true;
523 break;
524 }
525 }
526
527 if (!$methodapproved) {
528 return RPC_FORBIDDENMETHOD;
529 }
530
531 // Stash the object so we can call the method on it later
532 $MNET_REMOTE_CLIENT->object_to_call($object);
b91b274b 533 $MNET_REMOTE_CLIENT->static_location($static);
534
71558f85 535 // WE'RE LOOKING AT A FUNCTION
536 } else {
537 if (!function_exists($functionname)) {
538 // Generate error response - unable to locate function
539 return RPC_NOSUCHFUNCTION;
540 }
541
542 }
543
544 return RPC_OK;
545}
546
cdf22329 547function mnet_update_sso_access_control($username, $mnet_host_id, $accessctrl) {
cc38ff5d 548 global $DB;
549
550 $mnethost = $DB->get_record('mnet_host', array('id'=>$mnet_host_id));
551 if ($aclrecord = $DB->get_record('mnet_sso_access_control', array('username'=>$username, 'mnet_host_id'=>$mnet_host_id))) {
71558f85 552 // update
cdf22329 553 $aclrecord->accessctrl = $accessctrl;
cc38ff5d 554 if ($DB->update_record('mnet_sso_access_control', $aclrecord)) {
71558f85 555 add_to_log(SITEID, 'admin/mnet', 'update', 'admin/mnet/access_control.php',
c80934aa 556 "SSO ACL: $accessctrl user '$username' from {$mnethost->name}");
71558f85 557 } else {
2e34d3f9 558 print_error('failedaclwrite', 'mnet', '', $username);
71558f85 559 return false;
560 }
561 } else {
562 // insert
563 $aclrecord->username = $username;
cdf22329 564 $aclrecord->accessctrl = $accessctrl;
71558f85 565 $aclrecord->mnet_host_id = $mnet_host_id;
cc38ff5d 566 if ($id = $DB->insert_record('mnet_sso_access_control', $aclrecord)) {
71558f85 567 add_to_log(SITEID, 'admin/mnet', 'add', 'admin/mnet/access_control.php',
c80934aa 568 "SSO ACL: $accessctrl user '$username' from {$mnethost->name}");
71558f85 569 } else {
2e34d3f9 570 print_error('failedaclwrite', 'mnet', '', $username);
71558f85 571 return false;
572 }
573 }
574 return true;
575}
1ce2da58 576
577function mnet_get_peer_host ($mnethostid) {
578 global $DB;
579 static $hosts;
580 if (!isset($hosts[$mnethostid])) {
581 $host = $DB->get_record('mnet_host', array('id' => $mnethostid));
582 $hosts[$mnethostid] = $host;
583 }
584 return $hosts[$mnethostid];
585}
586
587/**
588 * Inline function to modify a url string so that mnet users are requested to
589 * log in at their mnet identity provider (if they are not already logged in)
590 * before ultimately being directed to the original url.
591 *
baed22bb 592 * uses global MNETIDPJUMPURL the url which user should initially be directed to
593 * MNETIDPJUMPURL is a URL associated with a moodle networking peer when it
594 * is fulfiling a role as an identity provider (IDP). Different urls for
595 * different peers, the jumpurl is formed partly from the IDP's webroot, and
596 * partly from a predefined local path within that webwroot.
597 * The result of the user hitting MNETIDPJUMPURL is that they will be asked
598 * to login (at their identity provider (if they aren't already)), mnet
599 * will prepare the necessary authentication information, then redirect
600 * them back to somewhere at the content provider(CP) moodle (this moodle)
1ce2da58 601 * @param array $url array with 2 elements
602 * 0 - context the url was taken from, possibly just the url, possibly href="url"
603 * 1 - the destination url
604 * @return string the url the remote user should be supplied with.
605 */
606function mnet_sso_apply_indirection ($url) {
baed22bb 607 global $MNETIDPJUMPURL;
078c1134 608 global $CFG;
1ce2da58 609
610 $localpart='';
611 $urlparts = parse_url($url[1]);
612 if($urlparts) {
613 if (isset($urlparts['path'])) {
078c1134 614 $path = $urlparts['path'];
615 // if our wwwroot has a path component, need to strip that path from beginning of the
616 // 'localpart' to make it relative to moodle's wwwroot
617 $wwwrootpath = parse_url($CFG->wwwroot, PHP_URL_PATH);
618 if (!empty($wwwrootpath) and strpos($path, $wwwrootpath) === 0) {
619 $path = substr($path, strlen($wwwrootpath));
620 }
621 $localpart .= $path;
1ce2da58 622 }
623 if (isset($urlparts['query'])) {
624 $localpart .= '?'.$urlparts['query'];
625 }
626 if (isset($urlparts['fragment'])) {
627 $localpart .= '#'.$urlparts['fragment'];
628 }
629 }
baed22bb 630 $indirecturl = $MNETIDPJUMPURL . urlencode($localpart);
1ce2da58 631 //If we matched on more than just a url (ie an html link), return the url to an href format
632 if ($url[0] != $url[1]) {
633 $indirecturl = 'href="'.$indirecturl.'"';
634 }
635 return $indirecturl;
636}
637
638function mnet_get_app_jumppath ($applicationid) {
639 global $DB;
640 static $appjumppaths;
641 if (!isset($appjumppaths[$applicationid])) {
642 $ssojumpurl = $DB->get_field('mnet_application', 'sso_jump_url', array('id' => $applicationid));
643 $appjumppaths[$applicationid] = $ssojumpurl;
644 }
645 return $appjumppaths[$applicationid];
646}
647
71558f85 648?>