ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
HTTPRedirect.php
Go to the documentation of this file.
1<?php
2
3namespace SAML2;
4
6
12class HTTPRedirect extends Binding
13{
14 const DEFLATE = 'urn:oasis:names:tc:SAML:2.0:bindings:URL-Encoding:DEFLATE';
15
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}
An exception for terminatinating execution or to throw for unit testing.
getRedirectURL(Message $message)
Create the redirect URL for a message.
static validateSignature(array $data, XMLSecurityKey $key)
Validate the signature on a HTTP-Redirect message.
static parseQuery()
Helper function to parse query data.
receive()
Receive a SAML 2 message sent using the HTTP-Redirect binding.
send(Message $message)
Send a SAML 2 message using the HTTP-Redirect binding.
Base class for all SAML 2 messages.
Definition: Message.php:19
$key
Definition: croninfo.php:18
catch(Exception $e) $message
$destination
$relayState
$query
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
$data
Definition: bench.php:6