ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
HTTPRedirect.php
Go to the documentation of this file.
1 <?php
2 
3 namespace SAML2;
4 
6 
12 class HTTPRedirect extends Binding
13 {
14  const DEFLATE = 'urn:oasis:names:tc:SAML:2.0:bindings:URL-Encoding:DEFLATE';
15 
22  public function getRedirectURL(Message $message)
23  {
24  if ($this->destination === null) {
25  $destination = $message->getDestination();
26  } else {
28  }
29 
30  $relayState = $message->getRelayState();
31 
32  $key = $message->getSignatureKey();
33 
34  $msgStr = $message->toUnsignedXML();
35  $msgStr = $msgStr->ownerDocument->saveXML($msgStr);
36 
37  Utils::getContainer()->debugMessage($msgStr, 'out');
38 
39  $msgStr = gzdeflate($msgStr);
40  $msgStr = base64_encode($msgStr);
41 
42  /* Build the query string. */
43 
44  if ($message instanceof Request) {
45  $msg = 'SAMLRequest=';
46  } else {
47  $msg = 'SAMLResponse=';
48  }
49  $msg .= urlencode($msgStr);
50 
51  if ($relayState !== null) {
52  $msg .= '&RelayState=' . urlencode($relayState);
53  }
54 
55  if ($key !== null) {
56  /* Add the signature. */
57  $msg .= '&SigAlg=' . urlencode($key->type);
58 
59  $signature = $key->signData($msg);
60  $msg .= '&Signature=' . urlencode(base64_encode($signature));
61  }
62 
63  if (strpos($destination, '?') === false) {
64  $destination .= '?' . $msg;
65  } else {
66  $destination .= '&' . $msg;
67  }
68 
69  return $destination;
70  }
71 
79  public function send(Message $message)
80  {
81  $destination = $this->getRedirectURL($message);
82  Utils::getContainer()->getLogger()->debug('Redirect to ' . strlen($destination) . ' byte URL: ' . $destination);
83  Utils::getContainer()->redirect($destination);
84  }
85 
97  public function receive()
98  {
99  $data = self::parseQuery();
100  if (array_key_exists('SAMLRequest', $data)) {
101  $message = $data['SAMLRequest'];
102  } elseif (array_key_exists('SAMLResponse', $data)) {
103  $message = $data['SAMLResponse'];
104  } else {
105  throw new \Exception('Missing SAMLRequest or SAMLResponse parameter.');
106  }
107 
108  if (isset($data['SAMLEncoding']) && $data['SAMLEncoding'] !== self::DEFLATE) {
109  throw new \Exception('Unknown SAMLEncoding: ' . var_export($data['SAMLEncoding'], true));
110  }
111 
112  $message = base64_decode($message);
113  if ($message === false) {
114  throw new \Exception('Error while base64 decoding SAML message.');
115  }
116 
117  $message = gzinflate($message);
118  if ($message === false) {
119  throw new \Exception('Error while inflating SAML message.');
120  }
121 
122  Utils::getContainer()->debugMessage($message, 'in');
123  $document = DOMDocumentFactory::fromString($message);
124  $xml = $document->firstChild;
125  $message = Message::fromXML($xml);
126 
127  if (array_key_exists('RelayState', $data)) {
128  $message->setRelayState($data['RelayState']);
129  }
130 
131  if (!array_key_exists('Signature', $data)) {
132  return $message;
133  }
134 
135  if (!array_key_exists('SigAlg', $data)) {
136  throw new \Exception('Missing signature algorithm.');
137  }
138 
139  $signData = array(
140  'Signature' => $data['Signature'],
141  'SigAlg' => $data['SigAlg'],
142  'Query' => $data['SignedQuery'],
143  );
144 
145  $message->addValidator(array(get_class($this), 'validateSignature'), $signData);
146 
147  return $message;
148  }
149 
159  private static function parseQuery()
160  {
161  /*
162  * Parse the query string. We need to do this ourself, so that we get access
163  * to the raw (urlencoded) values. This is required because different software
164  * can urlencode to different values.
165  */
166  $data = array();
167  $relayState = '';
168  $sigAlg = '';
169  $sigQuery = '';
170  foreach (explode('&', $_SERVER['QUERY_STRING']) as $e) {
171  $tmp = explode('=', $e, 2);
172  $name = $tmp[0];
173  if (count($tmp) === 2) {
174  $value = $tmp[1];
175  } else {
176  /* No value for this parameter. */
177  $value = '';
178  }
179  $name = urldecode($name);
180  $data[$name] = urldecode($value);
181 
182  switch ($name) {
183  case 'SAMLRequest':
184  case 'SAMLResponse':
185  $sigQuery = $name . '=' . $value;
186  break;
187  case 'RelayState':
188  $relayState = '&RelayState=' . $value;
189  break;
190  case 'SigAlg':
191  $sigAlg = '&SigAlg=' . $value;
192  break;
193  }
194  }
195 
196  $data['SignedQuery'] = $sigQuery . $relayState . $sigAlg;
197 
198  return $data;
199  }
200 
210  public static function validateSignature(array $data, XMLSecurityKey $key)
211  {
212  assert(array_key_exists("Query", $data));
213  assert(array_key_exists("SigAlg", $data));
214  assert(array_key_exists("Signature", $data));
215 
216  $query = $data['Query'];
217  $sigAlg = $data['SigAlg'];
218  $signature = $data['Signature'];
219 
220  $signature = base64_decode($signature);
221 
222  if ($key->type !== XMLSecurityKey::RSA_SHA256) {
223  throw new \Exception('Invalid key type for validating signature on query string.');
224  }
225  if ($key->type !== $sigAlg) {
226  $key = Utils::castKey($key, $sigAlg);
227  }
228 
229  if ($key->verifySignature($query, $signature) !== 1) {
230  throw new \Exception('Unable to validate signature on query string.');
231  }
232  }
233 }
static validateSignature(array $data, XMLSecurityKey $key)
Validate the signature on a HTTP-Redirect message.
getRedirectURL(Message $message)
Create the redirect URL for a message.
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
getRelayState()
Retrieve the RelayState associated with this message.
Definition: Message.php:411
$destination
receive()
Receive a SAML 2 message sent using the HTTP-Redirect binding.
getSignatureKey()
Retrieve the private key we should use to sign the message.
Definition: Message.php:514
static parseQuery()
Helper function to parse query data.
Base class for all SAML 2 messages.
Definition: Message.php:18
catch(Exception $e) $message
$relayState
verifySignature($data, $signature)
Verifies the data (string) against the given signature using the extension assigned to the type in th...
$query
toUnsignedXML()
Convert this message to an unsigned XML document.
Definition: Message.php:435
getDestination()
Retrieve the destination of this message.
Definition: Message.php:323
$key
Definition: croninfo.php:18
send(Message $message)
Send a SAML 2 message using the HTTP-Redirect binding.
$data
Definition: bench.php:6