php digest authentication
November 16th, 2006 by admin
some php scripts (like oscommerce) do not have an user authentication.
therefor i google a little bit and found a nice small script from Paul James (thank you paul).
this script does an http digest authentication. this digest should fit all your needs for security and can replace the silly .htaccess.
i optimized the php class a little bit and make it much easier to use.
also i add the "stale" value wich is very important for the usability.
here is how to use it.
add this to your unprotected script (just at the top)
PHP:
-
require('authentication.php');
-
$auth = new HTTPDigest();
-
$auth->baseURL = '/';
-
$auth->nonceLife = 60;
-
$auth->opaque = 'give me a random string';
-
$auth->privateKey = 'thIS is my privat3 k3Y -> change me';
-
$auth->realm = 'please login to '.$_SERVER['SERVER_NAME'];
-
-
//add the user user/pass
-
$auth->passwordsHashed = false;
-
$auth->add_user('user','pass');
-
//or (it is mostly the same, but short)
-
//$auth->add_user('user','pass',true);
-
-
//an better way is the hashed pass
-
// you get the hashed pass with echo $auth->crypt_pass('user','pass');
-
// it should look like this
-
//$auth->add_user('user','9d1414171dff4c587870eac7da3fb929');
-
-
//thats it and of cause you can add more than one user
-
//$auth->add_user('user1','pass1');
-
//$auth->add_user('user2','pass2');
-
-
if (!$auth->authenticate())
-
$auth->error();
authentication.php:
PHP:
-
/*
-
orginal script @ http://www.peej.co.uk/projects/phphttpdigest.html
-
Copyright (c) 2005 Paul James
-
All rights reserved.
-
Redistribution and use in source and binary forms, with or without
-
modification, are permitted provided that the following conditions
-
are met:
-
1. Redistributions of source code must retain the above copyright
-
notice, this list of conditions and the following disclaimer.
-
2. Redistributions in binary form must reproduce the above copyright
-
notice, this list of conditions and the following disclaimer in the
-
documentation and/or other materials provided with the distribution.
-
3. Neither the name of the Paul James nor the names of its contributors
-
may be used to endorse or promote products derived from this software
-
without specific prior written permission.
-
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
-
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-
SUCH DAMAGE.
-
*/
-
-
/** HTTP Digest authentication class modified by macosbrain*/
-
class HTTPDigest
-
{
-
/** The Digest opaque value (any string will do, never sent in plain text over the wire).
-
* @var str
-
*/
-
var $opaque = 'enter a random string';
-
/** The authentication realm name.
-
* @var str
-
*/
-
var $realm = 'please login';
-
/**
-
* flag to indicate the nonce was stale.
-
*
-
* @var bool
-
*/
-
var $stale = false;
-
/** The base URL of the application, auth data will be used for all resources under this URL.
-
* @var str
-
*/
-
var $baseURL = '/';
-
/** Are passwords stored as an a1 hash (username:realm:password) rather than plain text.
-
* @var str
-
*/
-
var $passwordsHashed = true;
-
/** The private key.
-
* @var str
-
*/
-
var $privateKey = 'please choose one';
-
/** The life of the nonce value in seconds
-
* @var int
-
*/
-
var $nonceLife = 30;// the $stale option allows us to set the $nonceLife very low
-
-
function HTTPDigest()
-
{
-
$this->unique = $_SERVER['SERVER_SOFTWARE'].$_SERVER['HTTP_HOST'].$_SERVER['SERVER_NAME'];//not a static value
-
}
-
-
function error()
-
{
-
die('User authentication is required. You must enter a valid login ID and password to access this resource or have to disable your proxy-server.');
-
}
-
/** Send HTTP Auth header */
-
function send()
-
{
-
$str = 'WWW-Authenticate: Digest '.
-
'realm="'.$this->realm.'", '.
-
'domain="'.$this->baseURL.'", '.
-
'qop=auth, '.
-
'algorithm=MD5, '.
-
'nonce="'.$this->getNonce().'", '.
-
'opaque="'.$this->getOpaque().'"';
-
if ($this->stale) {
-
$str .= ', stale=true';
-
}
-
}
-
/** Get the HTTP Auth header
-
* @return str
-
*/
-
function add_user($username,$password,$hash_it=false)
-
{
-
if ($hash_it==true)
-
$a1 = $this->crypt_pass($username,$password);
-
else
-
$a1 = $password;
-
$this->user[$username] = $a1;
-
}
-
-
function crypt_pass($user,$pass)
-
{
-
}
-
-
function getAuthHeader()
-
{
-
{
-
return $_SERVER['Authorization'];
-
}
-
{
-
return $headers['Authorization'];
-
}
-
return NULL;
-
}
-
/** Authenticate the user and return username on success.
-
* @param str[] users Array of username/password pairs
-
* @return str
-
*/
-
function authenticate()
-
{
-
$authorization = $this->getAuthHeader();
-
if (!$authorization)
-
{
-
$this->send();
-
//die('HTTP Digest headers not being passed to PHP by the server, unable to authenticate user');
-
}
-
if (preg_match('/username="([^"]+)"/', $authorization, $username) && preg_match('/nonce="([^"]+)"/', $authorization, $nonce) && preg_match('/response="([^"]+)"/', $authorization, $response) && preg_match('/opaque="([^"]+)"/', $authorization, $opaque) && preg_match('/uri="([^"]+)"/', $authorization, $uri))
-
{
-
$username = $username[1];
-
$requestURI = $_SERVER['REQUEST_URI'];
-
{ // hack for IE which does not pass querystring in URI element of Digest string or in response hash
-
}
-
{
-
if($nonce[1] != $this->getNonce())
-
{
-
$this->stale = true;
-
$this->send();
-
}
-
$passphrase = $this->user[$username];
-
if ($this->passwordsHashed)
-
$a1 = $passphrase;
-
else
-
$a1 = $this->crypt_pass($username,$passphrase);
-
-
if (preg_match('/qop="?([^,\s"]+)/', $authorization, $qop) && preg_match('/nc=([^,\s"]+)/', $authorization, $nc) && preg_match('/cnonce="([^"]+)"/', $authorization, $cnonce))
-
else
-
if ($response[1] == $expectedResponse)
-
{
-
$this->logged_in_user = $username;
-
return TRUE;
-
}
-
}
-
else
-
$this->send();
-
}
-
return NULL;
-
}
-
/** Get nonce value for HTTP Digest.
-
* @return str
-
*/
-
function getNonce() {
-
$nonce = date('Y-m-d H:i', $time).':'.$_SERVER['REMOTE_ADDR'].':'.$this->privateKey.':'.$_SERVER['HTTP_USER_AGENT'].$this->unique;
-
}
-
/** Get opaque value for HTTP Digest.
-
* @return str
-
*/
-
function getOpaque()
-
{
-
}
-
/** Get realm for HTTP Digest taking PHP safe mode into account.
-
* @return str
-
*/
-
function getRealm()
-
{
-
} else {
-
return $this->realm;
-
}
-
}
-
}
August 24th, 2007 at 20:14
Did you ever get it to work with safari or opera?
Thanks..
August 28th, 2007 at 12:53
i know that it works with the most common browser(ie and firefox). with a small bugfix it will also work with the opera browser.
i don’t got a mac right here so i can not test it with the safari browser.
November 8th, 2007 at 00:29
Hi the script works fine with ie7 but not ie6. I think this is because the username and password and not passed in the xmlHTTPRequest which remains undefined when using ie6 resulting in the $auth error condition. Any ideas?
Thanks
David
Oktober 6th, 2008 at 07:07
hi
I was trying to get digest authentication working on lighttpd server while processing response in javascript. But whenever server replies with 401 browser pops up login box which i dont want. Is there any way that i can get nonce & realm from server & pass it to javascript instead of browser….
November 13th, 2008 at 12:24
hi admin,
can you let me know what the fix that will make it work with Opera? I am looking for a solution for this problem on opera.