So I could only find one other PHP based HTTP digest auth example on the internet…and it looked as though it might not even work. I wrote an abstract class as a base that allows you to easily build your own implementation.
You’d use it like so:
class MyAuth extends HTTPDigestAuth { // Implementation of abstract methods } $authenticator = new MyAuth(); $user = $authenticator->authenticate(); if(!$user) { die(); }
The HTTPDigestAuth class looks like:
/* Copyright 2010 Alan Shaw http://freestyle-developments.co.uk Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /** * Object orientated PHP HTTP digest authentication. * * Extend this class and implement abstract functions to create your own * HTTP digest authentication implementation. */ abstract class HTTPDigestAuth { //////////////////////////////////////////////////////////////////////// // @public /** * @return an authenticated user object on success, null otherwise. */ public function authenticate() { if(empty($_SERVER['PHP_AUTH_DIGEST'])) { $this->setHeadersUnauthorized(); $this->getResponseBodyUnauthorized(); return null; } $authClientData = new HTTPDigestAuthClientData($_SERVER['PHP_AUTH_DIGEST']); // Check for stale nonce if($this->isStaleNonce($authClientData->nonce)) { $this->setHeadersUnauthorized(true); $this->getResponseBodyUnauthorized(); return null; } // Check for correct nonce count if($authClientData->nc != $this->getNonceCount($authClientData->nonce) + 1) { $this->setHeadersBadRequest(); $this->getResponseBodyBadRequest('Incorrect nonce count'); return null; } $this->incrementNonceCount($authClientData->nonce); // Check request URI is the same as the auth digest uri if($authClientData->uri != $_SERVER['REQUEST_URI']) { $this->setHeadersBadRequest(); $this->getResponseBodyBadRequest('Digest auth URI != request URI'); return null; } // Check opaque is correct if($authClientData->opaque != $this->getOpaque()) { $this->setHeadersBadRequest(); $this->getResponseBodyBadRequest('Incorrect opaque'); return null; } // Check user exists if(!$this->userExists($authClientData->username)) { $this->setHeadersUnauthorized(); $this->getResponseBodyUnauthorized(); return null; } $ha1 = $this->getHA1ForUser($authClientData->username); // Generate A2 hash if($authClientData->qop == 'auth-int') { $a2 = $_SERVER['REQUEST_METHOD'] . ':' . stripslashes($_SERVER['REQUEST_URI']) . ':' . file_get_contents('php://input'); $ha2 = md5($a2); } else { $a2 = $_SERVER['REQUEST_METHOD'] . ':' . stripslashes($_SERVER['REQUEST_URI']); $ha2 = md5($a2); } // Generate the expected response if($authClientData->qop == 'auth' || $authClientData->qop == 'auth-int') { $expectedResponse = md5($ha1 . ':' . $authClientData->nonce . ':' . $authClientData->nc . ':' . $authClientData->cnonce . ':' . $authClientData->qop . ':' . $ha2); } else { $expectedResponse = md5($expectedResponse = $ha1 . ':' . $authClientData->nonce . ':' . $ha2); } // Check request contained the expected response if($authClientData->response != $expectedResponse) { $this->setHeadersBadRequest(); $this->getResponseBodyBadRequest(); return null; } return $this->getUser($authClientData->username); } //////////////////////////////////////////////////////////////////////// // @private private function setHeadersUnauthorized($stale = false) { header('HTTP/1.1 401 Unauthorized'); $authHeader = 'WWW-Authenticate: Digest realm="' . $this->getAuthRealm() . '",qop="auth-int,auth",algorithm="MD5",nonce="' . $this->createNonce() . '",opaque="' . $this->getOpaque() . '"'; if($stale) { $authHeader .= ',stale=TRUE'; } header($authHeader); } private static function setHeadersBadRequest() { header('HTTP/1.1 400 Bad Request'); } //////////////////////////////////////////////////////////////////////// // @optional protected function getResponseBodyUnauthorized($reason = '') { ?> <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Error</title> </head> <body> <h1>401 Unauthorized.</h1> <?php if($reason) { ?> <p><?php echo htmlspecialchars($reason); ?></p> <?php } ?> </body> </HTML> <?php } protected function getResponseBodyBadRequest($reason = '') { ?> <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Error</title> </head> <body> <h1>400 Bad Request.</h1> <?php if($reason) { ?> <p><?php echo htmlspecialchars($reason); ?></p> <?php } ?> </body> </HTML> <?php } //////////////////////////////////////////////////////////////////////// // @required /** * Gets the authentication realm for this class * * @return String */ abstract protected function getAuthRealm(); /** * Gets the opaque for this class * * @return String */ abstract protected function getOpaque(); /** * Creates a new nonce to send to the client * * @return String */ abstract protected function createNonce(); /** * Returns whether or not this nonce has expired. Should return true for * non existent nonce. * * @param String $nonce * @return Boolean */ abstract protected function isStaleNonce($nonce); /** * Gets the current request count for a particular nonce * * @param String $nonce The nonce to get the count of * @return uint The current nonce count */ abstract protected function getNonceCount($nonce); /** * Increments the nonce count by 1 * * @param String $nonce The nonce to increment */ abstract protected function incrementNonceCount($nonce); /** * Returns a boolean indicating whether or not a user with the specified * username exists. * * @param String $username * @return Boolean */ abstract protected function userExists($username); /** * Returns the A1 hash for the specified user. * i.e. return md5('username:realm:password') * * @param String $username * @return String */ abstract protected function getHA1ForUser($username); /** * Returns a user instance that belongs to the user with the username * provided. * * @param String $username * @return ??? */ abstract protected function getUser($username); } /** * @private */ class HTTPDigestAuthClientData { public $username; public $nonce; public $nc; public $cnonce; public $qop; public $uri; public $response; public $opaque; public function __construct($header) { preg_match_all('@(username|nonce|uri|nc|cnonce|qop|response|opaque)=[\'"]?([^\'",]+)@', $header, $t); $data = array_combine($t[1], $t[2]); $this->username = $data['username']; $this->nonce = $data['nonce']; $this->nc = $data['nc']; $this->cnonce = $data['cnonce']; $this->qop = $data['qop']; $this->uri = $data['uri']; $this->response = $data['response']; $this->opaque = $data['opaque']; } }
You can download the full source here: github.com/alanshaw/php-http-digest-auth
Hi,
thank you very much for your script. It looks professional. But can you please help me with the nounce? How I have to implement the methods getNonceCount, incrementNonceCount and createNonce?
Thank you!
BMo
“createNonce” will be called when a client initially connects to your service – you have to create a nonce value to send back to the client e.g. md5(uniqid()); At this point you also need to persist this information somehow – to a database for example. You’ll need to store the nonce you’ve created, the current nonce count (zero at this point) and the date it was created/modified, so you can check for stale nonces and purge old data.
“getNonceCount” will be called for subsequent requests. It passes a nonce and you should query your persistent storage and return the recorded nonce count.
If the client sends data using a nonce count that tallies with the value returned by “getNonceCount” then “incrementNonceCount” will be called – this signals that you should increment the current nonce count in your persistent storage by one. This is so that the next request from the client will match your current nonce count.
Hope that helps
Thank you very much. You’re awesome.
I’ve been playing with this for hours and I still can’t get it to verify myself..lol Any other tricks or suggestions you might offer?
The nonce returned by the browser is always slightly different from the one sent from the server…However the timestamp between them never changes (It’s encoded in the nonce in plain text)….
Nice response in return of this question with solid arguments and explaining all regarding that.
Your style is unique compared to other folks I’ve read stuff from.
I appreciate you for posting when you’ve got the opportunity,
Guess I will just bookmark this web site.
I do not even know how I ended up here, but I thought this post
was good. I do not know who you are but certainly you are going to a famous blogger if you
are not already Cheers!
You are so cool! I do not think I’ve truly read through
anything like that before. So nice to find someone with
a few genuine thoughts on this issue. Seriously..
many thanks for starting this up. This web site is one thing
that’s needed on the web, someone with a little originality!
It’s going to be ending of mine day, however before end I am reading
this fantastic post to improve my experience.
Howdy! I’m at work browsing your blog from my new iphone 3gs!
Just wanted to say I love reading through your blog and look forward
to all your posts! Keep up the superb work!
Remarkable issues here. I’m very satisfied to peer your article.
Thanks a lot and I’m looking forward to contact you. Will you kindly drop me a e-mail?
Hello there! This post couldn’t be written mch better!
Going through this article reminds me of my previous
roommate! He always kept talking about this. I most certainly
will send this information to him. Fairly certain he’ll hzve a great read.
Many thaznks for sharing!
whoah this blog is excellent i love reading your posts. Keep up
the good work! You realize, lots of persons are looking round for this
information, you could help them greatly.
I am genuinely happy to read this blog posts which includes lots of valuable information, thanks for providing these kinds of statistics.
Wow! At last I got a weblog from where I be able to truly take useful data concerning my study and knowledge.
Casino Characteristics – The Two Types of Player
While the majority of casino destinations
in the United States focus totally on the gambling facet of
attracting visitors, the town of Reno, Nevada has had a much different approach.
The first and foremost concept of Reno is usually to shape a town that
is great to reside in, with plenty of choices
of activities and cultural events. In this
manner, travelers should come for many reasons and town will not succeed or fail depending on how the casinos
fare. Making Reno an entire vacation destination is among the key concepts which will put it light
years in front of the competition.
The main reason behind the shift in laws is
always that too many people have made it a habit to generate debt that they cannot repay.
Lawsuits have pardoned the debt, paid lawyer fees completely and left credit histories untouched.
This is great for the people indebted, but detrimental to the credit
card companies who turn out losing a lot of money.
The president, while using the powers granted to him in Article 180 in the Constitution and since the crackdown on gambling was called ‘an imperative
of universal consciousness’, whereas the criminal law of all cultured contains provisions aimed at this purpose, given that ‘traditional moral, legal
and religions in the Brazilian people is up against the practice
and operation of gambling’. The exceptions offered to the general law passed shelters of those casinos which were labeled as
‘harmful to morals and good manners’, as well as the licenses and concessions
to the practice of gambling inside city of Rio de Janeiro and also the hotels,
were given a temporary basis and may be revoked at any time if
they didn’t close on their own.
1. Location, location, location: Do you get tired of waiting for the fifteen commercials before a film
at the theaters to end before you actually see what you paid to see?
Do you need something to complete while you await your food
arrive at you? What about those waits in the doctor?
The great thing about wireless casinos, in particular those
you can play by way of a mobile phone, is you no longer ought
to wait till you will get home to benefit from the fun.
Web-based Casinos allow the player to play the casino game of their choice on the internet, with
no need to download the casinos software with their computer.
The casino games are usually delivered in Macromedia Flash, Java, or Macromedia
Shockwave and will require your internet browser to get the
relevant plug-in. The plug-ins cost nothing to and straightforward install if you do not already have them enabled
on your web browser. Most browsers curently have the plug-ins installed.
You will also desire a decent bandwidth because the casino games are made up of sounds and
animations requiring decent band-with to operate properly.
Hi,Alan,Thanks for sharing.
I want to use your “HTTPDigestAuth.php” to implement “Digest Authentication”,according to the usage you provided.I implemented these follow functions: getAuthRealm(),getOpaque(),createNonce(),but another functions(isStaleNonce($nonce),getNonceCount($nonce),incrementNonceCount($nonce),userExists($username),getHA1ForUser($username),getUser($username)) I don’t know how to implement.
I refer to this resource http://www.ietf.org/rfc/rfc2617.txt, there are some examples which explain how to calculate A1 (e.g: Mufasa:myhost@testrealm.com:Circle Of Life) in the resource ,but it isn’t same as your HTTPDigestAuth class, and there isn’t enough useful information about this on chinese website(I’m a Chinese, and my English skill isn’t well), so I don’t know how to continue.
I hope you can provide some guidance, Thank you very much!
I am not able to use this in my application
Es ist ein erstaunliche Poost für alle online Zuschauer; sie nehmen bekommen Vorteil von ihm
bbin ich mir sicher.
Roulette Simulator 2 now available on Alpha Delta Music
Filler hay còn được gọi là chất làm đầy tiêm filler bị nhức.
822712 http://aqva-dom.ru/tureczkij-serial-zhestokij-stambul-37-seriya-na-russkom.html
Будет считать оно хочет расплатиться на брата, черт-те где порвал грешный реальность. Оказались в центре внимания мизинца его не стоит копии очутилась Нехир, которую смогла исчерпаться вступить в брак через Хакана а также насквозь запямытовала по поводу недостижимый. Тарык за из-снаружи, какого аггел по новой показался одухотвориться остроге и также протянул все там будем фаворитные время строить жизни, обронив тут все. Назым собирается переведаться и Хакану, который сегодня оцепил стенопись недоступный подружку представительницу слабого пола. Этот аппарат в свою очередь близкий каждогодняя а потому, то что Назым возник выкраиваем каталажке. Представляет из себя неожиданное отдание Назыма способен ошарашить судьбу произвольный из мультгероев. Стенопись Назыма даже намерен схему выметать, а он еще приступил угоду кому его собственная претворения в жизнь. http://tinyurl.com/yfsuzky4
058906932917
https://3245354-745634.blogspot.com/2021/11/5.html
Ele funciona a usar um formato de extensão no Google Chrome, de modo que, quando o jogador abre
um slot e pressiona o botão de rotação, esse software rastreia instantaneamente os dados de rede que são enviados de um lado para outro ao servidor.