merged branch kepten/ticket_1813 (PR #3551)
Commits
-------
a450d00
[HttpFoundation] HTTP Basic authentication is broken with PHP as cgi/fastCGI under Apache
Discussion
----------
[HttpFoundation] HTTP Basic authentication is broken with php-cgi under Apache
Bug fix: yes
Feature addition: no
Backwards compatibility break: no
Symfony2 tests pass: yes
Fixes the following tickets: #1813
Todo: -
In order to work, add this to the .htaccess:
RewriteEngine on
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ app.php [QSA,L]
---------------------------------------------------------------------------
by stof at 2012-03-10T17:34:26Z
you should also add a unit test for this
---------------------------------------------------------------------------
by kepten at 2012-03-11T15:34:04Z
Thanks for the feedback, I committed the changes.
---------------------------------------------------------------------------
by stof at 2012-04-04T01:59:53Z
@fabpot could you review it ?
---------------------------------------------------------------------------
by fabpot at 2012-04-04T07:15:34Z
My comments:
* `ServerBag` represents what we have in the `$_SERVER` global variables. As such, the code should be moved to the `getHeaders()` method instead like the other tweaks we do for the HTTP headers.
* A comment must be added explaining why this is needed and the configuration the user must have to make it work (then remove the Github URLs).
* The code should only be executed when `PHP_AUTH_USER` is not available (to not have any overhead when not needed).
---------------------------------------------------------------------------
by danielholmes at 2012-04-14T13:27:09Z
A quick note on that .htaccess/apache configuration required, if adding to the Symfony SE htaccess file, then it will need to look like this:
```
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ app.php [QSA,L]
</IfModule>
```
NOTE: No **,L** in the Authorization Rewrite as in the original example - it prevents the front controller rewrite from happening
---------------------------------------------------------------------------
by towards at 2012-04-20T16:12:49Z
@kepten you were faster than me applying @fabpot's comments :) nevertheless part of the bug hunt day I also modified the ServerBag class and tested them on a productive LAMP hosting server using Apache and FastCGI
---------------------------------------------------------------------------
by kepten at 2012-04-20T16:15:57Z
ok, so is my PR is useless or should I still fix problems?
---------------------------------------------------------------------------
by towards at 2012-04-20T16:20:26Z
your PR is fine for sure and I don't want to interfere, just wanted to mention that part of the bug hunt day of Symfony I had a go at this PR as an "exercise" but just saw later on that you already fixed the problem, so you can ignore my pushes
---------------------------------------------------------------------------
by vicb at 2012-04-20T16:20:36Z
I have been working with @towards: your PR is useful, please implement his comments and squash your PR.
---------------------------------------------------------------------------
by kepten at 2012-04-20T16:59:07Z
never squashed before, is it okay now? :)
---------------------------------------------------------------------------
by stof at 2012-04-20T17:21:07Z
it is
---------------------------------------------------------------------------
by vicb at 2012-05-20T19:57:51Z
@fabpot this should be ready to be merged
This commit is contained in:
commit
87bb3661fc
@ -16,6 +16,7 @@ namespace Symfony\Component\HttpFoundation;
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
* @author Robert Kiss <kepten@gmail.com>
|
||||
*/
|
||||
class ServerBag extends ParameterBag
|
||||
{
|
||||
@ -32,10 +33,41 @@ class ServerBag extends ParameterBag
|
||||
}
|
||||
}
|
||||
|
||||
// PHP_AUTH_USER/PHP_AUTH_PW
|
||||
if (isset($this->parameters['PHP_AUTH_USER'])) {
|
||||
$pass = isset($this->parameters['PHP_AUTH_PW']) ? $this->parameters['PHP_AUTH_PW'] : '';
|
||||
$headers['AUTHORIZATION'] = 'Basic '.base64_encode($this->parameters['PHP_AUTH_USER'].':'.$pass);
|
||||
$headers['PHP_AUTH_USER'] = $this->parameters['PHP_AUTH_USER'];
|
||||
$headers['PHP_AUTH_PW'] = isset($this->parameters['PHP_AUTH_PW']) ? $this->parameters['PHP_AUTH_PW'] : '';
|
||||
} else {
|
||||
/*
|
||||
* php-cgi under Apache does not pass HTTP Basic user/pass to PHP by default
|
||||
* For this workaround to work, add this line to your .htaccess file:
|
||||
* RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
*
|
||||
* A sample .htaccess file:
|
||||
* RewriteEngine On
|
||||
* RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
* RewriteCond %{REQUEST_FILENAME} !-f
|
||||
* RewriteRule ^(.*)$ app.php [QSA,L]
|
||||
*/
|
||||
|
||||
$authorizationHeader = null;
|
||||
if (isset($this->parameters['HTTP_AUTHORIZATION'])) {
|
||||
$authorizationHeader = $this->parameters['HTTP_AUTHORIZATION'];
|
||||
} elseif (isset($this->parameters['REDIRECT_HTTP_AUTHORIZATION'])) {
|
||||
$authorizationHeader = $this->parameters['REDIRECT_HTTP_AUTHORIZATION'];
|
||||
}
|
||||
|
||||
// Decode AUTHORIZATION header into PHP_AUTH_USER and PHP_AUTH_PW
|
||||
if (null !== $authorizationHeader) {
|
||||
$exploded = explode(':', base64_decode(substr($authorizationHeader, 6)));
|
||||
if (count($exploded) == 2) {
|
||||
list($headers['PHP_AUTH_USER'], $headers['PHP_AUTH_PW']) = $exploded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PHP_AUTH_USER/PHP_AUTH_PW
|
||||
if (isset($headers['PHP_AUTH_USER'])) {
|
||||
$headers['AUTHORIZATION'] = 'Basic '.base64_encode($headers['PHP_AUTH_USER'].':'.$headers['PHP_AUTH_PW']);
|
||||
}
|
||||
|
||||
return $headers;
|
||||
|
@ -56,7 +56,7 @@ class BasicAuthenticationListener implements ListenerInterface
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
if (false === $username = $request->server->get('PHP_AUTH_USER', false)) {
|
||||
if (false === $username = $request->headers->get('PHP_AUTH_USER', false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ class BasicAuthenticationListener implements ListenerInterface
|
||||
}
|
||||
|
||||
try {
|
||||
$token = $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $request->server->get('PHP_AUTH_PW'), $this->providerKey));
|
||||
$token = $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $request->headers->get('PHP_AUTH_PW'), $this->providerKey));
|
||||
$this->securityContext->setToken($token);
|
||||
} catch (AuthenticationException $failed) {
|
||||
$this->securityContext->setToken(null);
|
||||
|
@ -40,6 +40,8 @@ class ServerBagTest extends \PHPUnit_Framework_TestCase
|
||||
'CONTENT_LENGTH' => '0',
|
||||
'ETAG' => 'asdf',
|
||||
'AUTHORIZATION' => 'Basic '.base64_encode('foo:bar'),
|
||||
'PHP_AUTH_USER' => 'foo',
|
||||
'PHP_AUTH_PW' => 'bar',
|
||||
), $bag->getHeaders());
|
||||
}
|
||||
|
||||
@ -47,6 +49,43 @@ class ServerBagTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$bag = new ServerBag(array('PHP_AUTH_USER' => 'foo'));
|
||||
|
||||
$this->assertEquals(array('AUTHORIZATION' => 'Basic '.base64_encode('foo:')), $bag->getHeaders());
|
||||
$this->assertEquals(array(
|
||||
'AUTHORIZATION' => 'Basic '.base64_encode('foo:'),
|
||||
'PHP_AUTH_USER' => 'foo',
|
||||
'PHP_AUTH_PW' => ''
|
||||
), $bag->getHeaders());
|
||||
}
|
||||
|
||||
public function testHttpBasicAuthWithPhpCgi()
|
||||
{
|
||||
$bag = new ServerBag(array('HTTP_AUTHORIZATION' => 'Basic '.base64_encode('foo:bar')));
|
||||
|
||||
$this->assertEquals(array(
|
||||
'AUTHORIZATION' => 'Basic '.base64_encode('foo:bar'),
|
||||
'PHP_AUTH_USER' => 'foo',
|
||||
'PHP_AUTH_PW' => 'bar'
|
||||
), $bag->getHeaders());
|
||||
}
|
||||
|
||||
public function testHttpBasicAuthWithPhpCgiRedirect()
|
||||
{
|
||||
$bag = new ServerBag(array('REDIRECT_HTTP_AUTHORIZATION' => 'Basic '.base64_encode('foo:bar')));
|
||||
|
||||
$this->assertEquals(array(
|
||||
'AUTHORIZATION' => 'Basic '.base64_encode('foo:bar'),
|
||||
'PHP_AUTH_USER' => 'foo',
|
||||
'PHP_AUTH_PW' => 'bar'
|
||||
), $bag->getHeaders());
|
||||
}
|
||||
|
||||
public function testHttpBasicAuthWithPhpCgiEmptyPassword()
|
||||
{
|
||||
$bag = new ServerBag(array('HTTP_AUTHORIZATION' => 'Basic '.base64_encode('foo:')));
|
||||
|
||||
$this->assertEquals(array(
|
||||
'AUTHORIZATION' => 'Basic '.base64_encode('foo:'),
|
||||
'PHP_AUTH_USER' => 'foo',
|
||||
'PHP_AUTH_PW' => ''
|
||||
), $bag->getHeaders());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user