Authentication broken in php cgi mode
greggles - November 14, 2006 - 23:48
| Project: | HTTP authentication |
| Version: | 5.x-1.x-dev |
| Component: | Code |
| Category: | bug report |
| Priority: | critical |
| Assigned: | naquah |
| Status: | closed |
Description
This is just a note to say that it's worth testing this on a server where php runs in cgi mode. Securesite (which is very similar) has a weakness that it cannot work under php-cgi. So, I imagine the same is the case here. Once that is confirmed it would be helpful to document the fact for new users.

#1
Hmm I wouldn't think the way PHP is installed would affect sending and receiving some headers.
But I'll look into the matter, thanks for your comment!
#2
Here is the issue from securesite http://drupal.org/node/28408
Perhaps it will give some clues.
#3
Their has been a workaround found for the CGI problem thanks to moshe weitzman. Have a look at the last few posts on this issue. http://drupal.org/node/28408
I am going to try to get the workaround into securesite later this week. The only complication is that it requires patching the .htaccess file.
#4
Thanks, I'll take a look at it!
#5
no patch to .htaccess. just add a few lines to settings.php. i am not running httpautgh on groupsbeta.drupal.org and soon groups.drupal.org. i had to tweak it a bit.
#6
I've just finished my virtualized Gentoo install, so I can test under CGI mode myself.
#7
@moshe
How exactly, I can't get it to work with $_SERVER['Authentication'], I need the .htaccess fix.
Are you, or are you not?
#8
Oops didn't close that last blockquote there.
#9
you are probably right. the server admins at drupal.org likely made changed in their .conf file so that i didn't need to do anything in .htaccess
i am indeed using this on groups.drupal.org. i had to patch the init function so the auth would fire on specified paths (like seduresite). i only use this to protect rss feed paths. otherwise, users should login using regular html box. so i am not using the (neat) callback feature which typically fires on 403 error ... i use this module because securesite was getting too complex for my taste.
#10
Thanks for your clarification. It pleases me you're using httpauth on groups.drupal.org, it always motivates to hear from people who're using your stuff.
Alright, I'll probably solve the .htaccess issue by asking the user if he/she wants to have the file changed automagically.
I submitted a feature request to httpauth that will allow authentication to be fired regardless of whether a 403 error was returned. This will be an optional feature.
Please: can somebody with the sufficient permissions close the blockquote tag after "a bit." in #8? Thanks.
#11
Note to self: fix this soon!
Will need porting to 5.x too.
#12
I applied the attached patch to all branches. You can either wait a few hours for the package update script to update the development package, or apply the patch yourself by running
patch < httpauth_cgi.patchin the httpauth directory.You will also need to add the following line to the .htaccess file in your Drupal root directory, just under
RewriteBase /drupal(might have a # in front of it) but above# Rewrite old-style URLs ...:RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]Works for me. Please tell me if it fixes everybody's problems, then I can find a user-friendly solution for the .htaccess fiddling.
Thanks.
#13
I still can't get this to work. I'm starting from a clean 5.1 install, and the only things I've done is enable the HTTP Authentication module and add the line from above to .htaccess. Is there something else I should be doing?
#14
Are you getting a username and password prompt?
#15
Yes. It just repeats.
So, I've been doing a little debugging here and it appears that either the HTTP_AUTHENTICATION environment variable is not being set, or that PHP can't access it. Either way, I'm only able to access the HTTP:Authentication string if I put it on the query string. In other words, here is my .htaccess:
RewriteEngine onRewriteCond %{HTTP:Authorization} .*
RewriteRule authenticate.php authenticate.php?login=%{HTTP:Authorization}
And here is my php test file (authenticate.php):
<?php
// split the user/pass parts
$d = base64_decode(substr($_GET['login'],6) );
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', $d);
// open a user/pass prompt
if ($_SERVER['PHP_AUTH_USER']=='') {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
echo 'Text to send if user hits Cancel button';
exit;
} else {
echo "<p>Hello, </p>".$_SERVER['PHP_AUTH_USER'];
echo "<p>You entered as your password: </p>".$_SERVER['PHP_AUTH_PW'];
}
?>
I figured this out from this page, by the way: http://www.besthostratings.com/articles/http-auth-php-cgi.html.
#16
Thanks, I will try the same thing on my virtualized PHP-CGI-box, the environment variable should be set.
If the variable is not set, there is something larger at hand, maybe.
#17
Can you do the same test again, with the following alterations:
Add
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]to .htaccess just after deRewriteCondbut before theRewriteRuleAdd
echo "<pre>"; var_dump($_GET); var_dump($_SERVER);at then end of authenticate.php.Please send me the output, so I can see what variables are being set exactly.
#18
Well, I tried dumping the environment variables, and sure enough, .htaccess isn't having any effect on them. I did a little more digging, and apparently there is a server setting somewhere that prevents .htaccess from changing environment variables (see, e.g., comments to http://us.php.net/features.http-auth). I use HostGator. I guess I'll shoot them off an email to see if they can change their settings, or maybe even resort to hacking up a version that will authenticate using the _GET trick.
Anyway, here was the output:
karl
You entered as your password:
1234
array(1) {
["login"]=>
string(18) "Basic a2FybDoxMjM0"
}
array(37) {
["PATH"]=>
string(28) "/usr/local/bin:/usr/bin:/bin"
["DOCUMENT_ROOT"]=>
string(31) "[omitted]"
["HTTP_ACCEPT"]=>
string(3) "*/*"
["HTTP_ACCEPT_ENCODING"]=>
string(13) "gzip, deflate"
["HTTP_ACCEPT_LANGUAGE"]=>
string(5) "en-us"
["HTTP_CONNECTION"]=>
string(10) "Keep-Alive"
["HTTP_COOKIE"]=>
string(56) "PHPSESSID=5e459520f186f7e1a1f08c8647f71aec; cprelogin=no"
["HTTP_HOST"]=>
string(17) "test.reeshome.org"
["HTTP_UA_CPU"]=>
string(3) "x86"
["HTTP_USER_AGENT"]=>
string(82) "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; InfoPath.1)"
["REDIRECT_QUERY_STRING"]=>
string(24) "login=Basic a2FybDoxMjM0"
["REDIRECT_STATUS"]=>
string(3) "200"
["REDIRECT_URL"]=>
string(17) "/authenticate.php"
["REMOTE_ADDR"]=>
string(11) "24.2.88.154"
["REMOTE_PORT"]=>
string(5) "62566"
["SCRIPT_FILENAME"]=>
string(48) "[omitted]authenticate.php"
["SERVER_ADDR"]=>
string(13) "74.53.108.130"
["SERVER_ADMIN"]=>
string(27) "[omitted]"
["SERVER_NAME"]=>
string(17) "test.reeshome.org"
["SERVER_PORT"]=>
string(2) "80"
["SERVER_SOFTWARE"]=>
string(151) "Apache/1.3.37 (Unix) mod_auth_passthrough/1.8 mod_log_bytes/1.2 mod_bwlimited/1.4 FrontPage/5.0.2.2635.SR1.2 mod_ssl/2.8.28 OpenSSL/0.9.7a PHP-CGI/0.1b"
["GATEWAY_INTERFACE"]=>
string(7) "CGI/1.1"
["SERVER_PROTOCOL"]=>
string(8) "HTTP/1.1"
["REQUEST_METHOD"]=>
string(3) "GET"
["QUERY_STRING"]=>
string(24) "login=Basic a2FybDoxMjM0"
["REQUEST_URI"]=>
string(17) "/authenticate.php"
["SCRIPT_NAME"]=>
string(17) "/authenticate.php"
["ORIG_SCRIPT_FILENAME"]=>
string(30) "/usr/local/cpanel/cgi-sys/php5"
["ORIG_PATH_INFO"]=>
string(17) "/authenticate.php"
["ORIG_PATH_TRANSLATED"]=>
string(48) "[omitted]authenticate.php"
["ORIG_SCRIPT_NAME"]=>
string(13) "/cgi-sys/php5"
["PHP_SELF"]=>
string(17) "/authenticate.php"
["REQUEST_TIME"]=>
int(1178584385)
["argv"]=>
array(1) {
[0]=>
string(24) "login=Basic a2FybDoxMjM0"
}
["argc"]=>
int(1)
["PHP_AUTH_PW"]=>
string(4) "1234"
["PHP_AUTH_USER"]=>
string(4) "karl"
}
#19
OK, I guess I'll change it so that it rewrites the HTTP:Authorization variable to the query string (
$_GET) instead of to an environment variable (<code>$_SERVER). My only doubt is whether this poses a security threat... though I don't think the rewritten URL (including the query string containing as good as a plain password) is logged anywhere.karlrees, thank you, you're being very helpful!
#20
OK I changed some code. Please test it using the following in .htaccess:
# Rewrite HTTP authorization information to the query stringRewriteCond %{HTTP:Authorization} ^Basic
RewriteRule ^(.*)$ $1?HTTP_AUTHORIZATION=%{HTTP:Authorization} [QSA]
Note that the development package may take up to 12 hours to be updated to the new code.
#21
Sorry it took so long to find time to test it. It appears to work fine if I use the following code in .htaccess:
RewriteCond %{HTTP:Authorization} ^Basic
RewriteCond %{QUERY_STRING} !^$
RewriteRule ^(.*)$ $1&HTTP_AUTHORIZATION=%{HTTP:Authorization} [QSA]
RewriteCond %{HTTP:Authorization} ^Basic
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^(.*)$ $1?HTTP_AUTHORIZATION=%{HTTP:Authorization} [QSA]
I'm not sure if this is the cleanest code, but this is the only way to make it so ?authenticate will work. Plus, it's more compatible if other stuff is put in the query string.
#22
Great that we at least solved the problem!
Only the rewriting of the query string... Drupal does the following, which works if an existing query string is present:
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]Actually the QSA is what should nicely append the existing query string. I'll run some tests.
#23
Okay, so I never really got this working the first time around. I had some bug where the query string would keep growing appending the last segment of the drupal path to itself (so, for example, if I tried going to admin/content?authenticate, I'd wind up at admin/content//content instead).
I'm sure there's a better workaround somewhere, and I'm not sure that my workaround won't cause problems for other people, but here's my eventual solution.
This is in .htaccess
# Rewrite HTTP authorization information to the query stringRewriteCond %{HTTP:Authorization} ^Basic
RewriteCond %{QUERY_STRING} !HTTP_AUTHORIZATION
RewriteRule ^(.*)$ $1?HTTP_AUTHORIZATION=%{HTTP:Authorization} [L,QSA]
I only changed two lines in the httpauth_redirect() function. I know, I should make a patch, but I'm lazy. Here's the relevant changes:
// Get the current query string (if available) and add session information for clients that don't support cookies.
// *** added "authenticate"
if ($query = drupal_query_string_encode($_GET, array('q', 'HTTP_AUTHORIZATION', 'authenticate'))) {
$query .= '&'. strip_tags(SID);
}
else {
$query = strip_tags(SID);
}
// *** use the server name + script name instead of q from the query string
//drupal_goto($_GET['q'], $query);
drupal_goto("http://".$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME'], $query);
Hopefully this helps other people out there.
#24
I tested your .htaccess fix and it appears to work as advertised when using CGI or FastCGI.
It's now documented in the README.txt file. (I forgot to properly mention the issue# and your name in the commit message, sorry karlrees!)
The changes to httpauth_redirect() aren't necessary anymore, since I removed that function completely.
Thanks for all your help, everybody!
#25
Automatically closed -- issue fixed for two weeks with no activity.