Skip to content

Commit 7867d60

Browse files
authored
Merge commit from fork
1 parent 7177b3f commit 7867d60

File tree

2 files changed

+162
-11
lines changed

2 files changed

+162
-11
lines changed

src/Binding/HTTPRedirect.php

+94-11
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,37 @@ public function send(AbstractMessage $message): ResponseInterface
123123
*/
124124
public function receive(ServerRequestInterface $request): AbstractMessage
125125
{
126-
$query = $request->getQueryParams();
127-
128-
if (array_key_exists('SAMLRequest', $query)) {
129-
$message = $query['SAMLRequest'];
130-
$signedQuery = 'SAMLRequest=' . urlencode($query['SAMLRequest']);
131-
} elseif (array_key_exists('SAMLResponse', $query)) {
132-
$message = $query['SAMLResponse'];
133-
$signedQuery = 'SAMLResponse=' . urlencode($query['SAMLResponse']);
126+
$query = $this->parseQuery();
127+
$signedQuery = $query['SignedQuery'];
128+
129+
/**
130+
* Get the SAMLRequest/SAMLResponse from the exact same signed data that will be verified later in
131+
* validateSignature into $res using the actual SignedQuery
132+
*/
133+
$res = [];
134+
foreach (explode('&', $signedQuery) as $e) {
135+
$tmp = explode('=', $e, 2);
136+
$name = $tmp[0];
137+
if (count($tmp) === 2) {
138+
$value = $tmp[1];
139+
} else {
140+
/* No value for this parameter. */
141+
$value = '';
142+
}
143+
$name = urldecode($name);
144+
$res[$name] = urldecode($value);
145+
}
146+
147+
/**
148+
* Put the SAMLRequest/SAMLResponse from the actual query string into $message,
149+
* and assert that the result from parseQuery() in $query and the parsing of the SignedQuery in $res agree
150+
*/
151+
if (array_key_exists('SAMLRequest', $res)) {
152+
Assert::same($res['SAMLRequest'], $query['SAMLRequest'], 'Parse failure.');
153+
$message = $res['SAMLRequest'];
154+
} elseif (array_key_exists('SAMLResponse', $res)) {
155+
Assert::same($res['SAMLResponse'], $query['SAMLResponse'], 'Parse failure.');
156+
$message = $res['SAMLResponse'];
134157
} else {
135158
throw new Exception('Missing SAMLRequest or SAMLResponse parameter.');
136159
}
@@ -154,7 +177,6 @@ public function receive(ServerRequestInterface $request): AbstractMessage
154177
$message = MessageFactory::fromXML($document->documentElement);
155178

156179
if (array_key_exists('RelayState', $query)) {
157-
$signedQuery .= '&RelayState=' . urlencode($query['RelayState']);
158180
$this->setRelayState($query['RelayState']);
159181
}
160182

@@ -174,8 +196,6 @@ public function receive(ServerRequestInterface $request): AbstractMessage
174196

175197
if (!array_key_exists('SigAlg', $query)) {
176198
throw new Exception('Missing signature algorithm.');
177-
} else {
178-
$signedQuery .= '&SigAlg=' . urlencode($query['SigAlg']);
179199
}
180200

181201
$container = ContainerSingleton::getInstance();
@@ -192,4 +212,67 @@ public function receive(ServerRequestInterface $request): AbstractMessage
192212

193213
return $message;
194214
}
215+
216+
217+
/**
218+
* Helper function to parse query data.
219+
*
220+
* This function returns the query string split into key=>value pairs.
221+
* It also adds a new parameter, SignedQuery, which contains the data that is
222+
* signed.
223+
*
224+
* @return array The query data that is signed.
225+
* @throws \Exception
226+
*/
227+
private static function parseQuery() : array
228+
{
229+
/*
230+
* Parse the query string. We need to do this ourself, so that we get access
231+
* to the raw (urlencoded) values. This is required because different software
232+
* can urlencode to different values.
233+
*/
234+
$data = [];
235+
$relayState = '';
236+
$sigAlg = '';
237+
$sigQuery = '';
238+
239+
foreach (explode('&', $_SERVER['QUERY_STRING']) as $e) {
240+
$tmp = explode('=', $e, 2);
241+
$name = $tmp[0];
242+
if (count($tmp) === 2) {
243+
$value = $tmp[1];
244+
} else {
245+
/* No value for this parameter. */
246+
$value = '';
247+
}
248+
249+
$name = urldecode($name);
250+
// Prevent keys from being set more than once
251+
if (array_key_exists($name, $data)) {
252+
throw new Exception('Duplicate parameter.');
253+
}
254+
$data[$name] = urldecode($value);
255+
256+
switch ($name) {
257+
case 'SAMLRequest':
258+
case 'SAMLResponse':
259+
$sigQuery = $name . '=' . $value;
260+
break;
261+
case 'RelayState':
262+
$relayState = '&RelayState=' . $value;
263+
break;
264+
case 'SigAlg':
265+
$sigAlg = '&SigAlg=' . $value;
266+
break;
267+
}
268+
}
269+
270+
if (array_key_exists('SAMLRequest', $data) && array_key_exists('SAMLResponse', $data)) {
271+
throw new Exception('Both SAMLRequest and SAMLResponse provided.');
272+
}
273+
274+
$data['SignedQuery'] = $sigQuery . $relayState . $sigAlg;
275+
276+
return $data;
277+
}
195278
}

0 commit comments

Comments
 (0)