ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
Artifact.php
Go to the documentation of this file.
1<?php
2
10
18
20{
21
30 private static function getArtifacts()
31 {
32 assert('array_key_exists("QUERY_STRING", $_SERVER)');
33
34 // We need to process the query string manually, to capture all SAMLart parameters
35
36 $artifacts = array();
37
38 $elements = explode('&', $_SERVER['QUERY_STRING']);
39 foreach ($elements as $element) {
40 list($name, $value) = explode('=', $element, 2);
41 $name = urldecode($name);
42 $value = urldecode($value);
43
44 if ($name === 'SAMLart') {
45 $artifacts[] = $value;
46 }
47 }
48
49 return $artifacts;
50 }
51
52
59 private static function buildRequest(array $artifacts)
60 {
61 $msg = '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">' .
62 '<SOAP-ENV:Body>' .
63 '<samlp:Request xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"' .
64 ' RequestID="' . Random::generateID() . '"' .
65 ' MajorVersion="1" MinorVersion="1"' .
66 ' IssueInstant="' . Time::generateTimestamp() . '"' .
67 '>';
68
69 foreach ($artifacts as $a) {
70 $msg .= '<samlp:AssertionArtifact>' . htmlspecialchars($a) . '</samlp:AssertionArtifact>';
71 }
72
73 $msg .= '</samlp:Request>' .
74 '</SOAP-ENV:Body>' .
75 '</SOAP-ENV:Envelope>';
76
77 return $msg;
78 }
79
80
88 private static function extractResponse($soapResponse)
89 {
90 assert('is_string($soapResponse)');
91
92 try {
93 $doc = DOMDocumentFactory::fromString($soapResponse);
94 } catch (\Exception $e) {
95 throw new \SimpleSAML_Error_Exception('Error parsing SAML 1 artifact response.');
96 }
97
98 $soapEnvelope = $doc->firstChild;
99 if (!XML::isDOMNodeOfType($soapEnvelope, 'Envelope', 'http://schemas.xmlsoap.org/soap/envelope/')) {
100 throw new \SimpleSAML_Error_Exception('Expected artifact response to contain a <soap:Envelope> element.');
101 }
102
103 $soapBody = XML::getDOMChildren($soapEnvelope, 'Body', 'http://schemas.xmlsoap.org/soap/envelope/');
104 if (count($soapBody) === 0) {
105 throw new \SimpleSAML_Error_Exception('Couldn\'t find <soap:Body> in <soap:Envelope>.');
106 }
107 $soapBody = $soapBody[0];
108
109
110 $responseElement = XML::getDOMChildren($soapBody, 'Response', 'urn:oasis:names:tc:SAML:1.0:protocol');
111 if (count($responseElement) === 0) {
112 throw new \SimpleSAML_Error_Exception('Couldn\'t find <saml1p:Response> in <soap:Body>.');
113 }
114 $responseElement = $responseElement[0];
115
116 /*
117 * Save the <saml1p:Response> element. Note that we need to import it
118 * into a new document, in order to preserve namespace declarations.
119 */
120 $newDoc = DOMDocumentFactory::create();
121 $newDoc->appendChild($newDoc->importNode($responseElement, true));
122 $responseXML = $newDoc->saveXML();
123
124 return $responseXML;
125 }
126
127
137 {
138 $artifacts = self::getArtifacts();
139 $request = self::buildRequest($artifacts);
140
141 XML::debugSAMLMessage($request, 'out');
142
143 $url = $idpMetadata->getDefaultEndpoint('ArtifactResolutionService', array('urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding'));
144 $url = $url['Location'];
145
146 $peerPublicKeys = $idpMetadata->getPublicKeys('signing', true);
147 $certData = '';
148 foreach ($peerPublicKeys as $key) {
149 if ($key['type'] !== 'X509Certificate') {
150 continue;
151 }
152 $certData .= "-----BEGIN CERTIFICATE-----\n" .
153 chunk_split($key['X509Certificate'], 64) .
154 "-----END CERTIFICATE-----\n";
155 }
156
157 $file = System::getTempDir() . DIRECTORY_SEPARATOR . sha1($certData) . '.crt';
158 if (!file_exists($file)) {
159 System::writeFile($file, $certData);
160 }
161
162 $spKeyCertFile = Config::getCertPath($spMetadata->getString('privatekey'));
163
164 $opts = array(
165 'ssl' => array(
166 'verify_peer' => true,
167 'cafile' => $file,
168 'local_cert' => $spKeyCertFile,
169 'capture_peer_cert' => true,
170 'capture_peer_chain' => true,
171 ),
172 'http' => array(
173 'method' => 'POST',
174 'content' => $request,
175 'header' => 'SOAPAction: http://www.oasis-open.org/committees/security' . "\r\n" .
176 'Content-Type: text/xml',
177 ),
178 );
179
180 // Fetch the artifact
181 $response = HTTP::fetch($url, $opts);
184
185 // Find the response in the SOAP message
187
188 return $response;
189 }
190}
An exception for terminatinating execution or to throw for unit testing.
static extractResponse($soapResponse)
Extract the response element from the SOAP response.
Definition: Artifact.php:88
static buildRequest(array $artifacts)
Build the request we will send to the IdP.
Definition: Artifact.php:59
static getArtifacts()
Parse the query string, and extract the SAMLart parameters.
Definition: Artifact.php:30
static getCertPath($path)
Resolves a path that may be relative to the cert-directory.
Definition: Config.php:22
static fetch($url, $context=array(), $getHeaders=false)
Helper function to retrieve a file or URL with proxy support, also supporting proxy basic authorizati...
Definition: HTTP.php:409
static generateID()
Generate a random identifier, ID_LENGTH bytes long.
Definition: Random.php:26
static writeFile($filename, $data, $mode=0600)
Atomically write a file.
Definition: System.php:176
static getTempDir()
This function retrieves the path to a directory where temporary files can be saved.
Definition: System.php:70
static generateTimestamp($instant=null)
This function generates a timestamp on the form used by the SAML protocols.
Definition: Time.php:32
static isDOMNodeOfType(\DOMNode $element, $name, $nsURI)
This function checks if the DOMElement has the correct localName and namespaceURI.
Definition: XML.php:357
static debugSAMLMessage($message, $type)
Helper function to log SAML messages that we send or receive.
Definition: XML.php:94
$key
Definition: croninfo.php:18
if($format !==null) $name
Definition: metadata.php:146
$idpMetadata
$spMetadata
$url
$response
if(!file_exists("$old.txt")) if( $old===$new) if(file_exists("$new.txt")) $file
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']