ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Artifact.php
Go to the documentation of this file.
1 <?php
2 
10 
18 
19 class Artifact
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 
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
186  $response = self::extractResponse($response);
187 
188  return $response;
189  }
190 }
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:183
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
foreach($paths as $path) $request
Definition: asyncclient.php:32
static getTempDir()
This function retrieves the path to a directory where temporary files can be saved.
Definition: System.php:70
static isDOMNodeOfType(\DOMNode $element, $name, $nsURI)
This function checks if the DOMElement has the correct localName and namespaceURI.
Definition: XML.php:357
static getArtifacts()
Parse the query string, and extract the SAMLart parameters.
Definition: Artifact.php:30
static extractResponse($soapResponse)
Extract the response element from the SOAP response.
Definition: Artifact.php:88
$spMetadata
static buildRequest(array $artifacts)
Build the request we will send to the IdP.
Definition: Artifact.php:59
static generateTimestamp($instant=null)
This function generates a timestamp on the form used by the SAML protocols.
Definition: Time.php:31
static debugSAMLMessage($message, $type)
Helper function to log SAML messages that we send or receive.
Definition: XML.php:94
getDefaultEndpoint($endpointType, array $bindings=null, $default=self::REQUIRED_OPTION)
Find the default endpoint of the given type.
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:408
getPublicKeys($use=null, $required=false, $prefix='')
Get public key from metadata.
getString($name, $default=self::REQUIRED_OPTION)
This function retrieves a string configuration option.
static getCertPath($path)
Resolves a path that may be relative to the cert-directory.
Definition: Config.php:22
$idpMetadata
$url
$response
$key
Definition: croninfo.php:18