Commit d1f250a8 authored by Nigel McNie's avatar Nigel McNie
Browse files

Merge branch 'xmlrpc-auth-fixes'

parents bcede6bd de31ef57
......@@ -47,8 +47,8 @@ class Client {
return $this;
}
function send($wwwroot) {
$this->peer = get_peer($wwwroot);
function send($wwwroot, $use_cached_peer=true) {
$this->peer = get_peer($wwwroot, $use_cached_peer);
$this->response = '';
$URL = $this->peer->wwwroot . $this->peer->application->xmlrpcserverurl;
......@@ -83,14 +83,16 @@ class Client {
$remote_timestamp = null;
if ($this->rawresponse == false) {
throw new Exception('Curl error: '.curl_errno($ch) .':'. curl_error($ch));
throw new XmlrpcClientException('Curl error: '.curl_errno($ch) .':'. curl_error($ch));
return false;
}
try {
$xml = new SimpleXMLElement($this->rawresponse);
} catch (Exception $e) {
throw new Exception('Payload is not a valid XML document', 6001);
}
catch (Exception $e) {
log_debug($this->rawresponse);
throw new XmlrpcClientException('Payload is not a valid XML document (payload is above)', 6001);
}
if ($xml->getName() == 'encryptedMessage') {
......@@ -120,7 +122,40 @@ class Client {
$time_offset = $remote_timestamp - $timestamp_send;
// We've set the maximum time drift between servers to 15 seconds
if ($time_offset > 15) {
throw new MaharaException('Time drift ('.$margin_of_error.', '.$time_offset.') is too large.');
throw new XmlrpcClientException('Time drift ('.$margin_of_error.', '.$time_offset.') is too large.');
}
}
if (is_array($this->response) && array_key_exists('faultCode', $this->response)) {
if ($this->response['faultCode'] == 7025) {
log_info('Remote application has sent us a new public key');
// The remote application sent back a new public key, the
// old one must have expired
if (array_key_exists('faultString', $this->response)) {
$details = openssl_x509_parse($this->response['faultString']);
if (isset($details['validTo_time_t'])) {
$updateobj = (object)array(
'publickey' => $this->response['faultString'],
'publickeyexpires' => $details['validTo_time_t'],
);
$whereobj = (object)array(
'wwwroot' => $wwwroot,
);
update_record('host', $updateobj, $whereobj);
log_info('New key has been imported. Valid until ' . date('Y/m/d h:i:s', $details['validTo_time_t']));
// Send request again. But don't use the cached
// peer, look it up again now we've changed the
// public key
$this->send($wwwroot, false);
}
else {
throw new XmlrpcClientException('Could not parse new public key');
}
}
else {
throw new XmlrpcClientException('Remote site claims to have sent a public key, but they LIE');
}
}
}
......@@ -132,7 +167,7 @@ class Client {
$this->method = '';
return true;
} else {
throw new MaharaException('Unrecognized XML document form: ' . $payload);
throw new XmlrpcClientException('Unrecognized XML document form: ' . $payload);
}
}
......
......@@ -51,6 +51,7 @@ class Dispatcher {
'auth/mnet/auth.php/update_enrolments' => 'xmlrpc_not_implemented',
'auth/mnet/auth.php/keepalive_server' => 'xmlrpc_not_implemented',
'auth/mnet/auth.php/kill_children' => 'xmlrpc_not_implemented',
'auth/mnet/auth.php/kill_child' => 'xmlrpc_not_implemented',
)
);
......
......@@ -440,11 +440,13 @@ function parse_payload($payload) {
}
}
function get_peer($wwwroot) {
function get_peer($wwwroot, $cache=true) {
$wwwroot = (string)$wwwroot;
static $peers = array();
if (isset($peers[$wwwroot])) return $peers[$wwwroot];
if ($cache) {
if (isset($peers[$wwwroot])) return $peers[$wwwroot];
}
require_once(get_config('libroot') . 'peer.php');
$peer = new Peer();
......
......@@ -99,46 +99,12 @@ try {
// Cascading switch. Kinda.
if ($xml->getName() == 'encryptedMessage') {
// The IP address for the hostname supplied by the client.
// This hostname can't be trusted.
$ipaddress = gethostbyname(get_hostname_from_uri((string)$xml->wwwroot));
// Check for masquerading
if (!get_config('xmlrpc_allow_masquerading') && $ipaddress != $_SERVER['REMOTE_ADDR']) {
if ($networkingdebug) {
throw new XmlrpcServerException('Your hostname ('.
get_hostname_from_uri((string)$xml->wwwroot) .
') resolves to the IP address '.$ipaddress .
' but your IP address is actually '.$_SERVER['REMOTE_ADDR'] , 6012);
}
header($protocol.' 403 Forbidden');
exit;
}
$payload_encrypted = true;
$REMOTEWWWROOT = (string)$xml->wwwroot;
$payload = xmlenc_envelope_strip($xml);
}
if ($xml->getName() == 'signedMessage') {
// The IP address for the hostname supplied by the client.
// This hostname can't be trusted.
$ipaddress = gethostbyname(get_hostname_from_uri((string)$xml->wwwroot));
// Check for masquerading
if (!get_config('xmlrpc_allow_masquerading') && $ipaddress != $_SERVER['REMOTE_ADDR']) {
if ($networkingdebug) {
throw new XmlrpcServerException('Your hostname ('.
get_hostname_from_uri((string)$xml->wwwroot) .
') resolves to the IP address '.$ipaddress .
' but your IP address is actually '.$_SERVER['REMOTE_ADDR'] , 6012);
}
header($protocol.' 403 Forbidden');
exit;
}
$payload_signed = true;
$REMOTEWWWROOT = (string)$xml->wwwroot;
$payload = xmldsig_envelope_strip($xml);
......
......@@ -830,10 +830,6 @@ function auth_draw_login_page($message=null, Pieform $form=null) {
*/
function auth_get_login_form() {
$institutions = get_records_menu('institution', '', '', 'name, displayname');
$defaultinstitution = get_cookie('institution');
if (!$defaultinstitution) {
$defaultinstitution = 'mahara';
}
$elements = array(
'login_username' => array(
......
......@@ -80,6 +80,14 @@ if (empty($instances)) {
throw new ParameterException(get_string('errnoauthinstances','auth'). htmlentities($remotewwwroot, ENT_QUOTES, 'UTF-8'));
}
// If the user is already logged in as someone, log them out. That way, if
// XMLRPC authentication fails, the system isn't left looking stupid as it
// reports that the user couldn't log in while they actually are.
if ($USER->is_logged_in()) {
$USER->logout();
}
$SESSION->set('messages', array());
$rpcconfigured = false;
$res = false;
......@@ -93,10 +101,6 @@ foreach($instances as $instance) {
continue;
// we don't care - a future plugin might accept the user
}
catch (Exception $e) {
log_info($e);
continue;
}
if ($res == true) {
break;
}
......@@ -112,8 +116,8 @@ if ($res == true) {
}
if ($rpcconfigured === false) {
throw new UserNotFoundException(get_string('errnoxmlrcpinstances','auth').htmlentities($remotewwwroot, ENT_QUOTES, 'UTF-8'));
throw new XmlrpcUserNotFoundException(get_string('errnoxmlrcpinstances','auth').htmlentities($remotewwwroot, ENT_QUOTES, 'UTF-8'));
} else {
throw new UserNotFoundException(get_string('errnoxmlrcpuser','auth'));
throw new XmlrpcUserNotFoundException(get_string('errnoxmlrpcuser','auth'));
}
?>
......@@ -105,7 +105,7 @@ class AuthXmlrpc extends Auth {
$peer = get_peer($remotewwwroot);
if ($peer->deleted != 0 || $this->config['theyssoin'] != 1) {
throw new MaharaException('We don\'t accept SSO connections from '.$peer->name );
throw new XmlrpcClientException('We don\'t accept SSO connections from ' . $peer->name);
}
$client = new Client();
......@@ -117,26 +117,12 @@ class AuthXmlrpc extends Auth {
$remoteuser = (object)$client->response;
if (empty($remoteuser) or !property_exists($remoteuser, 'username')) {
$errorobject = $remoteuser;
$errreport = 'Authorisation failure. ';
$faultcode = 1;
if (property_exists($errorobject, 'faultCode')) {
$errreport .= "\nCode: ".$errorobject->faultCode;
$faultcode = $errorobject->faultCode;
}
if (property_exists($errorobject, 'faultString')) {
$errreport .= "\nMessage: ".$errorobject->faultString;
}
throw new AccessDeniedException($errreport, $faultcode);
// Caught by land.php
throw new AccessDeniedException();
}
$virgin = false;
set_cookie('institution', $peer->institution, 0, get_mahara_install_subdirectory());
$oldlastlogin = null;
$create = false;
$update = false;
......@@ -150,6 +136,10 @@ class AuthXmlrpc extends Auth {
}
} catch (AuthUnknownUserException $e) {
if (!empty($this->config['weautocreateusers'])) {
$institution = new Institution($this->institution);
if ($institution->isFull()) {
throw new XmlrpcClientException('SSO attempt from ' . $institution->displayname . ' failed - institution is full');
}
$user = new User;
$create = true;
} else {
......
......@@ -112,12 +112,6 @@ $cfg->developermode = false;
// $cfg->smtpuser = '';
// $cfg->smtppass = '';
// xmlrpc
// if you're running in a configuration where the host contacting you will be
// using an IP address that is not the same as the IP address that is registered
// for its host name, then you should change the value below to 'true'.
$cfg->xmlrpc_allow_masquerading = false;
// maximum allowed size of uploaded images
// NOTE: the scalable resize might result in images with one dimesion larger than one of these sizes, but not both
$cfg->imagemaxwidth = 1024;
......
......@@ -33,7 +33,7 @@ $string['wwwroot'] = 'WWW root';
$string['port'] = 'Port number';
$string['protocol'] = 'Protocol';
$string['changepasswordurl'] = 'Password-change URL';
$string['cannotremove'] = "We can't remove this auth plugin, as it's the only \\nplugin that exists for this institution.";
$string['cannotremove'] = "We can't remove this auth plugin, as it's the only \nplugin that exists for this institution.";
$string['cannotremoveinuse'] = "We can't remove this auth plugin, as it's being used by some users.\nYou must update their records before you can remove this plugin.";
$string['saveinstitutiondetailsfirst'] = 'Please save the institution details before configuring authentication plugins.';
......@@ -59,5 +59,13 @@ $string['cantretrievekey'] = 'An error occurred while retrieving the public key
$string['errnoauthinstances'] = 'We don\'t seem to have any authentication plugin instances configured for the host at ';
$string['errnoxmlrcpinstances'] = 'We don\'t seem to have any XMLRPC authentication plugin instances configured for the host at ';
$string['errnoxmlrcpwwwroot'] = 'We don\'t have a record for any host at ';
$string['errnoxmlrcpuser'] = 'We were unable to authenticate you. Please ask your Mahara administrator to check Mahara\'s authentication plugin settings, and to check that either a user record exists for you on this Mahara, or that Mahara is configured to create new records for users from your Moodle.';
$string['errnoxmlrpcuser'] = "We were unable to authenticate you at this time. Possible reasons might be:
* Your SSO session might have expired. Go back to the other application and click the link to sign into Mahara again.
* You may not be allowed to SSO to Mahara. Please check with your administrator if you think you should be allowed to.";
$string['unabletosigninviasso'] = 'Unable to sign in via SSO';
$string['xmlrpccouldnotlogyouin'] = 'Sorry, could not log you in :(';
$string['xmlrpccouldnotlogyouindetail'] = 'Sorry, we could not log you into Mahara at this time. Please tryin again shortly, and if the problem persists, contact your administrator';
?>
......@@ -486,7 +486,7 @@ class MaharaException extends Exception {
}
$outputtitle = $this->get_string('title');
$outputmessage = $this->render_exception();
$outputmessage = trim($this->render_exception());
if (function_exists('smarty') && !$this instanceof ConfigSanityException) {
$smarty = smarty();
......@@ -556,6 +556,11 @@ EOF;
*/
class SystemException extends MaharaException implements MaharaThrowable {
public function __construct($message, $code=0) {
parent::__construct($message, $code);
$this->set_log();
}
public function render_exception () {
return $this->get_string('message');
}
......@@ -682,7 +687,14 @@ class XmlrpcServerException extends SystemException {}
/**
* Xmlrpc Client exception - Something has gone wrong in the networking
*/
class XmlrpcClientException extends SystemException {}
class XmlrpcClientException extends SystemException {
public function strings() {
return array_merge(parent::strings(), array(
'title' => get_string('xmlrpccouldnotlogyouin'),
'message' => get_string('xmlrpccouldnotlogyouindetail'))
);
}
}
/**
* Error with SSL and encryption
......@@ -719,6 +731,17 @@ class ViewNotFoundException extends NotFoundException {}
*/
class UserNotFoundException extends NotFoundException {}
/**
* Exception - user not found while doing XMLRPC authentication
*/
class XmlrpcUserNotFoundException extends UserNotFoundException {
public function strings() {
return array_merge(parent::strings(),
array('message' => ''),
array('title' => get_string('unabletosigninviasso', 'auth')));
}
}
/**
* Exception - group not found
*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment