/**
* This function sends the SOAP message to the service location and returns SOAP response
*
* @param \SAML2\Message $msg The request that should be sent.
* @param \SimpleSAML_Configuration $srcMetadata The metadata of the issuer of the message.
* @param \SimpleSAML_Configuration $dstMetadata The metadata of the destination of the message.
* @return \SAML2\Message The response we received.
* @throws \Exception
*/
public function send(Message $msg, SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata = null)
{
$issuer = $msg->getIssuer();
$ctxOpts = array('ssl' => array('verify_peer' => true, 'verify_peer_name' => true, 'capture_peer_cert' => true, 'verify_depth' => 5, 'peer_name' => 'as.ite.logon.realme.govt.nz', 'cafile' => 'mysite/certificate-bundle.pem'));
// Determine if we are going to do a MutualSSL connection between the IdP and SP - Shoaib
if ($srcMetadata->hasValue('saml.SOAPClient.certificate')) {
$cert = $srcMetadata->getValue('saml.SOAPClient.certificate');
if ($cert !== false) {
$ctxOpts['ssl']['local_cert'] = SimpleSAML_Utilities::resolveCert($srcMetadata->getString('saml.SOAPClient.certificate'));
if ($srcMetadata->hasValue('saml.SOAPClient.privatekey_pass')) {
$ctxOpts['ssl']['passphrase'] = $srcMetadata->getString('saml.SOAPClient.privatekey_pass');
}
}
} else {
/* Use the SP certificate and privatekey if it is configured. */
$privateKey = SimpleSAML_Utilities::loadPrivateKey($srcMetadata);
$publicKey = SimpleSAML_Utilities::loadPublicKey($srcMetadata);
if ($privateKey !== null && $publicKey !== null && isset($publicKey['PEM'])) {
$keyCertData = $privateKey['PEM'] . $publicKey['PEM'];
$file = SimpleSAML_Utilities::getTempDir() . '/' . sha1($keyCertData) . '.pem';
if (!file_exists($file)) {
SimpleSAML_Utilities::writeFile($file, $keyCertData);
}
$ctxOpts['ssl']['local_cert'] = $file;
if (isset($privateKey['password'])) {
$ctxOpts['ssl']['passphrase'] = $privateKey['password'];
}
}
}
// do peer certificate verification
if ($dstMetadata !== null) {
$peerPublicKeys = $dstMetadata->getPublicKeys('signing', true);
$certData = '';
foreach ($peerPublicKeys as $key) {
if ($key['type'] !== 'X509Certificate') {
continue;
}
$certData .= "-----BEGIN CERTIFICATE-----\n" . chunk_split($key['X509Certificate'], 64) . "-----END CERTIFICATE-----\n";
}
$peerCertFile = SimpleSAML_Utilities::getTempDir() . '/' . sha1($certData) . '.pem';
if (!file_exists($peerCertFile)) {
SimpleSAML_Utilities::writeFile($peerCertFile, $certData);
}
// create ssl context
$ctxOpts['ssl']['verify_peer'] = true;
$ctxOpts['ssl']['verify_depth'] = 1;
$ctxOpts['ssl']['cafile'] = $peerCertFile;
}
$context = stream_context_create($ctxOpts);
if ($context === null) {
throw new \Exception('Unable to create SSL stream context');
}
$options = array('uri' => $issuer, 'location' => $msg->getDestination(), 'stream_context' => $context);
if ($srcMetadata->hasValue('saml.SOAPClient.proxyhost')) {
$options['proxy_host'] = $srcMetadata->getValue('saml.SOAPClient.proxyhost');
}
if ($srcMetadata->hasValue('saml.SOAPClient.proxyport')) {
$options['proxy_port'] = $srcMetadata->getValue('saml.SOAPClient.proxyport');
}
$x = new SoapClient(null, $options);
// Add soap-envelopes
$request = $msg->toSignedXML();
$request = self::START_SOAP_ENVELOPE . $request->ownerDocument->saveXML($request) . self::END_SOAP_ENVELOPE;
Utils::getContainer()->debugMessage($request, 'out');
$action = 'http://www.oasis-open.org/committees/security';
$version = '1.1';
$destination = $msg->getDestination();
/* Perform SOAP Request over HTTP */
$soapresponsexml = $x->__doRequest($request, $destination, $action, $version);
if ($soapresponsexml === null || $soapresponsexml === "") {
throw new \Exception('Empty SOAP response, check peer certificate.');
}
Utils::getContainer()->debugMessage($soapresponsexml, 'in');
// Convert to SAML2\Message (\DOMElement)
try {
$dom = DOMDocumentFactory::fromString($soapresponsexml);
} catch (RuntimeException $e) {
throw new \Exception('Not a SOAP response.', 0, $e);
}
$soapfault = $this->getSOAPFault($dom);
if (isset($soapfault)) {
throw new \Exception($soapfault);
}
//Extract the message from the response
$samlresponse = Utils::xpQuery($dom->firstChild, '/soap-env:Envelope/soap-env:Body/*[1]');
$samlresponse = Message::fromXML($samlresponse[0]);
/* Add validator to message which uses the SSL context. */
self::addSSLValidator($samlresponse, $context);
Utils::getContainer()->getLogger()->debug("Valid ArtifactResponse received from IdP");
return $samlresponse;
}