Skip to content

Commit

Permalink
Fix DigestAuthenticate with simulated HTTP methods.
Browse files Browse the repository at this point in the history
Digest authentication headers depend on the original HTTP method. When
we use simulated request methods, we break digest authentication as the
hashes never match. This change adds `ORIGINAL_REQUEST_METHOD` to
request->env(), which allows us to access the original HTTP method.
I went down this route as I wanted to avoid more global dependencies,
and I thought having a way to access the original HTTP method could be
generally useful.

Refs #4889
  • Loading branch information
markstory committed Oct 17, 2014
1 parent 491c0c2 commit 8b9dfc4
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/Auth/DigestAuthenticate.php
Expand Up @@ -112,7 +112,7 @@ public function getUser(Request $request) {
$password = $user[$field];
unset($user[$field]);

$hash = $this->generateResponseHash($digest, $password, $request->env('REQUEST_METHOD'));
$hash = $this->generateResponseHash($digest, $password, $request->env('ORIGINAL_REQUEST_METHOD'));
if ($digest['response'] === $hash) {
return $user;
}
Expand Down
7 changes: 5 additions & 2 deletions src/Network/Request.php
Expand Up @@ -253,14 +253,16 @@ protected function _setConfig($config) {

/**
* Sets the REQUEST_METHOD environment variable based on the simulated _method
* HTTP override value.
* HTTP override value. The 'ORIGINAL_REQUEST_METHOD' is also preserved, if you
* want the read the non-simulated HTTP method the client used.
*
* @param array $data Array of post data.
* @return array
*/
protected function _processPost($data) {
$method = $this->env('REQUEST_METHOD');
if (
in_array($this->env('REQUEST_METHOD'), array('PUT', 'DELETE', 'PATCH')) &&
in_array($method, array('PUT', 'DELETE', 'PATCH')) &&
strpos($this->env('CONTENT_TYPE'), 'application/x-www-form-urlencoded') === 0
) {
$data = $this->input();
Expand All @@ -269,6 +271,7 @@ protected function _processPost($data) {
if ($this->env('HTTP_X_HTTP_METHOD_OVERRIDE')) {
$data['_method'] = $this->env('HTTP_X_HTTP_METHOD_OVERRIDE');
}
$this->_environment['ORIGINAL_REQUEST_METHOD'] = $method;
if (isset($data['_method'])) {
$this->_environment['REQUEST_METHOD'] = $data['_method'];
unset($data['_method']);
Expand Down
36 changes: 36 additions & 0 deletions tests/TestCase/Auth/DigestAuthenticateTest.php
Expand Up @@ -175,6 +175,42 @@ public function testAuthenticateSuccess() {
$this->assertEquals($expected, $result);
}

/**
* test authenticate success
*
* @return void
*/
public function testAuthenticateSuccessSimulatedRequestMethod() {
$request = new Request([
'url' => 'posts/index',
'post' => ['_method' => 'PUT'],
'environment' => ['REQUEST_METHOD' => 'GET']
]);
$request->addParams(array('pass' => array()));

$digest = <<<DIGEST
Digest username="mariano",
realm="localhost",
nonce="123",
uri="/dir/index.html",
qop=auth,
nc=1,
cnonce="123",
response="06b257a54befa2ddfb9bfa134224aa29",
opaque="123abc"
DIGEST;
$request->env('PHP_AUTH_DIGEST', $digest);

$result = $this->auth->authenticate($request, $this->response);
$expected = array(
'id' => 1,
'username' => 'mariano',
'created' => new Time('2007-03-17 01:16:23'),
'updated' => new Time('2007-03-17 01:18:31')
);
$this->assertEquals($expected, $result);
}

/**
* test scope failure.
*
Expand Down
7 changes: 7 additions & 0 deletions tests/TestCase/Network/RequestTest.php
Expand Up @@ -425,6 +425,13 @@ public function testMethodOverrides() {

$request = new Request(['environment' => ['HTTP_X_HTTP_METHOD_OVERRIDE' => 'PUT']]);
$this->assertEquals('PUT', $request->env('REQUEST_METHOD'));

$request = new Request([
'environment' => ['REQUEST_METHOD' => 'POST'],
'post' => ['_method' => 'PUT']
]);
$this->assertEquals('PUT', $request->env('REQUEST_METHOD'));
$this->assertEquals('POST', $request->env('ORIGINAL_REQUEST_METHOD'));
}

/**
Expand Down

0 comments on commit 8b9dfc4

Please sign in to comment.