Skip to content
Snippets Groups Projects
Commit 83e68f64 authored by Sergio Gómez's avatar Sergio Gómez
Browse files

SimpleSAML_Bindings_Shib13_* classes refactorized to PSR-2

parent 6ba08aab
No related branches found
No related tags found
No related merge requests found
......@@ -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;
}
}
......@@ -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)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment