예제 #1
0
 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;
 }
예제 #3
0
 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;
 }