1<?php 2/** 3 * DooDigestAuth class file. 4 * 5 * @author Leng Sheng Hong <darkredz@gmail.com> 6 * @link http://www.doophp.com/ 7 * @copyright Copyright © 2009 Leng Sheng Hong 8 * @license http://www.doophp.com/license 9 */ 10 11/** 12 * Handles HTTP digest authentication 13 * 14 * <p>HTTP digest authentication can be used with the URI router. 15 * HTTP digest is much more recommended over the use of HTTP Basic auth which doesn't provide any encryption. 16 * If you are running PHP on Apache in CGI/FastCGI mode, you would need to 17 * add the following line to your .htaccess for digest auth to work correctly.</p> 18 * <code>RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]</code> 19 * 20 * <p>This class is tested under Apache 2.2 and Cherokee web server. It should work in both mod_php and cgi mode.</p> 21 * 22 * @author Leng Sheng Hong <darkredz@gmail.com> 23 * @version $Id: DooDigestAuth.php 1000 2009-07-7 18:27:22 24 * @package doo.auth 25 * @since 1.0 26 * 27 * @deprecated 2.3 This will be removed in Minify 3.0 28 */ 29class DooDigestAuth{ 30 31 /** 32 * Authenticate against a list of username and passwords. 33 * 34 * <p>HTTP Digest Authentication doesn't work with PHP in CGI mode, 35 * you have to add this into your .htaccess <code>RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]</code></p> 36 * 37 * @param string $realm Name of the authentication session 38 * @param array $users An assoc array of username and password: array('uname1'=>'pwd1', 'uname2'=>'pwd2') 39 * @param string $fail_msg Message to be displayed if the User cancel the login 40 * @param string $fail_url URL to be redirect if the User cancel the login 41 * @return string The username if login success. 42 */ 43 public static function http_auth($realm, $users, $fail_msg=NULL, $fail_url=NULL){ 44 $realm = "Restricted area - $realm"; 45 46 //user => password 47 //$users = array('admin' => '1234', 'guest' => 'guest'); 48 if(!empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && strpos($_SERVER['REDIRECT_HTTP_AUTHORIZATION'], 'Digest')===0){ 49 $_SERVER['PHP_AUTH_DIGEST'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; 50 } 51 52 if (empty($_SERVER['PHP_AUTH_DIGEST'])) { 53 header('WWW-Authenticate: Digest realm="'.$realm. 54 '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); 55 header('HTTP/1.1 401 Unauthorized'); 56 if($fail_msg!=NULL) 57 die($fail_msg); 58 if($fail_url!=NULL) 59 die("<script>window.location.href = '$fail_url'</script>"); 60 exit; 61 } 62 63 // analyze the PHP_AUTH_DIGEST variable 64 if (!($data = self::http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || !isset($users[$data['username']])){ 65 header('WWW-Authenticate: Digest realm="'.$realm. 66 '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); 67 header('HTTP/1.1 401 Unauthorized'); 68 if($fail_msg!=NULL) 69 die($fail_msg); 70 if($fail_url!=NULL) 71 die("<script>window.location.href = '$fail_url'</script>"); 72 exit; 73 } 74 75 // generate the valid response 76 $A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]); 77 $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']); 78 $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2); 79 80 if ($data['response'] != $valid_response){ 81 header('HTTP/1.1 401 Unauthorized'); 82 header('WWW-Authenticate: Digest realm="'.$realm. 83 '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); 84 if($fail_msg!=NULL) 85 die($fail_msg); 86 if($fail_url!=NULL) 87 die("<script>window.location.href = '$fail_url'</script>"); 88 exit; 89 } 90 91 // ok, valid username & password 92 return $data['username']; 93 } 94 95 /** 96 * Method to parse the http auth header, works with IE. 97 * 98 * Internet Explorer returns a qop="xxxxxxxxxxx" in the header instead of qop=xxxxxxxxxxx as most browsers do. 99 * 100 * @param string $txt header string to parse 101 * @return array An assoc array of the digest auth session 102 */ 103 private static function http_digest_parse($txt) 104 { 105 $res = preg_match("/username=\"([^\"]+)\"/i", $txt, $match); 106 $data['username'] = (isset($match[1]))?$match[1]:null; 107 $res = preg_match('/nonce=\"([^\"]+)\"/i', $txt, $match); 108 $data['nonce'] = $match[1]; 109 $res = preg_match('/nc=([0-9]+)/i', $txt, $match); 110 $data['nc'] = $match[1]; 111 $res = preg_match('/cnonce=\"([^\"]+)\"/i', $txt, $match); 112 $data['cnonce'] = $match[1]; 113 $res = preg_match('/qop=([^,]+)/i', $txt, $match); 114 $data['qop'] = str_replace('"','',$match[1]); 115 $res = preg_match('/uri=\"([^\"]+)\"/i', $txt, $match); 116 $data['uri'] = $match[1]; 117 $res = preg_match('/response=\"([^\"]+)\"/i', $txt, $match); 118 $data['response'] = $match[1]; 119 return $data; 120 } 121 122 123} 124