public function create($data, $send_welcome_email = true, $token_mode = false) { $data['userCreated'] = date('Y-m-d H:i:s'); $data['userEnabled'] = '1'; if ($token_mode) { // issue a token for creating an account with a new password, like password reset does. $NewUser = parent::create($data); if (is_object($NewUser) && $send_welcome_email) { $NewUser->send_welcome_email($token_mode); } } else { $Hasher = PerchUtil::get_password_hasher(); $clear_pwd = $data['userPassword']; $data['userPassword'] = $Hasher->HashPassword($clear_pwd); $NewUser = parent::create($data); if (is_object($NewUser) && $send_welcome_email) { $NewUser->squirrel('clear_pwd', $clear_pwd); $NewUser->send_welcome_email(); } } return $NewUser; }
public function authenticate($username, $password) { // Passwords should never be longer than 72 characters if (strlen($password) > 72) { return false; } $username = filter_var($username, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW); if ($this->activate()) { if (PERCH_PARANOID) { // reset any expired lockouts for this user $sql = 'UPDATE ' . $this->table . ' SET userLastFailedLogin=NULL, userFailedLoginAttempts=0 WHERE BINARY userUsername='******' AND userLastFailedLogin<' . $this->db->pdb(date('Y-m-d H:i:s', strtotime('-' . PERCH_AUTH_LOCKOUT_DURATION))); $this->db->execute($sql); } $sql = 'SELECT u.*, r.* FROM ' . $this->table . ' u, ' . PERCH_DB_PREFIX . 'user_roles r WHERE u.roleID=r.roleID AND u.userEnabled=1 AND '; if (PERCH_PARANOID) { $sql .= 'BINARY userUsername='******' AND userFailedLoginAttempts<' . (int) PERCH_MAX_FAILED_LOGINS; } else { $sql .= 'userUsername='******' LIMIT 1'; $result = $this->db->get_row($sql); if (is_array($result)) { PerchUtil::debug('User exists, checking password.'); // presume password fail. $password_match = false; $stored_password = $result['userPassword']; $Hasher = PerchUtil::get_password_hasher(); // data array for user details - gets committed if passwords check out. $data = array(); // check password type if (substr($stored_password, 0, 3) == '$P$') { PerchUtil::debug('Stronger password hash.'); // stronger hash, check password if ($Hasher->CheckPassword($password, $stored_password)) { $password_match = true; PerchUtil::debug('Password is ok.'); } else { PerchUtil::debug('Password failed to match.'); } } else { // old MD5 password PerchUtil::debug('Old MD5 password.'); if ($stored_password == md5($password)) { $password_match = true; PerchUtil::debug('Password is ok. Upgrading.'); //upgrade! $hashed_password = $Hasher->HashPassword($password); $data['userPassword'] = $hashed_password; } else { PerchUtil::debug('MD5 password failed to match.'); } } if ($password_match) { $this->set_details($result); $data['userHash'] = md5(uniqid()); $data['userLastLogin'] = date('Y-m-d H:i:s'); $data['userFailedLoginAttempts'] = 0; $data['userLastFailedLogin'] = null; $this->update($data); $this->result['userHash'] = $data['userHash']; $this->set_details($result); PerchSession::regenerate(); PerchSession::set('userID', $result['userID']); PerchSession::set('userHash', $data['userHash']); $this->logged_in = true; $this->_load_privileges(); if (!$this->has_priv('perch.login')) { PerchUtil::debug('User role does not have login privs'); $this->logout(); return false; } // Set cookie for front-end might-be-authed check PerchUtil::setcookie('cmsa', 1, strtotime('+30 days'), '/'); $Perch = Perch::fetch(); $Perch->event('user.login', $this); return true; } // Username checks out, but wrong password. $data['userFailedLoginAttempts'] = (int) $result['userFailedLoginAttempts'] + 1; $data['userLastFailedLogin'] = date('Y-m-d H:i:s'); $this->set_details($result); $this->update($data); if (PERCH_PARANOID && $data['userFailedLoginAttempts'] == PERCH_MAX_FAILED_LOGINS) { $this->send_lockout_email($result['userID']); } } } PerchUtil::debug('Writing auth fail to log.'); $username = escapeshellcmd(stripslashes($username)); @syslog(LOG_INFO, 'Authentication failure for ' . $username . ' from ' . PerchUtil::get_client_ip()); return false; }
public function password_meets_requirements($clear_pwd) { if (defined('PERCH_STRONG_PASSWORDS') && PERCH_STRONG_PASSWORDS) { $pwd_min_len = 6; if (defined('PERCH_PASSWORD_MIN_LENGTH')) { $pwd_min_len = (int) PERCH_PASSWORD_MIN_LENGTH; } $user = $this->userUsername(); $pass = $clear_pwd; // http://docstore.mik.ua/orelly/webprog/pcook/ch14_06.htm $lc_pass = strtolower($pass); // check password with numbers or punctuation subbed for letters $denum_pass = strtr($lc_pass, '5301!$@', 'seollsa'); $lc_user = strtolower($user); // the password must be at least $pwd_min_len characters if (strlen($pass) < $pwd_min_len) { $this->msg = 'That password is too short. Make it longer.'; return false; } // the password can't be the username (or reversed username) if ($lc_pass == $lc_user || $lc_pass == strrev($lc_user) || $denum_pass == $lc_user || $denum_pass == strrev($lc_user)) { $this->msg = 'That password is based on your username. Choose something different.'; return false; } // count how many lowercase, uppercase, and digits are in the password $uc = 0; $lc = 0; $num = 0; $other = 0; for ($i = 0, $j = strlen($pass); $i < $j; $i++) { $c = substr($pass, $i, 1); if (preg_match('/^[[:upper:]]$/', $c)) { $uc++; } elseif (preg_match('/^[[:lower:]]$/', $c)) { $lc++; } elseif (preg_match('/^[[:digit:]]$/', $c)) { $num++; } else { $other++; } } // the password must have more than two characters of at least // two different kinds $max = $j - 2; if ($uc > $max) { $this->msg = "That password has too many upper case characters. Mix it up a bit."; return false; } if ($lc > $max) { $this->msg = "That password has too many lower case characters. Mix it up a bit."; return false; } if ($num > $max) { $this->msg = "That password has too many numeral characters. Mix it up a bit."; return false; } if ($other > $max) { $this->msg = "That password has too many special characters. Mix it up a bit."; return false; } // only check for existing users (pwd change) not new users (pwd create) if ($this->id()) { // has it been used in the last 6 months? $backdate = strtotime('-6 MONTHS'); $sql = 'SELECT userPassword FROM ' . PERCH_DB_PREFIX . 'user_passwords WHERE userID=' . $this->db->pdb((int) $this->id()) . ' AND passwordLastUsed > ' . $this->db->pdb(date('Y-m-d H:i:s', $backdate)); $old_passwords = $this->db->get_rows_flat($sql); // include the current password $old_passwords[] = $this->userPassword(); if (PerchUtil::count($old_passwords)) { $Hasher = PerchUtil::get_password_hasher(); foreach ($old_passwords as $old_pwd) { if ($Hasher->CheckPassword($pass, $old_pwd)) { $this->msg = "That password has been used before. Choose a new password."; return false; } } } } } // strong pwds not enabled, so there are no special requirements. // or has passed all the above checks return true; }