Convert an XML element into a message.
public static fromXML ( DOMElement $xml ) : |
||
$xml | DOMElement | The root XML element |
리턴 | The message |
/** * @group Message */ public function testCorrectSignatureMethodCanBeExtractedFromResponse() { $response = new \DOMDocument(); $response->load(__DIR__ . '/Response/response.xml'); $privateKey = CertificatesMock::getPrivateKey(); $unsignedMessage = Message::fromXML($response->documentElement); $unsignedMessage->setSignatureKey($privateKey); $unsignedMessage->setCertificates(array(CertificatesMock::PUBLIC_KEY_PEM)); $signedMessage = Message::fromXML($unsignedMessage->toSignedXML()); $this->assertEquals($privateKey->getAlgorith(), $signedMessage->getSignatureMethod()); }
/** * Receive a SAML 2 message sent using the HTTP-Redirect binding. * * Throws an exception if it is unable receive the message. * * @return \SAML2\Message The received message. * @throws \Exception * * NPath is currently too high but solving that just moves code around. * @SuppressWarnings(PHPMD.NPathComplexity) */ public function receive() { $data = self::parseQuery(); if (array_key_exists('SAMLRequest', $data)) { $message = $data['SAMLRequest']; } elseif (array_key_exists('SAMLResponse', $data)) { $message = $data['SAMLResponse']; } else { throw new \Exception('Missing SAMLRequest or SAMLResponse parameter.'); } if (isset($data['SAMLEncoding']) && $data['SAMLEncoding'] !== self::DEFLATE) { throw new \Exception('Unknown SAMLEncoding: ' . var_export($data['SAMLEncoding'], true)); } $message = base64_decode($message); if ($message === false) { throw new \Exception('Error while base64 decoding SAML message.'); } $message = gzinflate($message); if ($message === false) { throw new \Exception('Error while inflating SAML message.'); } Utils::getContainer()->debugMessage($message, 'in'); $document = DOMDocumentFactory::fromString($message); $xml = $document->firstChild; $message = Message::fromXML($xml); if (array_key_exists('RelayState', $data)) { $message->setRelayState($data['RelayState']); } if (!array_key_exists('Signature', $data)) { return $message; } if (!array_key_exists('SigAlg', $data)) { throw new \Exception('Missing signature algorithm.'); } $signData = array('Signature' => $data['Signature'], 'SigAlg' => $data['SigAlg'], 'Query' => $data['SignedQuery']); $message->addValidator(array(get_class($this), 'validateSignature'), $signData); return $message; }
/** * 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; }
/** * Receive a SAML 2 message sent using the HTTP-Artifact binding. * * Throws an exception if it is unable receive the message. * * @return \SAML2\Message The received message. * @throws \Exception */ public function receive() { if (array_key_exists('SAMLart', $_REQUEST)) { $artifact = base64_decode($_REQUEST['SAMLart']); $endpointIndex = bin2hex(substr($artifact, 2, 2)); $sourceId = bin2hex(substr($artifact, 4, 20)); } else { throw new \Exception('Missing SAMLArt parameter.'); } $metadataHandler = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); $idpMetadata = $metadataHandler->getMetaDataConfigForSha1($sourceId, 'saml20-idp-remote'); if ($idpMetadata === null) { throw new \Exception('No metadata found for remote provider with SHA1 ID: ' . var_export($sourceId, true)); } $endpoint = null; foreach ($idpMetadata->getEndpoints('ArtifactResolutionService') as $ep) { if ($ep['index'] === hexdec($endpointIndex)) { $endpoint = $ep; break; } } if ($endpoint === null) { throw new \Exception('No ArtifactResolutionService with the correct index.'); } Utils::getContainer()->getLogger()->debug("ArtifactResolutionService endpoint being used is := " . $endpoint['Location']); //Construct the ArtifactResolve Request $ar = new ArtifactResolve(); /* Set the request attributes */ $ar->setIssuer($this->spMetadata->getString('entityid')); $ar->setArtifact($_REQUEST['SAMLart']); $ar->setDestination($endpoint['Location']); /* Sign the request */ sspmod_saml_Message::addSign($this->spMetadata, $idpMetadata, $ar); // Shoaib - moved from the SOAPClient. $soap = new SOAPClient(); // Send message through SoapClient /** @var \SAML2\ArtifactResponse $artifactResponse */ $artifactResponse = $soap->send($ar, $this->spMetadata); if (!$artifactResponse->isSuccess()) { throw new \Exception('Received error from ArtifactResolutionService.'); } $xml = $artifactResponse->getAny(); if ($xml === null) { /* Empty ArtifactResponse - possibly because of Artifact replay? */ return null; } $samlResponse = Message::fromXML($xml); $samlResponse->addValidator(array(get_class($this), 'validateSignature'), $artifactResponse); if (isset($_REQUEST['RelayState'])) { $samlResponse->setRelayState($_REQUEST['RelayState']); } return $samlResponse; }