Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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 c2c747e
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 12 deletions.
46 changes: 36 additions & 10 deletions src/Http/Client/Auth/Oauth.php
Expand Up @@ -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;
}

/**
Expand Down
59 changes: 57 additions & 2 deletions tests/TestCase/Http/Client/Auth/OauthTest.php
Expand Up @@ -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.
*
Expand All @@ -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();
Expand Down

0 comments on commit c2c747e

Please sign in to comment.