/** * @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; }
/** * Add a signature validator based on a SSL context. * * @param \SAML2\Message $msg The message we should add a validator to. * @param resource $context The stream context. */ private static function addSSLValidator(Message $msg, $context) { $options = stream_context_get_options($context); if (!isset($options['ssl']['peer_certificate'])) { return; } //$out = ''; //openssl_x509_export($options['ssl']['peer_certificate'], $out); $key = openssl_pkey_get_public($options['ssl']['peer_certificate']); if ($key === false) { Utils::getContainer()->getLogger()->warning('Unable to get public key from peer certificate.'); return; } $keyInfo = openssl_pkey_get_details($key); if ($keyInfo === false) { Utils::getContainer()->getLogger()->warning('Unable to get key details from public key.'); return; } if (!isset($keyInfo['key'])) { Utils::getContainer()->getLogger()->warning('Missing key in public key details.'); return; } $msg->addValidator(array('\\SAML2\\SOAPClient', 'validateSSL'), $keyInfo['key']); }
/** * 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; }