From 83e68f642d8f8b61c99d32d9e88dbfb8ab9906ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20G=C3=B3mez?= <sergio@uco.es> Date: Tue, 28 Mar 2017 19:43:52 +0200 Subject: [PATCH] SimpleSAML_Bindings_Shib13_* classes refactorized to PSR-2 --- lib/SimpleSAML/Bindings/Shib13/Artifact.php | 344 ++++++++++---------- lib/SimpleSAML/Bindings/Shib13/HTTPPost.php | 10 +- 2 files changed, 177 insertions(+), 177 deletions(-) diff --git a/lib/SimpleSAML/Bindings/Shib13/Artifact.php b/lib/SimpleSAML/Bindings/Shib13/Artifact.php index 8a1b80e77..5960dceb9 100644 --- a/lib/SimpleSAML/Bindings/Shib13/Artifact.php +++ b/lib/SimpleSAML/Bindings/Shib13/Artifact.php @@ -16,174 +16,178 @@ use SimpleSAML\Utils\System; use SimpleSAML\Utils\Time; use SimpleSAML\Utils\XML; -class Artifact { - - /** - * Parse the query string, and extract the SAMLart parameters. - * - * This function is required because each query contains multiple - * artifact with the same parameter name. - * - * @return array The artifacts. - */ - private static function getArtifacts() { - assert('array_key_exists("QUERY_STRING", $_SERVER)'); - - // We need to process the query string manually, to capture all SAMLart parameters - - $artifacts = array(); - - $elements = explode('&', $_SERVER['QUERY_STRING']); - foreach ($elements as $element) { - list($name, $value) = explode('=', $element, 2); - $name = urldecode($name); - $value = urldecode($value); - - if ($name === 'SAMLart') { - $artifacts[] = $value; - } - } - - return $artifacts; - } - - - /** - * Build the request we will send to the IdP. - * - * @param array $artifacts The artifacts we will request. - * @return string The request, as an XML string. - */ - private static function buildRequest(array $artifacts) { - - $msg = '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">' . - '<SOAP-ENV:Body>' . - '<samlp:Request xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"' . - ' RequestID="' . Random::generateID() . '"' . - ' MajorVersion="1" MinorVersion="1"' . - ' IssueInstant="' . Time::generateTimestamp() . '"' . - '>'; - - foreach ($artifacts as $a) { - $msg .= '<samlp:AssertionArtifact>' . htmlspecialchars($a) . '</samlp:AssertionArtifact>'; - } - - $msg .= '</samlp:Request>' . - '</SOAP-ENV:Body>' . - '</SOAP-ENV:Envelope>'; - - return $msg; - } - - - /** - * Extract the response element from the SOAP response. - * - * @param string $soapResponse The SOAP response. - * @return string The <saml1p:Response> element, as a string. - */ - private static function extractResponse($soapResponse) { - assert('is_string($soapResponse)'); - - try { - $doc = DOMDocumentFactory::fromString($soapResponse); - } catch(\Exception $e) { - throw new \SimpleSAML_Error_Exception('Error parsing SAML 1 artifact response.'); - } - - $soapEnvelope = $doc->firstChild; - if (!XML::isDOMElementOfType($soapEnvelope, 'Envelope', 'http://schemas.xmlsoap.org/soap/envelope/')) { - throw new \SimpleSAML_Error_Exception('Expected artifact response to contain a <soap:Envelope> element.'); - } - - $soapBody = XML::getDOMChildren($soapEnvelope, 'Body', 'http://schemas.xmlsoap.org/soap/envelope/'); - if (count($soapBody) === 0) { - throw new \SimpleSAML_Error_Exception('Couldn\'t find <soap:Body> in <soap:Envelope>.'); - } - $soapBody = $soapBody[0]; - - - $responseElement = XML::getDOMChildren($soapBody, 'Response', 'urn:oasis:names:tc:SAML:1.0:protocol'); - if (count($responseElement) === 0) { - throw new \SimpleSAML_Error_Exception('Couldn\'t find <saml1p:Response> in <soap:Body>.'); - } - $responseElement = $responseElement[0]; - - /* - * Save the <saml1p:Response> element. Note that we need to import it - * into a new document, in order to preserve namespace declarations. - */ - $newDoc = DOMDocumentFactory::create(); - $newDoc->appendChild($newDoc->importNode($responseElement, TRUE)); - $responseXML = $newDoc->saveXML(); - - return $responseXML; - } - - - /** - * This function receives a SAML 1.1 artifact. - * - * @param \SimpleSAML_Configuration $spMetadata The metadata of the SP. - * @param \SimpleSAML_Configuration $idpMetadata The metadata of the IdP. - * @return string The <saml1p:Response> element, as an XML string. - */ - public static function receive(\SimpleSAML_Configuration $spMetadata, \SimpleSAML_Configuration $idpMetadata) { - - $artifacts = self::getArtifacts(); - $request = self::buildRequest($artifacts); - - XML::debugSAMLMessage($request, 'out'); - - $url = $idpMetadata->getDefaultEndpoint('ArtifactResolutionService', array('urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding')); - $url = $url['Location']; - - $peerPublicKeys = $idpMetadata->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"; - } - - $file = System::getTempDir() . DIRECTORY_SEPARATOR . sha1($certData) . '.crt'; - if (!file_exists($file)) { +class Artifact +{ + + /** + * Parse the query string, and extract the SAMLart parameters. + * + * This function is required because each query contains multiple + * artifact with the same parameter name. + * + * @return array The artifacts. + */ + private static function getArtifacts() + { + assert('array_key_exists("QUERY_STRING", $_SERVER)'); + + // We need to process the query string manually, to capture all SAMLart parameters + + $artifacts = array(); + + $elements = explode('&', $_SERVER['QUERY_STRING']); + foreach ($elements as $element) { + list($name, $value) = explode('=', $element, 2); + $name = urldecode($name); + $value = urldecode($value); + + if ($name === 'SAMLart') { + $artifacts[] = $value; + } + } + + return $artifacts; + } + + + /** + * Build the request we will send to the IdP. + * + * @param array $artifacts The artifacts we will request. + * @return string The request, as an XML string. + */ + private static function buildRequest(array $artifacts) + { + $msg = '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">' . + '<SOAP-ENV:Body>' . + '<samlp:Request xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"' . + ' RequestID="' . Random::generateID() . '"' . + ' MajorVersion="1" MinorVersion="1"' . + ' IssueInstant="' . Time::generateTimestamp() . '"' . + '>'; + + foreach ($artifacts as $a) { + $msg .= '<samlp:AssertionArtifact>' . htmlspecialchars($a) . '</samlp:AssertionArtifact>'; + } + + $msg .= '</samlp:Request>' . + '</SOAP-ENV:Body>' . + '</SOAP-ENV:Envelope>'; + + return $msg; + } + + + /** + * Extract the response element from the SOAP response. + * + * @param string $soapResponse The SOAP response. + * @return string The <saml1p:Response> element, as a string. + * @throws \SimpleSAML_Error_Exception + */ + private static function extractResponse($soapResponse) + { + assert('is_string($soapResponse)'); + + try { + $doc = DOMDocumentFactory::fromString($soapResponse); + } catch (\Exception $e) { + throw new \SimpleSAML_Error_Exception('Error parsing SAML 1 artifact response.'); + } + + $soapEnvelope = $doc->firstChild; + if (!XML::isDOMElementOfType($soapEnvelope, 'Envelope', 'http://schemas.xmlsoap.org/soap/envelope/')) { + throw new \SimpleSAML_Error_Exception('Expected artifact response to contain a <soap:Envelope> element.'); + } + + $soapBody = XML::getDOMChildren($soapEnvelope, 'Body', 'http://schemas.xmlsoap.org/soap/envelope/'); + if (count($soapBody) === 0) { + throw new \SimpleSAML_Error_Exception('Couldn\'t find <soap:Body> in <soap:Envelope>.'); + } + $soapBody = $soapBody[0]; + + + $responseElement = XML::getDOMChildren($soapBody, 'Response', 'urn:oasis:names:tc:SAML:1.0:protocol'); + if (count($responseElement) === 0) { + throw new \SimpleSAML_Error_Exception('Couldn\'t find <saml1p:Response> in <soap:Body>.'); + } + $responseElement = $responseElement[0]; + + /* + * Save the <saml1p:Response> element. Note that we need to import it + * into a new document, in order to preserve namespace declarations. + */ + $newDoc = DOMDocumentFactory::create(); + $newDoc->appendChild($newDoc->importNode($responseElement, true)); + $responseXML = $newDoc->saveXML(); + + return $responseXML; + } + + + /** + * This function receives a SAML 1.1 artifact. + * + * @param \SimpleSAML_Configuration $spMetadata The metadata of the SP. + * @param \SimpleSAML_Configuration $idpMetadata The metadata of the IdP. + * @return string The <saml1p:Response> element, as an XML string. + * @throws \SimpleSAML_Error_Exception + */ + public static function receive(\SimpleSAML_Configuration $spMetadata, \SimpleSAML_Configuration $idpMetadata) + { + $artifacts = self::getArtifacts(); + $request = self::buildRequest($artifacts); + + XML::debugSAMLMessage($request, 'out'); + + $url = $idpMetadata->getDefaultEndpoint('ArtifactResolutionService', array('urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding')); + $url = $url['Location']; + + $peerPublicKeys = $idpMetadata->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"; + } + + $file = System::getTempDir() . DIRECTORY_SEPARATOR . sha1($certData) . '.crt'; + if (!file_exists($file)) { System::writeFile($file, $certData); - } - - $spKeyCertFile = Config::getCertPath($spMetadata->getString('privatekey')); - - $opts = array( - 'ssl' => array( - 'verify_peer' => TRUE, - 'cafile' => $file, - 'local_cert' => $spKeyCertFile, - 'capture_peer_cert' => TRUE, - 'capture_peer_chain' => TRUE, - ), - 'http' => array( - 'method' => 'POST', - 'content' => $request, - 'header' => 'SOAPAction: http://www.oasis-open.org/committees/security' . "\r\n" . - 'Content-Type: text/xml', - ), - ); - - // Fetch the artifact - $response = HTTP::fetch($url, $opts); - if ($response === FALSE) { - throw new \SimpleSAML_Error_Exception('Failed to retrieve assertion from IdP.'); - } - - XML::debugSAMLMessage($response, 'in'); - - // Find the response in the SOAP message - $response = self::extractResponse($response); - - return $response; - } - -} \ No newline at end of file + } + + $spKeyCertFile = Config::getCertPath($spMetadata->getString('privatekey')); + + $opts = array( + 'ssl' => array( + 'verify_peer' => true, + 'cafile' => $file, + 'local_cert' => $spKeyCertFile, + 'capture_peer_cert' => true, + 'capture_peer_chain' => true, + ), + 'http' => array( + 'method' => 'POST', + 'content' => $request, + 'header' => 'SOAPAction: http://www.oasis-open.org/committees/security' . "\r\n" . + 'Content-Type: text/xml', + ), + ); + + // Fetch the artifact + $response = HTTP::fetch($url, $opts); + if ($response === false) { + throw new \SimpleSAML_Error_Exception('Failed to retrieve assertion from IdP.'); + } + + XML::debugSAMLMessage($response, 'in'); + + // Find the response in the SOAP message + $response = self::extractResponse($response); + + return $response; + } +} diff --git a/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php b/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php index d1f03255e..58824747e 100644 --- a/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php +++ b/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php @@ -10,7 +10,6 @@ namespace SimpleSAML\Bindings\Shib13; - use SAML2\DOMDocumentFactory; use SimpleSAML\Utils\Crypto; use SimpleSAML\Utils\HTTP; @@ -50,11 +49,11 @@ class HTTPPost /** * Send an authenticationResponse using HTTP-POST. * - * @param string $response The response which should be sent. + * @param string $response The response which should be sent. * @param \SimpleSAML_Configuration $idpmd The metadata of the IdP which is sending the response. * @param \SimpleSAML_Configuration $spmd The metadata of the SP which is receiving the response. - * @param string|null $relayState The relaystate for the SP. - * @param string $shire The shire which should receive the response. + * @param string|null $relayState The relaystate for the SP. + * @param string $shire The shire which should receive the response. */ public function sendResponse( $response, @@ -63,7 +62,6 @@ class HTTPPost $relayState, $shire ) { - XML::checkSAMLMessage($response, 'saml11'); $privatekey = Crypto::loadPrivateKey($idpmd, true); @@ -127,9 +125,7 @@ class HTTPPost * Decode a received response. * * @param array $post POST data received. - * * @return \SimpleSAML\XML\Shib13\AuthnResponse The response decoded into an object. - * * @throws \Exception If there is no SAMLResponse parameter. */ public function decodeResponse($post) -- GitLab