From 98e31f853f43d94c5bd1d3ab79388c44ce29ce0a Mon Sep 17 00:00:00 2001 From: Klap-in Date: Wed, 15 May 2013 16:51:44 +0200 Subject: Fix wrong config key in deprecated auth message --- inc/auth.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 9f180fc94..3f1f7925b 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -54,8 +54,8 @@ function auth_setup() { } elseif ('auth' . $conf['authtype'] === $plugin) { // matches old auth backends (pre-Weatherwax) $auth = $plugin_controller->load('auth', $plugin); - msg('Your authtype setting is deprecated. You must set $conf[\'authconfig\'] = ' . "auth" . $conf['authtype'] - . ' in your config (see Authentication Backends)',-1,'','',MSG_ADMINS_ONLY); + msg('Your authtype setting is deprecated. You must set $conf[\'authtype\'] = ' . "auth" . $conf['authtype'] + . ' in your configuration (see Authentication Backends)',-1,'','',MSG_ADMINS_ONLY); } } -- cgit v1.2.3 From a91f1103e66d9f28375fc94de05ebbcde454950d Mon Sep 17 00:00:00 2001 From: Anika Henke Date: Mon, 27 May 2013 16:39:54 +0100 Subject: fixed wrong use of quotes in authtype warning message --- inc/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 3f1f7925b..af9f35b38 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -54,7 +54,7 @@ function auth_setup() { } elseif ('auth' . $conf['authtype'] === $plugin) { // matches old auth backends (pre-Weatherwax) $auth = $plugin_controller->load('auth', $plugin); - msg('Your authtype setting is deprecated. You must set $conf[\'authtype\'] = ' . "auth" . $conf['authtype'] + msg('Your authtype setting is deprecated. You must set $conf[\'authtype\'] = "auth' . $conf['authtype'] . '"' . ' in your configuration (see Authentication Backends)',-1,'','',MSG_ADMINS_ONLY); } } -- cgit v1.2.3 From 8fcfc7abfd65ccd920753bee341c6bfdebcecd99 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 31 May 2013 09:29:08 +0200 Subject: use HMAC in password reset token FS#2794 --- inc/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index af9f35b38..dac67bcb7 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -993,7 +993,7 @@ function act_resendpwd() { } // generate auth token - $token = md5(auth_cookiesalt().$user); //secret but user based + $token = PassHash::hmac('md5', $user, auth_cookiesalt()); //secret but user based $tfile = $conf['cachedir'].'/'.$token{0}.'/'.$token.'.pwauth'; $url = wl('', array('do'=> 'resendpwd', 'pwauth'=> $token), true, '&'); -- cgit v1.2.3 From 183a7b8845875e4a6b67e466cfff9f5163da3f17 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 31 May 2013 14:43:31 +0200 Subject: make password reset token completely random No need for HMAC here because there's no length attack vector here. We only care for the existance of the file and each reset request is completely (random) independent from each other. --- inc/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index dac67bcb7..1f8489f03 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -993,7 +993,7 @@ function act_resendpwd() { } // generate auth token - $token = PassHash::hmac('md5', $user, auth_cookiesalt()); //secret but user based + $token = md5(uniqid(mt_rand(), true)); // random secret $tfile = $conf['cachedir'].'/'.$token{0}.'/'.$token.'.pwauth'; $url = wl('', array('do'=> 'resendpwd', 'pwauth'=> $token), true, '&'); -- cgit v1.2.3 From 8a285f7fa7f09ae969e12cf4b7bda0f5123bb0fb Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Sun, 9 Jun 2013 02:29:27 +0200 Subject: AUTH_PASSWORD_GENERATE event added This is needed to replace the password generator by a plugin implementation. Related to PR #166 and FS#2147 --- inc/auth.php | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 1f8489f03..82a6b46cd 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -678,27 +678,40 @@ function auth_nameencode($name, $skip_group = false) { /** * Create a pronouncable password * + * The $foruser variable might be used by plugins to run additional password + * policy checks, but is not used by the default implementation + * * @author Andreas Gohr * @link http://www.phpbuilder.com/annotate/message.php3?id=1014451 + * @triggers AUTH_PASSWORD_GENERATE * + * @param string $foruser username for which the password is generated * @return string pronouncable password */ -function auth_pwgen() { - $pw = ''; - $c = 'bcdfghjklmnprstvwz'; //consonants except hard to speak ones - $v = 'aeiou'; //vowels - $a = $c.$v; //both - - //use two syllables... - for($i = 0; $i < 2; $i++) { - $pw .= $c[rand(0, strlen($c) - 1)]; - $pw .= $v[rand(0, strlen($v) - 1)]; - $pw .= $a[rand(0, strlen($a) - 1)]; +function auth_pwgen($foruser='') { + $data = array( + 'password' = '', + 'foruser' = $foruser + ); + + $evt = new Doku_Event('AUTH_PASSWORD_GENERATE', $data); + if($evt->advise_before(true)) { + $c = 'bcdfghjklmnprstvwz'; //consonants except hard to speak ones + $v = 'aeiou'; //vowels + $a = $c.$v; //both + + //use two syllables... + for($i = 0; $i < 2; $i++) { + $data['password'] .= $c[rand(0, strlen($c) - 1)]; + $data['password'] .= $v[rand(0, strlen($v) - 1)]; + $data['password'] .= $a[rand(0, strlen($a) - 1)]; + } + //... and add a nice number + $data['password'] .= rand(10, 99); } - //... and add a nice number - $pw .= rand(10, 99); + $evt->advise_after(); - return $pw; + return $data['password']; } /** @@ -765,7 +778,7 @@ function register() { } if($conf['autopasswd']) { - $pass = auth_pwgen(); // automatically generate password + $pass = auth_pwgen($login); // automatically generate password } elseif(empty($pass) || empty($passchk)) { msg($lang['regmissing'], -1); // complain about missing passwords return false; @@ -958,7 +971,7 @@ function act_resendpwd() { } else { // autogenerate the password and send by mail - $pass = auth_pwgen(); + $pass = auth_pwgen($user); if(!$auth->triggerUserMod('modify', array($user, array('pass' => $pass)))) { msg('error modifying user data', -1); return false; -- cgit v1.2.3 From d628dcf33c131b3ede5c78b4550c2ba23124f432 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Sun, 9 Jun 2013 02:51:19 +0200 Subject: fixed syntax fuckup --- inc/auth.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 82a6b46cd..db6245e20 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -690,8 +690,8 @@ function auth_nameencode($name, $skip_group = false) { */ function auth_pwgen($foruser='') { $data = array( - 'password' = '', - 'foruser' = $foruser + 'password' => '', + 'foruser' => $foruser ); $evt = new Doku_Event('AUTH_PASSWORD_GENERATE', $data); -- cgit v1.2.3 From 987c8d26bbfec753f50b50e8f16e0f5579a93e11 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Fri, 14 Jun 2013 14:49:39 +0200 Subject: Increased strength of auto generated passwords a bit If you want better random initialization and more control over the password strength install the passpolicy plugin. --- inc/auth.php | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index db6245e20..6107645cd 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -681,14 +681,14 @@ function auth_nameencode($name, $skip_group = false) { * The $foruser variable might be used by plugins to run additional password * policy checks, but is not used by the default implementation * - * @author Andreas Gohr - * @link http://www.phpbuilder.com/annotate/message.php3?id=1014451 + * @author Andreas Gohr + * @link http://www.phpbuilder.com/annotate/message.php3?id=1014451 * @triggers AUTH_PASSWORD_GENERATE * * @param string $foruser username for which the password is generated * @return string pronouncable password */ -function auth_pwgen($foruser='') { +function auth_pwgen($foruser = '') { $data = array( 'password' => '', 'foruser' => $foruser @@ -696,18 +696,19 @@ function auth_pwgen($foruser='') { $evt = new Doku_Event('AUTH_PASSWORD_GENERATE', $data); if($evt->advise_before(true)) { - $c = 'bcdfghjklmnprstvwz'; //consonants except hard to speak ones - $v = 'aeiou'; //vowels - $a = $c.$v; //both - - //use two syllables... - for($i = 0; $i < 2; $i++) { - $data['password'] .= $c[rand(0, strlen($c) - 1)]; - $data['password'] .= $v[rand(0, strlen($v) - 1)]; - $data['password'] .= $a[rand(0, strlen($a) - 1)]; + $c = 'bcdfghjklmnprstvwz'; //consonants except hard to speak ones + $v = 'aeiou'; //vowels + $a = $c.$v; //both + $s = '!$%&?+*~#-_:.;,'; // specials + + //use thre syllables... + for($i = 0; $i < 3; $i++) { + $data['password'] .= $c[mt_rand(0, strlen($c) - 1)]; + $data['password'] .= $v[mt_rand(0, strlen($v) - 1)]; + $data['password'] .= $a[mt_rand(0, strlen($a) - 1)]; } - //... and add a nice number - $data['password'] .= rand(10, 99); + //... and add a nice number and special + $data['password'] .= mt_rand(10, 99).$s[mt_rand(0, strlen($s) - 1)]; } $evt->advise_after(); -- cgit v1.2.3 From ea2272c40a77ba38305773f8f3e3172bb71e9f49 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Sun, 16 Jun 2013 21:57:42 +0200 Subject: removed tabs --- inc/auth.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 6107645cd..47b29eff7 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -59,18 +59,18 @@ function auth_setup() { } } - if(!isset($auth) || !$auth){ + if(!isset($auth) || !$auth){ msg($lang['authtempfail'], -1); return false; } if ($auth->success == false) { - // degrade to unauthenticated user - unset($auth); - auth_logoff(); - msg($lang['authtempfail'], -1); + // degrade to unauthenticated user + unset($auth); + auth_logoff(); + msg($lang['authtempfail'], -1); return false; - } + } // do the login either by cookie or provided credentials XXX $INPUT->set('http_credentials', false); -- cgit v1.2.3 From 483b6238a3599595a678f995b2c7c9e9f07a7ce7 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Tue, 30 Jul 2013 18:46:02 +0200 Subject: Add truly random numbers and use them in places where randomness matters --- inc/auth.php | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 102 insertions(+), 6 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 537d44c01..ace98f51f 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -294,7 +294,7 @@ function auth_validateToken($token) { * @return string The auth token */ function auth_createToken() { - $token = md5(mt_rand()); + $token = md5(auth_randombytes(16)); @session_start(); // reopen the session if needed $_SESSION[DOKU_COOKIE]['auth']['token'] = $token; session_write_close(); @@ -349,6 +349,102 @@ function auth_cookiesalt($addsession = false) { return $salt; } +/** + * Return truly (pseudo) random bytes if available, otherwise fall back to mt_rand + * + * @author Mark Seecof + * @author Michael Hamann + * @link http://www.php.net/manual/de/function.mt-rand.php#83655 + * @param int $length number of bytes to get + * @throws Exception when no usable random generator is found + * @return string binary random strings + */ +function auth_randombytes($length) { + $strong = false; + $rbytes = false; + + if (function_exists('openssl_random_pseudo_bytes') + && (version_compare(PHP_VERSION, '5.3.4') >= 0 + || strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') + ) { + $rbytes = openssl_random_pseudo_bytes($length, $strong); + } + + if (!$strong && function_exists('mcrypt_create_iv') + && (version_compare(PHP_VERSION, '5.3.7') >= 0 + || strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') + ) { + $rbytes = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); + if ($rbytes !== false && strlen($rbytes) === $length) { + $strong = true; + } + } + + + // If no strong randoms available, try OS the specific ways + if(!$strong) { + // Unix/Linux platform + $fp = @fopen('/dev/urandom', 'rb'); + if($fp !== false) { + $rbytes = fread($fp, $length); + fclose($fp); + } + + // MS-Windows platform + if(class_exists('COM')) { + // http://msdn.microsoft.com/en-us/library/aa388176(VS.85).aspx + try { + $CAPI_Util = new COM('CAPICOM.Utilities.1'); + $rbytes = $CAPI_Util->GetRandom($length, 0); + + // if we ask for binary data PHP munges it, so we + // request base64 return value. + if($rbytes) $rbytes = base64_decode($rbytes); + } catch(Exception $ex) { + // fail + } + } + } + if(strlen($rbytes) < $length) $rbytes = false; + + // still no random bytes available - fall back to mt_rand() + if($rbytes === false) { + $rbytes = ''; + for ($i = 0; $i < $length; ++$i) { + $rbytes .= chr(mt_rand(0, 255)); + } + } + + return $rbytes; +} + +/** + * Random number generator using the best available source + * + * @author Michael Samuel + * @author Michael Hamann + * @param int $min + * @param int $max + * @return int + */ +function auth_random($min, $max) { + $abs_max = $max - $min; + + $nbits = 0; + for ($n = $abs_max; $n > 0; $n >>= 1) { + ++$nbits; + } + + $mask = (1 << $nbits) - 1; + do { + $bytes = auth_randombytes(PHP_INT_SIZE); + $integers = unpack('Inum', $bytes); + $integer = $integers["num"] & $mask; + } while ($integer > $abs_max); + + return $min + $integer; +} + /** * Log out the current user * @@ -703,12 +799,12 @@ function auth_pwgen($foruser = '') { //use thre syllables... for($i = 0; $i < 3; $i++) { - $data['password'] .= $c[mt_rand(0, strlen($c) - 1)]; - $data['password'] .= $v[mt_rand(0, strlen($v) - 1)]; - $data['password'] .= $a[mt_rand(0, strlen($a) - 1)]; + $data['password'] .= $c[auth_random(0, strlen($c) - 1)]; + $data['password'] .= $v[auth_random(0, strlen($v) - 1)]; + $data['password'] .= $a[auth_random(0, strlen($a) - 1)]; } //... and add a nice number and special - $data['password'] .= mt_rand(10, 99).$s[mt_rand(0, strlen($s) - 1)]; + $data['password'] .= auth_random(10, 99).$s[auth_random(0, strlen($s) - 1)]; } $evt->advise_after(); @@ -1007,7 +1103,7 @@ function act_resendpwd() { } // generate auth token - $token = md5(uniqid(mt_rand(), true)); // random secret + $token = md5(auth_randombytes(16)); // random secret $tfile = $conf['cachedir'].'/'.$token{0}.'/'.$token.'.pwauth'; $url = wl('', array('do'=> 'resendpwd', 'pwauth'=> $token), true, '&'); -- cgit v1.2.3 From 27058a053ea6ffa90fee7aaf26f81ab1109d6df3 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Tue, 30 Jul 2013 13:40:59 +0200 Subject: Fix and add type declarations for the auth system --- inc/auth.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 47b29eff7..537d44c01 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -40,7 +40,7 @@ function auth_setup() { global $INPUT; global $AUTH_ACL; global $lang; - global $config_cascade; + /* @var Doku_Plugin_Controller $plugin_controller */ global $plugin_controller; $AUTH_ACL = array(); @@ -207,7 +207,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { global $USERINFO; global $conf; global $lang; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; $sticky ? $sticky = true : $sticky = false; //sanity check @@ -361,7 +361,7 @@ function auth_cookiesalt($addsession = false) { function auth_logoff($keepbc = false) { global $conf; global $USERINFO; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; // make sure the session is writable (it usually is) @@ -407,7 +407,7 @@ function auth_logoff($keepbc = false) { function auth_ismanager($user = null, $groups = null, $adminonly = false) { global $conf; global $USERINFO; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; if(!$auth) return false; @@ -460,7 +460,7 @@ function auth_isadmin($user = null, $groups = null) { * @return bool true for membership acknowledged */ function auth_isMember($memberlist, $user, array $groups) { - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; if(!$auth) return false; @@ -526,7 +526,7 @@ function auth_quickaclcheck($id) { function auth_aclcheck($id, $user, $groups) { global $conf; global $AUTH_ACL; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; // if no ACL is used always return upload rights @@ -725,7 +725,7 @@ function auth_pwgen($foruser = '') { */ function auth_sendPassword($user, $password) { global $lang; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; if(!$auth) return false; @@ -759,7 +759,7 @@ function auth_sendPassword($user, $password) { function register() { global $lang; global $conf; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; global $INPUT; @@ -828,7 +828,7 @@ function register() { function updateprofile() { global $conf; global $lang; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; /* @var Input $INPUT */ global $INPUT; @@ -918,7 +918,7 @@ function updateprofile() { function act_resendpwd() { global $lang; global $conf; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; /* @var Input $INPUT */ global $INPUT; @@ -1084,7 +1084,7 @@ function auth_verifyPassword($clear, $crypt) { */ function auth_setCookie($user, $pass, $sticky) { global $conf; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; global $USERINFO; -- cgit v1.2.3 From 30d544a4c371bf69023e4d9958bc2b00d84387d9 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Tue, 30 Jul 2013 18:47:58 +0200 Subject: Use a new, truly random secret for cookie encryption --- inc/auth.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index ace98f51f..a1da971ae 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -219,7 +219,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { if($auth->checkPass($user, $pass)) { // make logininfo globally available $_SERVER['REMOTE_USER'] = $user; - $secret = auth_cookiesalt(!$sticky); //bind non-sticky to session + $secret = auth_cookiesalt(!$sticky, true); //bind non-sticky to session auth_setCookie($user, PMA_blowfish_encrypt($pass, $secret), $sticky); return true; } else { @@ -250,7 +250,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { return true; } // no we don't trust it yet - recheck pass but silent - $secret = auth_cookiesalt(!$sticky); //bind non-sticky to session + $secret = auth_cookiesalt(!$sticky, true); //bind non-sticky to session $pass = PMA_blowfish_decrypt($pass, $secret); return auth_login($user, $pass, $sticky, true); } @@ -333,14 +333,18 @@ function auth_browseruid() { * * @author Andreas Gohr * @param bool $addsession if true, the sessionid is added to the salt + * @param bool $secure if security is more important than keeping the old value * @return string */ -function auth_cookiesalt($addsession = false) { +function auth_cookiesalt($addsession = false, $secure = false) { global $conf; $file = $conf['metadir'].'/_htcookiesalt'; + if ($secure || !file_exists($file)) { + $file = $conf['metadir'].'/_htcookiesalt2'; + } $salt = io_readFile($file); if(empty($salt)) { - $salt = uniqid(rand(), true); + $salt = bin2hex(auth_randombytes(64)); io_saveFile($file, $salt); } if($addsession) { @@ -988,7 +992,7 @@ function updateprofile() { // update cookie and session with the changed data if($changes['pass']) { list( /*user*/, $sticky, /*pass*/) = auth_getCookie(); - $pass = PMA_blowfish_encrypt($changes['pass'], auth_cookiesalt(!$sticky)); + $pass = PMA_blowfish_encrypt($changes['pass'], auth_cookiesalt(!$sticky, true)); auth_setCookie($_SERVER['REMOTE_USER'], $pass, (bool) $sticky); } return true; -- cgit v1.2.3 From 04369c3eae728e14962c41d1ab259f9e7ed99144 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Tue, 30 Jul 2013 18:50:28 +0200 Subject: Add AES from phpseclib and use it for cookie encryption This replaces the deprecated and broken Blowfish implementation that has previously been used and should provide a lot more security. --- inc/auth.php | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index a1da971ae..f02bfebca 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -220,7 +220,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { // make logininfo globally available $_SERVER['REMOTE_USER'] = $user; $secret = auth_cookiesalt(!$sticky, true); //bind non-sticky to session - auth_setCookie($user, PMA_blowfish_encrypt($pass, $secret), $sticky); + auth_setCookie($user, auth_encrypt($pass, $secret), $sticky); return true; } else { //invalid credentials - log off @@ -251,7 +251,7 @@ function auth_login($user, $pass, $sticky = false, $silent = false) { } // no we don't trust it yet - recheck pass but silent $secret = auth_cookiesalt(!$sticky, true); //bind non-sticky to session - $pass = PMA_blowfish_decrypt($pass, $secret); + $pass = auth_decrypt($pass, $secret); return auth_login($user, $pass, $sticky, true); } } @@ -449,6 +449,40 @@ function auth_random($min, $max) { return $min + $integer; } +/** + * Encrypt data using the given secret using AES + * + * The mode is CBC with a random initialization vector, the key is derived + * using pbkdf2. + * + * @param string $data The data that shall be encrypted + * @param string $secret The secret/password that shall be used + * @return string The ciphertext + */ +function auth_encrypt($data, $secret) { + $iv = auth_randombytes(16); + $cipher = new Crypt_AES(); + $cipher->setPassword($secret); + + return $cipher->encrypt($iv.$data); +} + +/** + * Decrypt the given AES ciphertext + * + * The mode is CBC, the key is derived using pbkdf2 + * + * @param string $ciphertext The encrypted data + * @param string $secret The secret/password that shall be used + * @return string The decrypted data + */ +function auth_decrypt($ciphertext, $secret) { + $cipher = new Crypt_AES(); + $cipher->setPassword($secret); + + return substr($cipher->decrypt($ciphertext), 16); +} + /** * Log out the current user * @@ -992,7 +1026,7 @@ function updateprofile() { // update cookie and session with the changed data if($changes['pass']) { list( /*user*/, $sticky, /*pass*/) = auth_getCookie(); - $pass = PMA_blowfish_encrypt($changes['pass'], auth_cookiesalt(!$sticky, true)); + $pass = auth_encrypt($changes['pass'], auth_cookiesalt(!$sticky, true)); auth_setCookie($_SERVER['REMOTE_USER'], $pass, (bool) $sticky); } return true; -- cgit v1.2.3 From 8269996a43469c1ce5295a22248ad9a9ab34efc8 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 31 Jul 2013 11:56:16 +0200 Subject: auth_random: remove exception comment as there is no exception --- inc/auth.php | 1 - 1 file changed, 1 deletion(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index f02bfebca..227ee80fd 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -360,7 +360,6 @@ function auth_cookiesalt($addsession = false, $secure = false) { * @author Michael Hamann * @link http://www.php.net/manual/de/function.mt-rand.php#83655 * @param int $length number of bytes to get - * @throws Exception when no usable random generator is found * @return string binary random strings */ function auth_randombytes($length) { -- cgit v1.2.3 From 7b650cef79bb603087a8ef43b22a1f7c3d86b7ef Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Wed, 31 Jul 2013 11:56:58 +0200 Subject: auth_en/decrypt: Add explanation and more efficient decryption Added an explanation that what we do is like normal CBC but that we additionally encrypt the IV which is actually suggested by the NIST for non-random (but unique) IVs. In the decryption process it's not necessary to decrypt the IV, this should save some time. --- inc/auth.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 227ee80fd..96b80e19e 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -459,10 +459,16 @@ function auth_random($min, $max) { * @return string The ciphertext */ function auth_encrypt($data, $secret) { - $iv = auth_randombytes(16); + $iv = auth_randombytes(16); $cipher = new Crypt_AES(); $cipher->setPassword($secret); + /* + this uses the encrypted IV as IV as suggested in + http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, Appendix C + for unique but necessarily random IVs. The resulting ciphertext is + compatible to ciphertext that was created using a "normal" IV. + */ return $cipher->encrypt($iv.$data); } @@ -476,10 +482,12 @@ function auth_encrypt($data, $secret) { * @return string The decrypted data */ function auth_decrypt($ciphertext, $secret) { + $iv = substr($ciphertext, 0, 16); $cipher = new Crypt_AES(); $cipher->setPassword($secret); + $cipher->setIV($iv); - return substr($cipher->decrypt($ciphertext), 16); + return $cipher->decrypt(substr($ciphertext, 16)); } /** -- cgit v1.2.3 From 2a7abf2d7fee6a2d6418e5ad4b79e37e6049bd92 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 18:14:26 +0200 Subject: FS#2751 - self deletion of user account --- inc/auth.php | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 537d44c01..75ba9a9ba 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -901,6 +901,45 @@ function updateprofile() { return false; } +function auth_deleteprofile(){ + global $conf; + global $lang; + /* @var auth_basic $auth */ + global $auth; + /* @var Input $INPUT */ + global $INPUT; + + if(!$INPUT->post->bool('delete')) return false; + if(!checkSecurityToken()) return false; + + // action prevented or auth module disallows + if(!actionOK('profile_delete') || !$auth->canDo('delUser')) { + msg($lang['profnodelete'], -1); + return false; + } + + if(!$INPUT->post->bool('confirm_delete')){ + msg($lang['profconfdeletemissing'], -1); + return false; + } + + if($conf['profileconfirm']) { + if(!$auth->checkPass($_SERVER['REMOTE_USER'], $INPUT->post->str('oldpass'))) { + msg($lang['badpassconfirm'], -1); + return false; + } + } + + $deleted[] = $_SERVER['REMOTE_USER']; + if($result = $auth->triggerUserMod('delete', array($deleted))) { + // force and immediate logout including removing the sticky cookie + auth_logoff(); + return true; + } + + return false; +} + /** * Send a new password * -- cgit v1.2.3 From 71422fc898ea54876cd58c3bf5c4c0d9de032b52 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 31 Jul 2013 18:41:02 +0200 Subject: Change error message shown for incorrect current password on update profile form. The current message confusingly mentions bad 'username' when username is not involved. The new message is the same as that introduced for an incorrect current password on the self delete profile form (FS#2751) --- inc/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 537d44c01..29ef46d03 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -883,7 +883,7 @@ function updateprofile() { if($conf['profileconfirm']) { if(!$auth->checkPass($_SERVER['REMOTE_USER'], $INPUT->post->str('oldpass'))) { - msg($lang['badlogin'], -1); + msg($lang['badpassconfirm'], -1); return false; } } -- cgit v1.2.3 From 73012efd9607b31a4ddd7856761cd1dac5774eef Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Fri, 2 Aug 2013 17:57:07 +0200 Subject: coding corrections. correct type hint, remove unused variable assignment --- inc/auth.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 75ba9a9ba..a9d53779c 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -904,7 +904,7 @@ function updateprofile() { function auth_deleteprofile(){ global $conf; global $lang; - /* @var auth_basic $auth */ + /* @var DokuWiki_Auth_Plugin $auth */ global $auth; /* @var Input $INPUT */ global $INPUT; @@ -931,7 +931,7 @@ function auth_deleteprofile(){ } $deleted[] = $_SERVER['REMOTE_USER']; - if($result = $auth->triggerUserMod('delete', array($deleted))) { + if($auth->triggerUserMod('delete', array($deleted))) { // force and immediate logout including removing the sticky cookie auth_logoff(); return true; -- cgit v1.2.3 From ad3d68d738ab9057164c5d13a1836bd2791ab2f7 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Sat, 3 Aug 2013 14:04:06 +0200 Subject: Fix a couple of bugs in ACL substitution mechanism - %GROUP% & %USER% can now both be used in the same rule, e.g. %GROUP%:%USER% 2 - rules with tokens will be skipped when the user is not logged in previously %USER% was attempted --- inc/auth.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index be6b7ebbe..1c0bf5b4f 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -136,22 +136,30 @@ function auth_loadACL() { $acl = file($config_cascade['acl']['default']); - //support user wildcard $out = array(); foreach($acl as $line) { $line = trim($line); if($line{0} == '#') continue; list($id,$rest) = preg_split('/\s+/',$line,2); + // substitue user wildcard first (its 1:1) + if(strstr($line, '%USER%')){ + // if user is not logged in, this ACL line is meaningless - skip it + if (!isset($_SERVER['REMOTE_USER'])) continue; + + $id = str_replace('%USER%',cleanID($_SERVER['REMOTE_USER']),$id); + $rest = str_replace('%USER%',auth_nameencode($_SERVER['REMOTE_USER']),$rest); + } + + // substitute group wildcard (its 1:m) if(strstr($line, '%GROUP%')){ + // if user is not logged in, grps is empty, no output will be added (i.e. skipped) foreach((array) $USERINFO['grps'] as $grp){ $nid = str_replace('%GROUP%',cleanID($grp),$id); $nrest = str_replace('%GROUP%','@'.auth_nameencode($grp),$rest); $out[] = "$nid\t$nrest"; } } else { - $id = str_replace('%USER%',cleanID($_SERVER['REMOTE_USER']),$id); - $rest = str_replace('%USER%',auth_nameencode($_SERVER['REMOTE_USER']),$rest); $out[] = "$id\t$rest"; } } -- cgit v1.2.3 From b8983d3a45d16afc81d527fc2616f8c43bbf2c87 Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Tue, 20 Aug 2013 21:18:30 -0700 Subject: Fix CodeSniffer violations Remove whitespace from end of lines to reduce the number of CodeSniffer violations. --- inc/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 1c0bf5b4f..696456cfc 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -1061,7 +1061,7 @@ function auth_deleteprofile(){ if(!$INPUT->post->bool('delete')) return false; if(!checkSecurityToken()) return false; - // action prevented or auth module disallows + // action prevented or auth module disallows if(!actionOK('profile_delete') || !$auth->canDo('delUser')) { msg($lang['profnodelete'], -1); return false; -- cgit v1.2.3 From 7ef8e99fe605c5da36ab6b5d317b22fcd17f665b Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Thu, 22 Aug 2013 01:01:41 -0700 Subject: Fix CodeSniffer violations Change indentation to ensure code confirms to CodeSniffer rules. --- inc/auth.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 696456cfc..8be270bfc 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -48,15 +48,15 @@ function auth_setup() { // try to load auth backend from plugins foreach ($plugin_controller->getList('auth') as $plugin) { - if ($conf['authtype'] === $plugin) { - $auth = $plugin_controller->load('auth', $plugin); - break; - } elseif ('auth' . $conf['authtype'] === $plugin) { - // matches old auth backends (pre-Weatherwax) - $auth = $plugin_controller->load('auth', $plugin); - msg('Your authtype setting is deprecated. You must set $conf[\'authtype\'] = "auth' . $conf['authtype'] . '"' - . ' in your configuration (see Authentication Backends)',-1,'','',MSG_ADMINS_ONLY); - } + if ($conf['authtype'] === $plugin) { + $auth = $plugin_controller->load('auth', $plugin); + break; + } elseif ('auth' . $conf['authtype'] === $plugin) { + // matches old auth backends (pre-Weatherwax) + $auth = $plugin_controller->load('auth', $plugin); + msg('Your authtype setting is deprecated. You must set $conf[\'authtype\'] = "auth' . $conf['authtype'] . '"' + . ' in your configuration (see Authentication Backends)',-1,'','',MSG_ADMINS_ONLY); + } } if(!isset($auth) || !$auth){ @@ -65,10 +65,10 @@ function auth_setup() { } if ($auth->success == false) { - // degrade to unauthenticated user - unset($auth); - auth_logoff(); - msg($lang['authtempfail'], -1); + // degrade to unauthenticated user + unset($auth); + auth_logoff(); + msg($lang['authtempfail'], -1); return false; } -- cgit v1.2.3 From 2f7a0e94cadfbc1ece3bd1d3ff23483b845cd420 Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Tue, 10 Sep 2013 22:17:43 -0700 Subject: Fix CodeSniffer whitespace violoations Removed extraneous whitespace to eliminate errors reported by the Squiz.WhiteSpace.SuperfluousWhitespace sniff. --- inc/auth.php | 1 - 1 file changed, 1 deletion(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 8be270bfc..36fc7d086 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -391,7 +391,6 @@ function auth_randombytes($length) { } } - // If no strong randoms available, try OS the specific ways if(!$strong) { // Unix/Linux platform -- cgit v1.2.3 From 30f6faf00624251f7ac69fc86e9f3c5a01ad5d90 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 16 Oct 2013 15:22:58 +0100 Subject: update for deprecated '/e' flag in preg_replace (php 5.5) --- inc/auth.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 36fc7d086..ac079c574 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -808,14 +808,14 @@ function auth_nameencode($name, $skip_group = false) { if(!isset($cache[$name][$skip_group])) { if($skip_group && $name{0} == '@') { - $cache[$name][$skip_group] = '@'.preg_replace( - '/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f])/e', - "'%'.dechex(ord(substr('\\1',-1)))", substr($name, 1) + $cache[$name][$skip_group] = '@'.preg_replace_callback( + '/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f])/', + 'auth_nameencode_callback', substr($name, 1) ); } else { - $cache[$name][$skip_group] = preg_replace( - '/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f])/e', - "'%'.dechex(ord(substr('\\1',-1)))", $name + $cache[$name][$skip_group] = preg_replace_callback( + '/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f])/', + 'auth_nameencode_callback', $name ); } } @@ -823,6 +823,10 @@ function auth_nameencode($name, $skip_group = false) { return $cache[$name][$skip_group]; } +function auth_nameencode_callback($matches) { + return '%'.dechex(ord(substr($matches[1],-1))); +} + /** * Create a pronouncable password * -- cgit v1.2.3 From 443e135d59e9d227eec818dabf9ee64d7a73d474 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 16 Oct 2013 22:04:01 +0100 Subject: replace boolean conditional checks on possibly uninitialized vars with \!empty/empty/isset as appropriate --- inc/auth.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index ac079c574..0d42c8673 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -139,10 +139,10 @@ function auth_loadACL() { $out = array(); foreach($acl as $line) { $line = trim($line); - if($line{0} == '#') continue; + if(empty($line) || ($line{0} == '#')) continue; // skip blank lines & comments list($id,$rest) = preg_split('/\s+/',$line,2); - // substitue user wildcard first (its 1:1) + // substitute user wildcard first (its 1:1) if(strstr($line, '%USER%')){ // if user is not logged in, this ACL line is meaningless - skip it if (!isset($_SERVER['REMOTE_USER'])) continue; -- cgit v1.2.3 From 21c3090a76ebde3117ae1dcb9f503fe3a61c1c02 Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Mon, 21 Oct 2013 23:32:15 +0100 Subject: replace \s, \S with [ \t], [^ \t] in regexs used with acls --- inc/auth.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'inc/auth.php') diff --git a/inc/auth.php b/inc/auth.php index 0d42c8673..b793f5d12 100644 --- a/inc/auth.php +++ b/inc/auth.php @@ -140,7 +140,7 @@ function auth_loadACL() { foreach($acl as $line) { $line = trim($line); if(empty($line) || ($line{0} == '#')) continue; // skip blank lines & comments - list($id,$rest) = preg_split('/\s+/',$line,2); + list($id,$rest) = preg_split('/[ \t]+/',$line,2); // substitute user wildcard first (its 1:1) if(strstr($line, '%USER%')){ @@ -716,11 +716,11 @@ function auth_aclcheck($id, $user, $groups) { } //check exact match first - $matches = preg_grep('/^'.preg_quote($id, '/').'\s+(\S+)\s+/u', $AUTH_ACL); + $matches = preg_grep('/^'.preg_quote($id, '/').'[ \t]+([^ \t]+)[ \t]+/', $AUTH_ACL); if(count($matches)) { foreach($matches as $match) { $match = preg_replace('/#.*$/', '', $match); //ignore comments - $acl = preg_split('/\s+/', $match); + $acl = preg_split('/[ \t]+/', $match); if(!$auth->isCaseSensitive() && $acl[1] !== '@ALL') { $acl[1] = utf8_strtolower($acl[1]); } @@ -746,11 +746,11 @@ function auth_aclcheck($id, $user, $groups) { } do { - $matches = preg_grep('/^'.preg_quote($path, '/').'\s+(\S+)\s+/u', $AUTH_ACL); + $matches = preg_grep('/^'.preg_quote($path, '/').'[ \t]+([^ \t]+)[ \t]+/', $AUTH_ACL); if(count($matches)) { foreach($matches as $match) { $match = preg_replace('/#.*$/', '', $match); //ignore comments - $acl = preg_split('/\s+/', $match); + $acl = preg_split('/[ \t]+/', $match); if(!$auth->isCaseSensitive() && $acl[1] !== '@ALL') { $acl[1] = utf8_strtolower($acl[1]); } -- cgit v1.2.3