diff options
author | Michal Rezler <rezlemic@fel.cvut.cz> | 2011-03-23 10:39:45 +0100 |
---|---|---|
committer | Michal Rezler <rezlemic@fel.cvut.cz> | 2011-03-23 10:39:45 +0100 |
commit | 35838d22a57707952f630eaf9f9e9ab4c6c3cfb0 (patch) | |
tree | 3603e2e56314af40a4b7922e14e52c0bc06f6f9d /inc/auth.php | |
parent | c4bb7947fcb2d4a5e5f8a15d9e3bbec333e44e13 (diff) | |
parent | ee1214abb2c14cf0f86ff6d9a5b49536c6b01e18 (diff) | |
download | rpg-35838d22a57707952f630eaf9f9e9ab4c6c3cfb0.tar.gz rpg-35838d22a57707952f630eaf9f9e9ab4c6c3cfb0.tar.bz2 |
jQuery rewrite branch merged into master branch of whole project
Diffstat (limited to 'inc/auth.php')
-rw-r--r-- | inc/auth.php | 291 |
1 files changed, 90 insertions, 201 deletions
diff --git a/inc/auth.php b/inc/auth.php index a2844a732..53376be34 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -70,6 +70,12 @@ function auth_setup(){ $_REQUEST['http_credentials'] = false; if (!$conf['rememberme']) $_REQUEST['r'] = false; + // handle renamed HTTP_AUTHORIZATION variable (can happen when a fix like + // the one presented at + // http://www.besthostratings.com/articles/http-auth-php-cgi.html is used + // for enabling HTTP authentication with CGI/SuExec) + if(isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) + $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; // streamline HTTP auth credentials (IIS/rewrite -> mod_php) if(isset($_SERVER['HTTP_AUTHORIZATION'])){ list($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']) = @@ -183,7 +189,9 @@ function auth_login($user,$pass,$sticky=false,$silent=false){ if ($auth->checkPass($user,$pass)){ // make logininfo globally available $_SERVER['REMOTE_USER'] = $user; - auth_setCookie($user,PMA_blowfish_encrypt($pass,auth_cookiesalt()),$sticky); + $secret = auth_cookiesalt(); + if(!$sticky) $secret .= session_id; //bind non-sticky to session + auth_setCookie($user,PMA_blowfish_encrypt($pass,$secret),$sticky); return true; }else{ //invalid credentials - log off @@ -194,23 +202,27 @@ function auth_login($user,$pass,$sticky=false,$silent=false){ }else{ // read cookie information list($user,$sticky,$pass) = auth_getCookie(); - // get session info - $session = $_SESSION[DOKU_COOKIE]['auth']; if($user && $pass){ // we got a cookie - see if we can trust it + + // get session info + $session = $_SESSION[DOKU_COOKIE]['auth']; if(isset($session) && $auth->useSessionCache($user) && ($session['time'] >= time()-$conf['auth_security_timeout']) && ($session['user'] == $user) && - ($session['pass'] == $pass) && //still crypted + ($session['pass'] == sha1($pass)) && //still crypted ($session['buid'] == auth_browseruid()) ){ + // he has session, cookie and browser right - let him in $_SERVER['REMOTE_USER'] = $user; $USERINFO = $session['info']; //FIXME move all references to session return true; } // no we don't trust it yet - recheck pass but silent - $pass = PMA_blowfish_decrypt($pass,auth_cookiesalt()); + $secret = auth_cookiesalt(); + if(!$sticky) $secret .= session_id(); //bind non-sticky to session + $pass = PMA_blowfish_decrypt($pass,$secret); return auth_login($user,$pass,$sticky,true); } } @@ -371,63 +383,15 @@ function auth_ismanager($user=null,$groups=null,$adminonly=false){ $user = $_SERVER['REMOTE_USER']; } } - $user = trim($auth->cleanUser($user)); - if($user === '') return false; - if(is_null($groups)) $groups = (array) $USERINFO['grps']; - $groups = array_map(array($auth,'cleanGroup'),$groups); - $user = auth_nameencode($user); - - // check username against superuser and manager - $superusers = explode(',', $conf['superuser']); - $superusers = array_unique($superusers); - $superusers = array_map('trim', $superusers); - $superusers = array_filter($superusers); - // prepare an array containing only true values for array_map call - $alltrue = array_fill(0, count($superusers), true); - $superusers = array_map('auth_nameencode', $superusers, $alltrue); - - // case insensitive? - if(!$auth->isCaseSensitive()){ - $superusers = array_map('utf8_strtolower',$superusers); - $user = utf8_strtolower($user); + if(is_null($groups)){ + $groups = (array) $USERINFO['grps']; } - // check user match - if(in_array($user, $superusers)) return true; - + // check superuser match + if(auth_isMember($conf['superuser'],$user, $groups)) return true; + if($adminonly) return false; // check managers - if(!$adminonly){ - $managers = explode(',', $conf['manager']); - $managers = array_unique($managers); - $managers = array_map('trim', $managers); - $managers = array_filter($managers); - // prepare an array containing only true values for array_map call - $alltrue = array_fill(0, count($managers), true); - $managers = array_map('auth_nameencode', $managers, $alltrue); - if(!$auth->isCaseSensitive()) $managers = array_map('utf8_strtolower',$managers); - if(in_array($user, $managers)) return true; - } - - // check user's groups against superuser and manager - if (!empty($groups)) { - - //prepend groups with @ and nameencode - $cnt = count($groups); - for($i=0; $i<$cnt; $i++){ - $groups[$i] = '@'.auth_nameencode($groups[$i]); - if(!$auth->isCaseSensitive()){ - $groups[$i] = utf8_strtolower($groups[$i]); - } - } - - // check groups against superuser and manager - foreach($superusers as $supu) - if(in_array($supu, $groups)) return true; - if(!$adminonly){ - foreach($managers as $mana) - if(in_array($mana, $groups)) return true; - } - } + if(auth_isMember($conf['manager'],$user, $groups)) return true; return false; } @@ -446,6 +410,52 @@ function auth_isadmin($user=null,$groups=null){ return auth_ismanager($user,$groups,true); } + +/** + * Match a user and his groups against a comma separated list of + * users and groups to determine membership status + * + * Note: all input should NOT be nameencoded. + * + * @param $memberlist string commaseparated list of allowed users and groups + * @param $user string user to match against + * @param $groups array groups the user is member of + * @returns bool true for membership acknowledged + */ +function auth_isMember($memberlist,$user,array $groups){ + global $auth; + if (!$auth) return false; + + // clean user and groups + if(!$auth->isCaseSensitive()){ + $user = utf8_strtolower($user); + $groups = array_map('utf8_strtolower',$groups); + } + $user = $auth->cleanUser($user); + $groups = array_map(array($auth,'cleanGroup'),$groups); + + // extract the memberlist + $members = explode(',',$memberlist); + $members = array_map('trim',$members); + $members = array_unique($members); + $members = array_filter($members); + + // compare cleaned values + foreach($members as $member){ + if(!$auth->isCaseSensitive()) $member = utf8_strtolower($member); + if($member[0] == '@'){ + $member = $auth->cleanGroup(substr($member,1)); + if(in_array($member, $groups)) return true; + }else{ + $member = $auth->cleanUser($member); + if($member == $user) return true; + } + } + + // still here? not a member! + return false; +} + /** * Convinience function for auth_aclcheck() * @@ -536,13 +546,13 @@ function auth_aclcheck($id,$user,$groups){ //still here? do the namespace checks if($ns){ - $path = $ns.':\*'; + $path = $ns.':*'; }else{ - $path = '\*'; //root document + $path = '*'; //root document } do{ - $matches = preg_grep('/^'.$path.'\s+('.$regexp.')\s+/'.$ci,$AUTH_ACL); + $matches = preg_grep('/^'.preg_quote($path,'/').'\s+('.$regexp.')\s+/'.$ci,$AUTH_ACL); if(count($matches)){ foreach($matches as $match){ $match = preg_replace('/#.*$/','',$match); //ignore comments @@ -559,9 +569,9 @@ function auth_aclcheck($id,$user,$groups){ //get next higher namespace $ns = getNS($ns); - if($path != '\*'){ - $path = $ns.':\*'; - if($path == ':\*') $path = '\*'; + if($path != '*'){ + $path = $ns.':*'; + if($path == ':*') $path = '*'; }else{ //we did this already //looks like there is something wrong with the ACL @@ -681,9 +691,8 @@ function register(){ global $conf; global $auth; - if (!$auth) return false; if(!$_POST['save']) return false; - if(!$auth->canDo('addUser')) return false; + if(!actionOK('register')) return false; //clean username $_POST['login'] = trim($auth->cleanUser($_POST['login'])); @@ -759,12 +768,10 @@ function updateprofile() { global $lang; global $auth; - if (!$auth) return false; if(empty($_POST['save'])) return false; if(!checkSecurityToken()) return false; - // should not be able to get here without Profile being possible... - if(!$auth->canDo('Profile')) { + if(!actionOK('profile')) { msg($lang['profna'],-1); return false; } @@ -835,11 +842,7 @@ function act_resendpwd(){ global $conf; global $auth; - if(!actionOK('resendpwd')) return false; - if (!$auth) return false; - - // should not be able to get here without modPass being possible... - if(!$auth->canDo('modPass')) { + if(!actionOK('resendpwd')) { msg($lang['resendna'],-1); return false; } @@ -927,18 +930,6 @@ function act_resendpwd(){ * If the selected method needs a salt and none was given, a random one * is chosen. * - * The following methods are understood: - * - * smd5 - Salted MD5 hashing - * apr1 - Apache salted MD5 hashing - * md5 - Simple MD5 hashing - * sha1 - SHA1 hashing - * ssha - Salted SHA1 hashing - * crypt - Unix crypt - * mysql - MySQL password (old method) - * my411 - MySQL 4.1.1 password - * kmd5 - Salted MD5 hashing as used by UNB - * * @author Andreas Gohr <andi@splitbrain.org> * @return string The crypted password */ @@ -946,128 +937,26 @@ function auth_cryptPassword($clear,$method='',$salt=null){ global $conf; if(empty($method)) $method = $conf['passcrypt']; - //prepare a salt - if(is_null($salt)) $salt = md5(uniqid(rand(), true)); - - switch(strtolower($method)){ - case 'smd5': - if(defined('CRYPT_MD5') && CRYPT_MD5) return crypt($clear,'$1$'.substr($salt,0,8).'$'); - // when crypt can't handle SMD5, falls through to pure PHP implementation - $magic = '1'; - case 'apr1': - //from http://de.php.net/manual/en/function.crypt.php#73619 comment by <mikey_nich at hotmail dot com> - if(!isset($magic)) $magic = 'apr1'; - $salt = substr($salt,0,8); - $len = strlen($clear); - $text = $clear.'$'.$magic.'$'.$salt; - $bin = pack("H32", md5($clear.$salt.$clear)); - for($i = $len; $i > 0; $i -= 16) { - $text .= substr($bin, 0, min(16, $i)); - } - for($i = $len; $i > 0; $i >>= 1) { - $text .= ($i & 1) ? chr(0) : $clear{0}; - } - $bin = pack("H32", md5($text)); - for($i = 0; $i < 1000; $i++) { - $new = ($i & 1) ? $clear : $bin; - if ($i % 3) $new .= $salt; - if ($i % 7) $new .= $clear; - $new .= ($i & 1) ? $bin : $clear; - $bin = pack("H32", md5($new)); - } - $tmp = ''; - for ($i = 0; $i < 5; $i++) { - $k = $i + 6; - $j = $i + 12; - if ($j == 16) $j = 5; - $tmp = $bin[$i].$bin[$k].$bin[$j].$tmp; - } - $tmp = chr(0).chr(0).$bin[11].$tmp; - $tmp = strtr(strrev(substr(base64_encode($tmp), 2)), - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", - "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); - return '$'.$magic.'$'.$salt.'$'.$tmp; - case 'md5': - return md5($clear); - case 'sha1': - return sha1($clear); - case 'ssha': - $salt=substr($salt,0,4); - return '{SSHA}'.base64_encode(pack("H*", sha1($clear.$salt)).$salt); - case 'crypt': - return crypt($clear,substr($salt,0,2)); - case 'mysql': - //from http://www.php.net/mysql comment by <soren at byu dot edu> - $nr=0x50305735; - $nr2=0x12345671; - $add=7; - $charArr = preg_split("//", $clear); - foreach ($charArr as $char) { - if (($char == '') || ($char == ' ') || ($char == '\t')) continue; - $charVal = ord($char); - $nr ^= ((($nr & 63) + $add) * $charVal) + ($nr << 8); - $nr2 += ($nr2 << 8) ^ $nr; - $add += $charVal; - } - return sprintf("%08x%08x", ($nr & 0x7fffffff), ($nr2 & 0x7fffffff)); - case 'my411': - return '*'.sha1(pack("H*", sha1($clear))); - case 'kmd5': - $key = substr($salt, 16, 2); - $hash1 = strtolower(md5($key . md5($clear))); - $hash2 = substr($hash1, 0, 16) . $key . substr($hash1, 16); - return $hash2; - default: - msg("Unsupported crypt method $method",-1); + $pass = new PassHash(); + $call = 'hash_'.$method; + + if(!method_exists($pass,$call)){ + msg("Unsupported crypt method $method",-1); + return false; } + + return $pass->$call($clear,$salt); } /** * Verifies a cleartext password against a crypted hash * - * The method and salt used for the crypted hash is determined automatically - * then the clear text password is crypted using the same method. If both hashs - * match true is is returned else false - * * @author Andreas Gohr <andi@splitbrain.org> * @return bool */ function auth_verifyPassword($clear,$crypt){ - $method=''; - $salt=''; - - //determine the used method and salt - $len = strlen($crypt); - if(preg_match('/^\$1\$([^\$]{0,8})\$/',$crypt,$m)){ - $method = 'smd5'; - $salt = $m[1]; - }elseif(preg_match('/^\$apr1\$([^\$]{0,8})\$/',$crypt,$m)){ - $method = 'apr1'; - $salt = $m[1]; - }elseif(substr($crypt,0,6) == '{SSHA}'){ - $method = 'ssha'; - $salt = substr(base64_decode(substr($crypt, 6)),20); - }elseif($len == 32){ - $method = 'md5'; - }elseif($len == 40){ - $method = 'sha1'; - }elseif($len == 16){ - $method = 'mysql'; - }elseif($len == 41 && $crypt[0] == '*'){ - $method = 'my411'; - }elseif($len == 34){ - $method = 'kmd5'; - $salt = $crypt; - }else{ - $method = 'crypt'; - $salt = substr($crypt,0,2); - } - - //crypt and compare - if(auth_cryptPassword($clear,$method,$salt) === $crypt){ - return true; - } - return false; + $pass = new PassHash(); + return $pass->verify_hash($clear,$crypt); } /** @@ -1095,7 +984,7 @@ function auth_setCookie($user,$pass,$sticky) { } // set session $_SESSION[DOKU_COOKIE]['auth']['user'] = $user; - $_SESSION[DOKU_COOKIE]['auth']['pass'] = $pass; + $_SESSION[DOKU_COOKIE]['auth']['pass'] = sha1($pass); $_SESSION[DOKU_COOKIE]['auth']['buid'] = auth_browseruid(); $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO; $_SESSION[DOKU_COOKIE]['auth']['time'] = time(); @@ -1117,4 +1006,4 @@ function auth_getCookie(){ return array($user,$sticky,$pass); } -//Setup VIM: ex: et ts=2 enc=utf-8 : +//Setup VIM: ex: et ts=2 : |