Skip to content
Permalink
Browse files

Fix nested parameter encoding in Oauth1 client.

Nested parameters should not emit errors when generating an Oauth
signature. Instead use the [] style that PHP uses for complex POST data.
I've kept the existing behavior for list style arguments as I don't want
to break compatibility with existing use cases.

Refs #10458
  • Loading branch information...
markstory committed May 5, 2017
1 parent bb9e73e commit c2c747ec53f122b3310d081f1ea949d63f6a8ecd
Showing with 93 additions and 12 deletions.
  1. +36 −10 src/Http/Client/Auth/Oauth.php
  2. +57 −2 tests/TestCase/Http/Client/Auth/OauthTest.php
@@ -291,21 +291,47 @@ protected function _normalizedParams($request, $oauthValues)
}
$args = array_merge($queryArgs, $oauthValues, $post);
uksort($args, 'strcmp');
$pairs = [];
foreach ($args as $k => $val) {
if (is_array($val)) {
sort($val, SORT_STRING);
foreach ($val as $nestedVal) {
$pairs[] = "$k=$nestedVal";
$pairs = $this->_normalizeData($args);
$data = [];
foreach ($pairs as $pair) {
$data[] = implode('=', $pair);
}
sort($data, SORT_STRING);
return implode('&', $data);
}
/**
* Recursively convert request data into the normalized form.
*
* @param array $args The arguments to normalize.
* @param string $path The current path being converted.
* @see https://tools.ietf.org/html/rfc5849#section-3.4.1.3.2
* @return array
*/
protected function _normalizeData($args, $path = '')
{
$data = [];
foreach ($args as $key => $value) {
if ($path) {
// Fold string keys with [].
// Numeric keys result in a=b&a=c. While this isn't
// standard behavior in PHP, it is common in other platforms.
if (!is_numeric($key)) {
$key = "{$path}[{$key}]";
} else {
$key = $path;
}
}
if (is_array($value)) {
uksort($value, 'strcmp');
$data = array_merge($data, $this->_normalizeData($value, $key));
} else {
$pairs[] = "$k=$val";
$data[] = [$key, $value];
}
}
return implode('&', $pairs);
return $data;
}
/**
@@ -159,6 +159,61 @@ public function testBaseStringWithQueryString()
);
}
/**
* Ensure that post data is sorted and encoded.
*
* Keys with array values have to be serialized using
* a more standard HTTP approach. PHP flavoured HTTP
* is not part of the Oauth spec.
*
* See Normalize Request Parameters (section 9.1.1)
*
* @return void
*/
public function testBaseStringWithPostDataNestedArrays()
{
$request = new Request();
$request->url('http://example.com/search?q=pogo')
->method(Request::METHOD_POST)
->body([
'search' => [
'filters' => [
'field' => 'date',
'value' => 'one two'
]
]
]);
$auth = new Oauth();
$values = [
'oauth_version' => '1.0',
'oauth_nonce' => uniqid(),
'oauth_timestamp' => time(),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_token' => 'token',
'oauth_consumer_key' => 'consumer-key',
];
$result = $auth->baseString($request, $values);
$this->assertContains('POST&', $result, 'method was missing.');
$this->assertContains(
'http%3A%2F%2Fexample.com%2Fsearch&',
$result
);
$this->assertContains(
'&oauth_consumer_key%3Dconsumer-key' .
'%26oauth_nonce%3D' . $values['oauth_nonce'] .
'%26oauth_signature_method%3DHMAC-SHA1' .
'%26oauth_timestamp%3D' . $values['oauth_timestamp'] .
'%26oauth_token%3Dtoken' .
'%26oauth_version%3D1.0' .
'%26q%3Dpogo' .
'%26search%5Bfilters%5D%5Bfield%5D%3Ddate' .
'%26search%5Bfilters%5D%5Bvalue%5D%3Done%20two',
$result
);
}
/**
* Ensure that post data is sorted and encoded.
*
@@ -178,8 +233,8 @@ public function testBaseStringWithPostData()
->method(Request::METHOD_POST)
->body([
'address' => 'post',
'tags' => ['oauth', 'cake'],
'zed' => 'last'
'zed' => 'last',
'tags' => ['oauth', 'cake']
]);
$auth = new Oauth();

0 comments on commit c2c747e

Please sign in to comment.
You can’t perform that action at this time.