18 const START_SOAP_ENVELOPE =
'<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"><soap-env:Header/><soap-env:Body>';
19 const END_SOAP_ENVELOPE =
'</soap-env:Body></soap-env:Envelope>';
36 'capture_peer_cert' =>
true,
37 'allow_self_signed' =>
true 42 if ($srcMetadata->
hasValue(
'saml.SOAPClient.certificate')) {
43 $cert = $srcMetadata->
getValue(
'saml.SOAPClient.certificate');
44 if ($cert !==
false) {
46 $srcMetadata->
getString(
'saml.SOAPClient.certificate')
48 if ($srcMetadata->
hasValue(
'saml.SOAPClient.privatekey_pass')) {
49 $ctxOpts[
'ssl'][
'passphrase'] = $srcMetadata->
getString(
'saml.SOAPClient.privatekey_pass');
56 if ($privateKey !== null && $publicKey !== null && isset($publicKey[
'PEM'])) {
57 $keyCertData = $privateKey[
'PEM'] . $publicKey[
'PEM'];
59 if (!file_exists($file)) {
62 $ctxOpts[
'ssl'][
'local_cert'] = $file;
63 if (isset($privateKey[
'password'])) {
64 $ctxOpts[
'ssl'][
'passphrase'] = $privateKey[
'password'];
70 if ($dstMetadata !== null) {
71 $peerPublicKeys = $dstMetadata->getPublicKeys(
'signing',
true);
73 foreach ($peerPublicKeys as
$key) {
74 if ($key[
'type'] !==
'X509Certificate') {
77 $certData .=
"-----BEGIN CERTIFICATE-----\n" .
78 chunk_split($key[
'X509Certificate'], 64) .
79 "-----END CERTIFICATE-----\n";
82 if (!file_exists($peerCertFile)) {
86 $ctxOpts[
'ssl'][
'verify_peer'] =
true;
87 $ctxOpts[
'ssl'][
'verify_depth'] = 1;
88 $ctxOpts[
'ssl'][
'cafile'] = $peerCertFile;
91 if ($srcMetadata->
hasValue(
'saml.SOAPClient.stream_context.ssl.peer_name')) {
92 $ctxOpts[
'ssl'][
'peer_name'] = $srcMetadata->
getString(
'saml.SOAPClient.stream_context.ssl.peer_name');
95 $context = stream_context_create($ctxOpts);
97 throw new \Exception(
'Unable to create SSL stream context');
106 if ($srcMetadata->
hasValue(
'saml.SOAPClient.proxyhost')) {
107 $options[
'proxy_host'] = $srcMetadata->
getValue(
'saml.SOAPClient.proxyhost');
110 if ($srcMetadata->
hasValue(
'saml.SOAPClient.proxyport')) {
111 $options[
'proxy_port'] = $srcMetadata->
getValue(
'saml.SOAPClient.proxyport');
120 Utils::getContainer()->debugMessage(
$request,
'out');
122 $action =
'http://www.oasis-open.org/committees/security';
128 if ($soapresponsexml === null || $soapresponsexml ===
"") {
129 throw new \Exception(
'Empty SOAP response, check peer certificate.');
132 Utils::getContainer()->debugMessage($soapresponsexml,
'in');
136 $dom = DOMDocumentFactory::fromString($soapresponsexml);
138 throw new \Exception(
'Not a SOAP response.', 0, $e);
141 $soapfault = $this->getSOAPFault($dom);
142 if (isset($soapfault)) {
143 throw new \Exception($soapfault);
146 $samlresponse = Utils::xpQuery($dom->firstChild,
'/soap-env:Envelope/soap-env:Body/*[1]');
147 $samlresponse = Message::fromXML($samlresponse[0]);
150 self::addSSLValidator($samlresponse,
$context);
152 Utils::getContainer()->getLogger()->debug(
"Valid ArtifactResponse received from IdP");
154 return $samlresponse;
166 if (!isset(
$options[
'ssl'][
'peer_certificate'])) {
173 $key = openssl_pkey_get_public(
$options[
'ssl'][
'peer_certificate']);
174 if (
$key ===
false) {
175 Utils::getContainer()->getLogger()->warning(
'Unable to get public key from peer certificate.');
180 $keyInfo = openssl_pkey_get_details(
$key);
181 if ($keyInfo ===
false) {
182 Utils::getContainer()->getLogger()->warning(
'Unable to get key details from public key.');
187 if (!isset($keyInfo[
'key'])) {
188 Utils::getContainer()->getLogger()->warning(
'Missing key in public key details.');
193 $msg->
addValidator(array(
'\SAML2\SOAPClient',
'validateSSL'), $keyInfo[
'key']);
205 assert(is_string(
$data));
207 $keyInfo = openssl_pkey_get_details($key->key);
208 if ($keyInfo ===
false) {
209 throw new \Exception(
'Unable to get key details from XMLSecurityKey.');
212 if (!isset($keyInfo[
'key'])) {
213 throw new \Exception(
'Missing key in public key details.');
216 if ($keyInfo[
'key'] !==
$data) {
217 Utils::getContainer()->getLogger()->debug(
'Key on SSL connection did not match key we validated against.');
222 Utils::getContainer()->getLogger()->debug(
'Message validated based on SSL certificate.');
232 $soapFault = Utils::xpQuery($soapMessage->firstChild,
'/soap-env:Envelope/soap-env:Body/soap-env:Fault');
234 if (empty($soapFault)) {
239 $soapFaultElement = $soapFault[0];
241 $soapFaultString =
"Unknown fault string found";
243 $faultStringElement = Utils::xpQuery($soapFaultElement,
'./soap-env:faultstring') ;
244 if (!empty($faultStringElement)) {
245 return $faultStringElement[0]->textContent;
248 return $soapFaultString;
static resolveCert($path)
foreach($paths as $path) $request
hasValue($name)
Check whether a key in the configuration exists or not.
getIssuer()
Retrieve the issuer if this message.
toSignedXML()
Convert this message to a signed XML document.
getValue($name, $default=null)
Retrieve a configuration option set in config.php.
static writeFile($filename, $data, $mode=0600)
static loadPublicKey(SimpleSAML_Configuration $metadata, $required=false, $prefix='')
Base class for all SAML 2 messages.
static addSSLValidator(Message $msg, $context)
Add a signature validator based on a SSL context.
catch(Exception $e) if(!($request instanceof \SAML2\ArtifactResolve)) $issuer
getString($name, $default=self::REQUIRED_OPTION)
This function retrieves a string configuration option.
static validateSSL($data, XMLSecurityKey $key)
Validate a SOAP message against the certificate on the SSL connection.
getDestination()
Retrieve the destination of this message.
send(Message $msg, SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata=null)
This function sends the SOAP message to the service location and returns SOAP response.
static loadPrivateKey(SimpleSAML_Configuration $metadata, $required=false, $prefix='')
getSOAPFault($soapMessage)
addValidator($function, $data)
Add a method for validating this message.