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; $this->requesttext = xmlrpc_encode_request($this->method, $this->params, array("encoding" => "utf-8")); $this->signedrequest = xmldsig_envelope($this->requesttext); $this->encryptedrequest = xmlenc_envelope($this->signedrequest, $this->peer->certificate); $config = array(CURLOPT_URL => $URL, CURLOPT_TIMEOUT => $this->timeout, CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_USERAGENT => 'Mahara', CURLOPT_POSTFIELDS => $this->encryptedrequest, CURLOPT_HTTPHEADER => array("Content-Type: text/xml charset=UTF-8", 'Expect: '), CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => 0); $result = mahara_http_request($config); $timestamp_send = time(); $this->rawresponse = $result->data; $response_code = $result->info['http_code']; $response_code_prefix = substr($response_code, 0, 1); if ('2' != $response_code_prefix) { if ('4' == $response_code_prefix) { throw new XmlrpcClientException('Client error code: ' . $response_code); } else { if ('5' == $response_code_prefix) { throw new XmlrpcClientException('An error occurred at the remote server. Code: ' . $response_code); } } } $timestamp_receive = time(); $remote_timestamp = null; $curl_errno = $result->errno; if ($curl_errno || $this->rawresponse == false) { throw new XmlrpcClientException('Curl error: ' . $curl_errno . ': ' . $result->error); return false; } try { $xml = new SimpleXMLElement(trim($this->rawresponse)); } catch (Exception $e) { log_debug($this->rawresponse); throw new XmlrpcClientException('Payload is not a valid XML document (payload is above)', 6001); } try { if ($xml->getName() == 'encryptedMessage') { $payload_encrypted = true; $wwwroot = (string) $xml->wwwroot; // Strip encryption, using an older code is OK, because we're the client. // The server is able to respond with the correct key, be we're not $payload = xmlenc_envelope_strip($xml, true); } if ($xml->getName() == 'signedMessage') { $payload_signed = true; $remote_timestamp = $xml->timestamp; $payload = xmldsig_envelope_strip($xml); } } catch (CryptException $e) { throw new XmlrpcClientException("An error occurred while decrypting a message sent by {$wwwroot}. Unable to authenticate the user."); } if ($xml->getName() == 'methodResponse') { $this->response = xmlrpc_decode($payload); // Margin of error is the time it took the request to complete. $margin_of_error = $timestamp_receive - $timestamp_send; // Guess the time gap between sending the request and the remote machine // executing the time() function. Marginally better than nothing. $hysteresis = $margin_of_error / 2; if (!empty($remote_timestamp)) { $remote_timestamp = $remote_timestamp - $hysteresis; $time_offset = $remote_timestamp - $timestamp_send; if ($time_offset > self::get_max_server_time_difference()) { 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'); } } throw new XmlrpcClientException('Unknown error occurred: ' . $this->response['faultCode'] . ': ' . $this->response['faultString']); } // Clean up so object can be re-used. $this->requesttext = ''; $this->signedrequest = ''; $this->encryptedrequest = ''; $this->params = array(); $this->method = ''; return true; } else { throw new XmlrpcClientException('Unrecognized XML document form: ' . $payload); } }
/** * Chance for each protocol to modify the out going * raw payload - eg: SOAP encryption and signatures * * @param string $response The raw response value * * @return content */ protected function modify_result($response) { if (!empty($this->publickey)) { // do sigs + encrypt require_once get_config('docroot') . 'api/xmlrpc/lib.php'; $openssl = OpenSslRepo::singleton(); if ($this->payload_signed) { // Sign and encrypt our response, even though we don't know if the // request was signed and encrypted $response = xmldsig_envelope($response); } if ($this->payload_encrypted) { $response = xmlenc_envelope($response, $this->publickey); } } return $response; }
xmlrpc_error($e->getMessage(), $e->getCode()); $response = ob_get_contents(); ob_end_clean(); // Sign and encrypt our response, even though we don't know if the // request was signed and encrypted $response = xmldsig_envelope($response); $peer = get_peer($REMOTEWWWROOT); $response = xmlenc_envelope($response, $peer->certificate); echo $response; exit; } } if ($xml->getName() == 'methodCall') { // $payload ? if (empty($xml->methodName)) { throw new XmlrpcServerException('Payload is not an XML-RPC document', 6008); } $Dispatcher = new Dispatcher($payload, $payload_signed, $payload_encrypted); if ($payload_signed) { $response = xmldsig_envelope($Dispatcher->response); } else { $response = $Dispatcher->response; } if ($payload_encrypted) { $peer = get_peer($REMOTEWWWROOT); $response = xmlenc_envelope($response, $peer->certificate); } echo $response; } else { throw new XmlrpcServerException('Unrecognized XML document form: ' . var_export($xml, 1), 6009); }