[eluser]Phil Sturgeon[/eluser]
I approach this from another angle. The same end goal can be done via pure PHP which is a much better way to handle this seeing as CodeIgniter does not rely on sub-directories existing whereas .htpasswd does.
Here is some code from my REST controller which you can use to piece this together. This should go in a MY_Controller or possibly a hook. You can ignore the digest stuff and just use the Basic code if yu arent too worried about security.
Code:
private function _prepareBasicAuth()
{
$username = NULL;
$password = NULL;
// mod_php
if (isset($_SERVER['PHP_AUTH_USER']))
{
$username = $_SERVER['PHP_AUTH_USER'];
$password = $_SERVER['PHP_AUTH_PW'];
}
// most other servers
elseif (isset($_SERVER['HTTP_AUTHENTICATION']))
{
if (strpos(strtolower($_SERVER['HTTP_AUTHENTICATION']),'basic')===0)
{
list($username,$password) = explode(':',base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
}
}
if ( !$this->_checkLogin($username, $password) )
{
$this->_forceLogin();
}
}
private function _prepareDigestAuth()
{
$uniqid = uniqid(""); // Empty argument for backward compatibility
// We need to test which server authentication variable to use
// because the PHP ISAPI module in IIS acts different from CGI
if(isset($_SERVER['PHP_AUTH_DIGEST']))
{
$digest_string = $_SERVER['PHP_AUTH_DIGEST'];
}
elseif(isset($_SERVER['HTTP_AUTHORIZATION']))
{
$digest_string = $_SERVER['HTTP_AUTHORIZATION'];
}
else
{
$digest_string = "";
}
/* The $_SESSION['error_prompted'] variabile is used to ask
the password again if none given or if the user enters
a wrong auth. informations. */
if ( empty($digest_string) )
{
$this->_forceLogin($uniqid);
}
// We need to retrieve authentication informations from the $auth_data variable
preg_match_all('@(username|nonce|uri|nc|cnonce|qop|response)=[\'"]?([^\'",]+)@', $digest_string, $matches);
$digest = array_combine($matches[1], $matches[2]);
if ( !array_key_exists('username', $digest) || !$this->_checkLogin($digest['username']) )
{
$this->_forceLogin($uniqid);
}
$valid_logins =& $this->config->item('rest_valid_logins');
$valid_pass = $valid_logins[$digest['username']];
// This is the valid response expected
$A1 = md5($digest['username'] . ':' . $this->config->item('rest_realm') . ':' . $valid_pass);
$A2 = md5(strtoupper($this->_method).':'.$digest['uri']);
$valid_response = md5($A1.':'.$digest['nonce'].':'.$digest['nc'].':'.$digest['cnonce'].':'.$digest['qop'].':'.$A2);
if ($digest['response'] != $valid_response)
{
header('HTTP/1.0 401 Unauthorized');
header('HTTP/1.1 401 Unauthorized');
exit;
}
}
private function _forceLogin($nonce = '')
{
header('HTTP/1.0 401 Unauthorized');
header('HTTP/1.1 401 Unauthorized');
if($this->config->item('rest_auth') == 'basic')
{
header('WWW-Authenticate: Basic realm="'.$this->config->item('rest_realm').'"');
}
elseif($this->config->item('rest_auth') == 'digest')
{
header('WWW-Authenticate: Digest realm="'.$this->config->item('rest_realm'). '" qop="auth" nonce="'.$nonce.'" opaque="'.md5($this->config->item('rest_realm')).'"');
}
echo 'Text to send if user hits Cancel button';
die();
}