diff --git a/www/admin/class_test.php b/www/admin/class_test.php index db0d64c2..ee50ac4d 100644 --- a/www/admin/class_test.php +++ b/www/admin/class_test.php @@ -1,4 +1,5 @@ verifyCryptString($this->password, $res['password']) ) { // check passwword as crypted, $2a$ or $2y$ is blowfish start, $1$ is MD5 start, $\w{12} is standard DES + // this is only for OLD $07$ password $this->login_error = 1011; + } elseif (preg_match("/^\\$2y\\$/", $res['password']) && + !preg_match("/\\$07\\$/", $res['password']) && + !$this->passwordVerify($this->password, $res['password']) + ) { + // this is the new password hash methid, is only $2y$ + $this->login_error = 1013; } elseif (!preg_match("/^\\$2(a|y)\\$/", $res['password']) && !preg_match("/^\\$1\\$/", $res['password']) && !preg_match("/^\\$[0-9A-Za-z.]{12}$/", $res['password']) && @@ -306,6 +315,14 @@ class Login extends \CoreLibs\DB\IO // check old plain password, non case sensitive $this->login_error = 1012; } else { + // check if the current password is an invalid hash and do a rehash and set password + // $this->debug('LOGIN', 'Hash: '.$res['password'].' -> VERIFY: '.(password_verify($this->password, $res['password']) ? 'OK' : 'FAIL').' => HASH: '.(password_needs_rehash($res['password'], PASSWORD_DEFAULT, $this->password_options) ? 'NEW NEEDED' : 'OK')); + if (password_needs_rehash($res['password'], PASSWORD_DEFAULT, $this->password_options)) { + $new_hash = password_hash($this->password, PASSWORD_DEFAULT, $this->password_options); + // update password hash to new one now + $q = "UPDATE edit_user SET password = '".$this->dbEscapeString($new_hash)."' WHERE edit_user_id = ".$res['edit_user_id']; + $this->dbExec($q); + } // normal user processing // set class var and session var $_SESSION["EUID"] = $this->euid = $res["edit_user_id"]; @@ -548,6 +565,7 @@ class Login extends \CoreLibs\DB\IO $this->acl['admin'] = 1; $this->acl['base'] = 100; } else { + $this->acl['admin'] = 0; // now go throw the flow and set the correct ACL // user > page > group // group ACL 0 @@ -618,7 +636,7 @@ class Login extends \CoreLibs\DB\IO // set the full acl list too $this->acl['acl_list'] = $_SESSION['DEFAULT_ACL_LIST']; // debug -// $this->debug('ACL', $this->print_ar($this->acl)); + // $this->debug('ACL', $this->print_ar($this->acl)); } // METHOD: loginCheckEditAccess @@ -785,7 +803,7 @@ class Login extends \CoreLibs\DB\IO $this->writeLog($event, '', $this->login_error, $username, $password); } // write log under certain settings // now close DB connection -// $this->error_msg = $this->_login(); + // $this->error_msg = $this->_login(); if (!$this->permission_okay) { return false; } else { @@ -816,6 +834,7 @@ class Login extends \CoreLibs\DB\IO "1010" => $this->l->__("Fatal Error: Login Failed - Wrong Username or Password"), // user not found "1011" => $this->l->__("Fatal Error: Login Failed - Wrong Username or Password"), // blowfish password wrong "1012" => $this->l->__("Fatal Error: Login Failed - Wrong Username or Password"), // fallback md5 password wrong + "1013" => $this->l->__("Fatal Error: Login Failed - Wrong Username or Password"), // new password_hash wrong "102" => $this->l->__("Fatal Error: Login Failed - Please enter username and password"), "103" => $this->l->__("Fatal Error: You do not have the rights to access this Page"), "104" => $this->l->__("Fatal Error: Login Failed - User not enabled"), diff --git a/www/lib/CoreLibs/Basic.inc b/www/lib/CoreLibs/Basic.inc index f78fd4cc..2973a943 100644 --- a/www/lib/CoreLibs/Basic.inc +++ b/www/lib/CoreLibs/Basic.inc @@ -148,12 +148,13 @@ class Basic // error char for the char conver public $mbErrorChar; - // crypt saslt prefix + // [!!! DEPRECATED !!!] crypt saslt prefix public $cryptSaltPrefix = ''; public $cryptSaltSuffix = ''; public $cryptIterationCost = 7; // this is for staying backwards compatible with the old ones public $cryptSaltSize = 22; // default 22 chars for blowfish, 2 for STD DES, 8 for MD5, - + // new better password management + protected $password_options = array (); // session name private $session_name = ''; private $session_id = ''; @@ -340,8 +341,10 @@ class Basic $this->session_id = session_id(); } - // init crypt settings + // [!!! DEPRECATED !!!] init crypt settings $this->cryptInit(); + // new better password init + $this->passwordInit(); // start logging running time $this->runningTime(); @@ -1630,6 +1633,11 @@ class Basic return false; } + // [!!! DEPRECATED !!!] + // ALL crypt* methids are DEPRECATED and SHALL NOT BE USED + // use the new password* instead + + // [!!! DEPRECATED !!!] -> passwordInit // METHOD: cryptInit // PARAMS: none // RETURN: none @@ -1676,6 +1684,7 @@ class Basic } } + // [!!! DEPRECATED !!!] -> not needed // METHOD: cryptSaltString // PARAMS: random string length, default is 22 (for blowfish crypt) // RETURN: random string @@ -1703,6 +1712,7 @@ class Basic return $salt_string; } + // [!!! DEPRECATED !!!] -> passwordSet // METHOD: cryptString // PARAMS: string to be crypted (one way) // RETURN: encrypted string @@ -1714,6 +1724,7 @@ class Basic return crypt($string, $this->cryptSaltPrefix.$this->cryptSaltString($this->cryptSaltSize).$this->cryptSaltSuffix); } + // [!!! DEPRECATED !!!] -> passwordVerify // METHOD: verifyCryptString // PARAMS: plain string (eg password) // full crypted string (from cryptString @@ -1729,6 +1740,61 @@ class Basic } } + // *** BETTER PASSWORD OPTIONS, must be used *** + // METHOD: passwordInit + // PARAMS: none + // RETURN: none + // DESC : inits the password options set + // currently this is et empty, and the default options are used + private function passwordInit() + { + // set default password cost: use default set automatically + $this->password_options = array ( + // 'cost' => PASSWORD_BCRYPT_DEFAULT_COST + ); + } + + // METHOD: passwordSet + // PARAMS: password + // RETURN: hashed password + // DESC : creates the password hash + public function passwordSet($password) + { + // always use the PHP default for the password + // password options ca be set in the password init, but should be kept as default + return password_hash($password, PASSWORD_DEFAULT, $this->password_options); + } + + // METHOD: passwordVerify + // PARAMS: password and hash + // RETURN: true or false + // DESC : checks if the entered password matches the hash + public function passwordVerify($password, $hash) + { + if (password_verify($password, $hash)) { + return true; + } else { + return false; + } + // in case something strange, return false on default + return false; + } + + // METHOD: passwordRehashCheck + // PARAMS: hash + // RETURN: true or false + // DESC : checks if the password needs to be rehashed + public function passwordRehashCheck($hash) + { + if (password_needs_rehash($hash, PASSWORD_DEFAULT, $this->password_options)) { + return true; + } else { + return false; + } + // in case of strange, force re-hash + return true; + } + // *** COLORS *** // METHOD: hex2rgb diff --git a/www/lib/CoreLibs/Output/Form/Generate.inc b/www/lib/CoreLibs/Output/Form/Generate.inc index deace199..1b5c7ad5 100644 --- a/www/lib/CoreLibs/Output/Form/Generate.inc +++ b/www/lib/CoreLibs/Output/Form/Generate.inc @@ -887,16 +887,16 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO } // switch } // for each error to check } elseif ($value["mandatory"] && - ( - // for all "normal" fields - ($this->table_array[$key]["type"] != "password" && $this->table_array[$key]["type"] != "drop_down_db_input" && !$this->table_array[$key]["value"]) || - // for drop_down_db_input check if one of both fields filled - ($this->table_array[$key]["type"] == "drop_down_db_input" && !$this->table_array[$key]["input_value"] && !$this->table_array[$key]["value"]) || - // for password - ($this->table_array[$key]["type"] == "password" && !$this->table_array[$key]["value"] && !$this->table_array[$key]["HIDDEN_value"]) - ) - // main if end - ) { + ( + // for all "normal" fields + ($this->table_array[$key]["type"] != "password" && $this->table_array[$key]["type"] != "drop_down_db_input" && !$this->table_array[$key]["value"]) || + // for drop_down_db_input check if one of both fields filled + ($this->table_array[$key]["type"] == "drop_down_db_input" && !$this->table_array[$key]["input_value"] && !$this->table_array[$key]["value"]) || + // for password + ($this->table_array[$key]["type"] == "password" && !$this->table_array[$key]["value"] && !$this->table_array[$key]["HIDDEN_value"]) + ) + // main if end + ) { // if mandatory && no input // $this->debug('form', "A: ".$this->table_array[$key]["type"]." -- ".$this->table_array[$key]["input_value"]." -- ".$this->table_array[$key]["value"]); if (!$this->table_array[$key]["value"] && $this->table_array[$key]["type"] != "binary") { @@ -1145,7 +1145,6 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO // DESC : save a table, reference and all input fields public function formSaveTableArray($addslashes = 0) { -// global $_FILES; // for drop_down_db_input check if text field is filled and if, if not yet in db ... // and upload files if (!is_array($this->table_array)) { @@ -1154,9 +1153,9 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO reset($this->table_array); while (list($key, $value) = each($this->table_array)) { // drop_down_db with input + reference table -//$this->debug('form', "A: ".$this->table_array[$key]["type"]." --- ".$this->table_array[$key]["input_value"]); + // $this->debug('form', "A: ".$this->table_array[$key]["type"]." --- ".$this->table_array[$key]["input_value"]); if ($this->table_array[$key]["type"] == "drop_down_db_input" && $this->table_array[$key]["input_value"]) { -//$this->debug('form', "HERE"); + // $this->debug('form', "HERE"); // check if this text name already exists (lowercase compare) $q = "SELECT ".$this->table_array[$key]["pk_name"]." FROM ".$this->table_array[$key]["table_name"]." WHERE LCASE(".$this->table_array[$key]["input_name"].") = '".$this->db_escape_string(strtolower($this->table_array[$key]["input_value"]))."'"; // if a where was given, add here @@ -1208,10 +1207,10 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO // if smth in $$key_file -> save or overwrite // if smth in $key && $$key_delete && !$$key_file-> delte // if smth in $key, keep as is -// $_file=$key."_file"; -// $_delete=$key."_delete"; -//$this->debug('form', "UF: ".$GLOBALS["_FILES"][$key."_file"]['name']); -//$this->debug('form', "delete: ".$key."_delete => ".$GLOBALS[$key.'_delete']); + // $_file=$key."_file"; + // $_delete=$key."_delete"; + // $this->debug('form', "UF: ".$GLOBALS["_FILES"][$key."_file"]['name']); + // $this->debug('form', "delete: ".$key."_delete => ".$GLOBALS[$key.'_delete']); if ($GLOBALS["_FILES"][$key."_file"]['name']) { // check if dir exists if (is_dir($this->table_array[$key]["save_dir"])) { @@ -1240,11 +1239,11 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO // for password crypt it as blowfish, or if not available MD5 if ($this->table_array[$key]['type'] == 'password') { if ($this->table_array[$key]["value"]) { - // password is stored in blowfish format, or in the format supported by this PHP version - $this->table_array[$key]["value"] = $this->cryptString($this->table_array[$key]["value"]); + // use the better new passwordSet instead of crypt based + $this->table_array[$key]['value'] = $this->passwordSet($this->table_array[$key]['value']); $this->table_array[$key]["HIDDEN_value"] = $this->table_array[$key]["value"]; } else { -// $this->table_array[$key]["HIDDEN_value"] = + // $this->table_array[$key]["HIDDEN_value"] = } } } // go through each field @@ -1287,14 +1286,14 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO $max = count($_POST[$prfx.$key]); } } -//$this->debug('edit_error', "MAX: $max"); + // $this->debug('edit_error', "MAX: $max"); // check if there is a hidden key, update, else insert while (list($el_name, $data_array) = each($reference_array["elements"])) { // this is only for reference_data part, at least one of the text fields need to be set for writing $blow_write = array (); -//$this->debug('edit_error_query', "QUERY: ".$this->print_ar($_POST)); + // $this->debug('edit_error_query', "QUERY: ".$this->print_ar($_POST)); // go through all submitted data -// for ($i = 0; $i < count($_POST[$el_name]); $i ++) + // for ($i = 0; $i < count($_POST[$el_name]); $i ++) for ($i = 0; $i < $max; $i ++) { // if we have enable name & delete set, then only insert/update those which are flagged as active // check if mandatory field is set, if not set "do not write flag" @@ -1326,7 +1325,7 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO // write all data (insert/update) because I don't know until all are processed if it is insert or update // don't write primary key backup for update // for reference_data type, only write if at least one text type field is set -//$this->debug('edit_error', "I: $i | EL Name: $prfx$el_name | Data: ".$_POST[$prfx.$el_name][$i]." | Type: ".$type[$i]." | PK: ".$data_array["pk_id"].", Block write: ".$block_write[$i]); + // $this->debug('edit_error', "I: $i | EL Name: $prfx$el_name | Data: ".$_POST[$prfx.$el_name][$i]." | Type: ".$type[$i]." | PK: ".$data_array["pk_id"].", Block write: ".$block_write[$i]); // only add elements that are not PK or FK flaged if (!$data_array['pk_id'] && !$data_array['fk_id']) { // update data list