/** * Send a SAML 2 message using the HTTP-POST binding. * * Note: This function never returns. * * @param SAML2_Message $message The message we should send. */ public function send(SAML2_Message $message) { if ($this->destination === NULL) { $destination = $message->getDestination(); } else { $destination = $this->destination; } $relayState = $message->getRelayState(); $msgStr = $message->toSignedXML(); $msgStr = $msgStr->ownerDocument->saveXML($msgStr); SimpleSAML_Utilities::debugMessage($msgStr, 'out'); $msgStr = base64_encode($msgStr); $msgStr = htmlspecialchars($msgStr); if ($message instanceof SAML2_Request) { $msgType = 'SAMLRequest'; } else { $msgType = 'SAMLResponse'; } $destination = htmlspecialchars($destination); if ($relayState !== NULL) { $relayState = '<input type="hidden" name="RelayState" value="' . htmlspecialchars($relayState) . '">'; } else { $relayState = ''; } $out = <<<END <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title>POST data</title> </head> <body onload="document.forms[0].submit()"> <noscript> <p><strong>Note:</strong> Since your browser does not support JavaScript, you must press the button below once to proceed.</p> </noscript> <form method="post" action="{$destination}"> <input type="hidden" name="{$msgType}" value="{$msgStr}" /> {$relayState} <noscript><input type="submit" value="Submit" /></noscript> </form> </body> </html> END; echo $out; exit(0); }
/** * Create the redirect URL for a message. * * @param SAML2_Message $message The message. * @return string The URL the user should be redirected to in order to send a message. * @throws Exception */ public function getRedirectURL(SAML2_Message $message) { $store = SimpleSAML_Store::getInstance(); if ($store === FALSE) { throw new Exception('Unable to send artifact without a datastore configured.'); } $generatedId = pack('H*', (string) SimpleSAML_Utilities::stringToHex(SimpleSAML_Utilities::generateRandomBytes(20))); $artifact = base64_encode("" . sha1($message->getIssuer(), TRUE) . $generatedId); $artifactData = $message->toUnsignedXML(); $artifactDataString = $artifactData->ownerDocument->saveXML($artifactData); $store->set('artifact', $artifact, $artifactDataString, time() + 15 * 60); $params = array('SAMLart' => $artifact); $relayState = $message->getRelayState(); if ($relayState !== NULL) { $params['RelayState'] = $relayState; } return SimpleSAML_Utilities::addURLparameter($message->getDestination(), $params); }
/** * Create the redirect URL for a message. * * @param SAML2_Message $message The message. * @return string The URL the user should be redirected to in order to send a message. */ public function getRedirectURL(SAML2_Message $message) { if ($this->destination === NULL) { $destination = $message->getDestination(); } else { $destination = $this->destination; } $relayState = $message->getRelayState(); $key = $message->getSignatureKey(); $msgStr = $message->toUnsignedXML(); $msgStr = $msgStr->ownerDocument->saveXML($msgStr); SimpleSAML_Utilities::debugMessage($msgStr, 'out'); $msgStr = gzdeflate($msgStr); $msgStr = base64_encode($msgStr); /* Build the query string. */ if ($message instanceof SAML2_Request) { $msg = 'SAMLRequest='; } else { $msg = 'SAMLResponse='; } $msg .= urlencode($msgStr); if ($relayState !== NULL) { $msg .= '&RelayState=' . urlencode($relayState); } if ($key !== NULL) { /* Add the signature. */ $msg .= '&SigAlg=' . urlencode(XMLSecurityKey::RSA_SHA1); $signature = $key->signData($msg); $msg .= '&Signature=' . urlencode(base64_encode($signature)); } if (strpos($destination, '?') === FALSE) { $destination .= '?' . $msg; } else { $destination .= '&' . $msg; } return $destination; }
/** * Send a SAML 2 message using the HTTP-POST binding. * * Note: This function never returns. * * @param SAML2_Message $message The message we should send. */ public function send(SAML2_Message $message) { if ($this->destination === NULL) { $destination = $message->getDestination(); } else { $destination = $this->destination; } $relayState = $message->getRelayState(); $msgStr = $message->toSignedXML(); $msgStr = $msgStr->ownerDocument->saveXML($msgStr); SAML2_Utils::getContainer()->debugMessage($msgStr, 'out'); $msgStr = base64_encode($msgStr); if ($message instanceof SAML2_Request) { $msgType = 'SAMLRequest'; } else { $msgType = 'SAMLResponse'; } $post = array(); $post[$msgType] = $msgStr; if ($relayState !== NULL) { $post['RelayState'] = $relayState; } SAML2_Utils::getContainer()->postRedirect($destination, $post); }
/** * This function sends the SOAP message to the service location and returns SOAP response * * @param SAML2_Message $m 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. */ public function send(SAML2_Message $msg, SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata = NULL) { $issuer = $msg->getIssuer(); $ctxOpts = array('ssl' => array('capture_peer_cert' => TRUE)); // Determine if we are going to do a MutualSSL connection between the IdP and SP - Shoaib if ($srcMetadata->hasValue('saml.SOAPClient.certificate')) { $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); $x = new SoapClient(NULL, $options); // Add soap-envelopes $request = $msg->toSignedXML(); $request = self::START_SOAP_ENVELOPE . $request->ownerDocument->saveXML($request) . self::END_SOAP_ENVELOPE; SimpleSAML_Utilities::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.'); } SimpleSAML_Utilities::debugMessage($soapresponsexml, 'in'); // Convert to SAML2_Message (DOMElement) $dom = new DOMDocument(); if (!$dom->loadXML($soapresponsexml)) { throw new Exception('Not a SOAP response.'); } $soapfault = $this->getSOAPFault($dom); if (isset($soapfault)) { throw new Exception($soapfault); } //Extract the message from the response $xml = $dom->firstChild; /* Soap Envelope */ $samlresponse = SAML2_Utils::xpQuery($dom->firstChild, '/soap-env:Envelope/soap-env:Body/*[1]'); $samlresponse = SAML2_Message::fromXML($samlresponse[0]); /* Add validator to message which uses the SSL context. */ self::addSSLValidator($samlresponse, $context); SimpleSAML_Logger::debug("Valid ArtifactResponse received from IdP"); return $samlresponse; }
/** * 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(SAML2_Message $msg, SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata = NULL) { $issuer = $msg->getIssuer(); $ctxOpts = array('ssl' => array('capture_peer_cert' => TRUE)); /* 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; } $ctxOpts['http']['header'] = 'SOAPAction: "http://www.oasis-open.org/committees/security"' . "\n"; if ($this->username !== NULL && $this->password !== NULL) { /* Add HTTP Basic authentication header. */ $authData = $this->username . ':' . $this->password; $authData = base64_encode($authData); $ctxOpts['http']['header'] .= 'Authorization: Basic ' . $authData . "\n"; } 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; SAML2_Utils::getContainer()->debugMessage($request, 'out'); $ctxOpts['http']['content'] = $request; $ctxOpts['http']['header'] .= 'Content-Type: text/xml; charset=utf-8' . "\n"; $ctxOpts['http']['method'] = 'POST'; $destination = $msg->getDestination(); /* Perform SOAP Request over HTTP */ $context = stream_context_create($ctxOpts); if ($context === NULL) { throw new Exception('Unable to create stream context'); } $soapresponsexml = @file_get_contents($destination, FALSE, $context); if ($soapresponsexml === FALSE) { throw new Exception('Error processing SOAP call: ' . SimpleSAML_Utilities::getLastError()); } SAML2_Utils::getContainer()->debugMessage($soapresponsexml, 'in'); /* Convert to SAML2_Message (DOMElement) */ try { $dom = SAML2_DOMDocumentFactory::fromString($soapresponsexml); } catch (SAML2_Exception_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 = SAML2_Utils::xpQuery($dom->firstChild, '/soap-env:Envelope/soap-env:Body/*[1]'); $samlresponse = SAML2_Message::fromXML($samlresponse[0]); /* Add validator to message which uses the SSL context. */ self::addSSLValidator($samlresponse, $context); SAML2_Utils::getContainer()->getLogger()->debug("Valid ArtifactResponse received from IdP"); return $samlresponse; }
/** * Get the message Destination * * @return NULL|string */ public function getDestination() { return $this->sspMessage->getDestination(); }