/libraries/Auth.php
PHP | 450 lines | 194 code | 85 blank | 171 comment | 28 complexity | d995d19bae1141a0c0a00de6e08b60ad MD5 | raw file
- <?php
- /**
- * Auth - Secure, clean Authentication library for CodeIgniter
- *
- * @package Auth
- * @category Libraries
- * @author Giordano Piazza
- * @link http://www.giordanopiazza.com
- * @version 0.4
- * @copyright Copyright (c) 2009-2010, Giordano Piazza
- *
- */
- /*
- TODO
- - Login attempts
- - Encrypt/Decrypt cookies and database
- NOTES
- - security reminder: check login attempts from multiple IPs to the same username
- - remember me: if last ip mask doesn't match current, force the user to enter the password
- */
- class Auth
- {
- protected $ci; // The CI object
- protected $config; // The config items
- protected $users_table; // The user table (prefix + config)
- protected $groups_table; // The group table (prefix + config)
- protected $remember_me_cookie; // The cookie used for remember me autologin
-
- /**
- * Auth constructor
- *
- * @access public
- */
- public function __construct()
- {
- $this->ci =& get_instance();
-
- $this->ci->load->database();
- $this->ci->load->library('session');
- $this->ci->load->library('security');
-
- $this->ci->config->load('auth');
-
- $this->users_table = $this->ci->config->item('users_table');
- $this->groups_table = $this->ci->config->item('groups_table');
-
- // Check remember-me cookie if enabled
- if ($this->ci->config->item('remember_me'))
- {
- if(!$this->logged_in())
- {
- $this->verify_cookie();
- }
- }
- }
- /**
- * Log a user in
- *
- *
- * @access public
- * @param string
- * @param string
- * @param bool
- * @return bool
- */
- public function login($identity = false, $password = false, $remember_me = false)
- {
- // TODO: better login attempts handling in users table
- /*if((array_key_exists('login_attempts', $_COOKIE)) && ($_COOKIE['login_attempts'] >= 5))
- {
- echo $this->ci->lang->line('max_login_attempts_error');
- }*/
-
-
- // Check if identity and password are there
- if ($identity === false || $password === false)
- {
- return false;
- }
- // Get user identity
- $query = $this->get_identity($identity);
- // If the identity is found
- if ($query->num_rows() == 1)
- {
- // Get query result
- $result = $query->row();
-
- if (!empty($result->activation_code)) { return false; }
-
- // Hashing password with user's email as Salt (against rainbow tables)
- $password = $this->hash($password, $result->email);
- // Check if the passwords match
- if ($result->password === $password)
- {
- // Set the identity and the logged_in flag in the session data
- $this->ci->session->set_userdata(array('identity' => $identity,
- 'logged_in' => true));
- //$this->ci->session->set_userdata('logged_in', true);
-
- // If remember-me is enabled, create the cookie
- if ($remember_me) $this->make_cookie($identity);
-
- // Force the session id to refresh
- $this->ci->session->sess_time_to_update = 0;
- $this->ci->session->sess_update();
-
- return true;
- }
- else
- {
- $this->session->unset_userdata('logged_in');
- return false;
- }
- }
-
- return false;
- }
- /**
- * Logout - logs a user out
- *
- * @access public
- * @return void
- */
- public function logout()
- {
- // destroy session
- $this->ci->session->sess_destroy();
-
- // delete cookie
- $this->delete_cookie();
- }
- /**
- * Register a new user
- *
- * Adds the main user information, and the additional profile columns if specified
- *
- * @access public
- * @param string
- * @return bool
- */
- public function register($username = false, $password = false, $email = false, $profile_fields = false)
- {
- if ($username === false || $password === false || $email === false)
- {
- return false;
- }
-
- // Add info to the users table
- $data = array('username' => $username,
- 'password' => $this->hash($password, $email),
- 'email' => $email,
- 'activation_code' => sha1(microtime().$username.$email),
- 'created' => date("y-m-d H:i:s", time()),
- 'last_ip' => $this->ci->input->ip_address());
-
- $this->ci->db->insert($this->users_table, $data);
- // Add info to the profiles table - not yet used
- if ($this->ci->config->item('profiles_table') != '')
- {
- $id = $this->ci->db->insert_id();
- $data = array($this->ci->config->item('join_table') => $id);
-
- if (!empty($profile_fields))
- {
- foreach ($profile_fields as $input)
- $data[$input] = $this->ci->input->post($input, true);
- }
-
- $this->ci->db->insert($this->ci->config->item('profiles_table'), $data);
- return ($this->ci->db->affected_rows() > 0) ? true : false;
- }
- }
- /**
- * Check if a user is logged in
- *
- * Look in the session data and return the 'logged_in' value
- *
- * @access public
- * @return bool
- */
- public function logged_in()
- {
- return ($this->ci->session->userdata('logged_in')) ? true : false;
- }
- /**
- * Activate the user with the code sent by email
- *
- * Check if the provided activation code exists in the database and empty the field to activate the user
- *
- * @access public
- * @param string
- * @return bool
- */
- public function activate($code = false)
- {
- if ($code === false) return false;
-
- $code = $this->ci->security->xss_clean($code);
-
- $this->ci->db->where('activation_code', $code)
- ->limit(1)
- ->update($this->users_table, array('activation_code' => ''));
-
- return ($this->ci->db->affected_rows() > 0) ? true : false;
- }
- /**
- * Get user identity
- *
- * @access public
- * @param string
- * @return mixed : query-result or false
- */
- public function get_identity($identity = false)
- {
- if ($identity === false) return false;
-
- // get the columns to use as identity
- $identity_columns = $this->ci->config->item('identity_columns');
-
- // select the fields separating them with a comma
- $this->ci->db->select(implode(", ", $identity_columns).', id, password, activation_code');
-
- // Prepare the query with all the available identities
- foreach ($identity_columns as $column)
- $this->ci->db->or_where($column.' =', $identity);
-
- // finally get and return user info
- $query = $this->ci->db->get($this->users_table, 1, 0);
- return ($query->num_rows() === 1) ? $query : false;
- }
- /**
- * Verify if the user's identity already exists in the database
- *
- * @access public
- * @param string
- * @return bool
- */
- public function check_identity($identity = false)
- {
- return ($this->get_identity($identity) != false) ? true : false;
- }
- /**
- * Hash the user password with the encryption key, and the salt if set
- *
- * @access protected
- * @param string
- * @return string
- */
- protected function hash($str, $salt = false)
- {
- if ($salt) $str .= $salt;
- return hash($this->ci->config->item('hash_type'), $this->ci->config->item('salt').$str);
- }
- /**
- * Generate a 128 bit random uuid
- *
- * @access protected
- * @return string
- */
- protected function generate_token()
- {
- return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
- mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
- mt_rand( 0, 0x0fff ) | 0x4000,
- mt_rand( 0, 0x3fff ) | 0x8000,
- mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ) );
- }
- /**
- * Verify that a user has a Remember-Me cookie.
- * If the cookie doesn't match the database, log the user out.
- *
- * @access protected
- * @return void
- */
- protected function verify_cookie()
- {
- //log_message('debug', "============== Verify Cookie started");
-
- $this->ci->load->library('encrypt');
- $this->ci->load->helper('cookie');
- // get cookie
- $cookie = $this->ci->input->cookie($this->ci->config->item('remember_me_cookie'), true);
-
- // decrypt cookie
- if ($cookie)
- {
- $cookie = $this->ci->encrypt->decode($cookie);
- $cookie = @unserialize(base64_decode($cookie));
- }
-
- // validate cookie
- if (is_array($cookie))
- {
- //log_message('debug', "============== Cookie found");
-
- $remember_me_table = $this->ci->config->item('remember_me_table');
-
- // get db data
- $query = $this->ci->db->select('identity, token, user_agent')
- ->where(array('identity' => $cookie['identity'], 'token' => $cookie['token']))
- ->limit(1)
- ->get($remember_me_table);
- $result = $query->row();
-
- // found the cookie in the db
- if ($query->num_rows() == 1)
- {
- //log_message('debug', "============== Cookie found in the DB");
- // double check if the cookie and the user agent match (maybe maniac?)
- if ($result->identity == $cookie['identity'] &&
- $result->token == $cookie['token'] &&
- $result->user_agent == $this->ci->input->user_agent())
- {
- // delete token from database
- $this->ci->db->where(array('identity' => $result->identity, 'token' => $result->token))
- ->limit(1)
- ->delete($remember_me_table);
-
- // Force the session id to refresh
- $this->ci->session->sess_time_to_update = 0;
- $this->ci->session->sess_update();
-
- // The user is now logged in, remember me is flagged to disallow some specific operations until a password is provided
- $data = array('identity' => $result->identity,
- 'logged_in' => true,
- 'remember_me' => true);
-
- $this->ci->session->set_userdata($data);
-
- // Make the Remember-me cookie
- $this->make_cookie($result->identity);
-
- //log_message('debug', "============== Cookie verified and recreated");
-
- return true;
- }
- /*else
- {
- //log_message('debug', "============== Cookie NOT verfied");
-
- // delete cookie
- //$this->delete_cookie();
- }*/
- }
- else
- {
- //log_message('debug', "============== Cookie NOT found in the DB");
-
- $this->logout();
-
- return false;
- }
- }
- else
- {
- //log_message('debug', "============== Cookie NOT found");
- return false;
- }
- }
- /**
- * Make a new Remember-me cookie
- *
- * @access private
- * @return void
- */
- protected function make_cookie($identity = false)
- {
- if ($identity === false) return false;
-
- // generate a new random token
- $token = $this->generate_token();
-
- $data = array('identity' => $identity,
- 'token' => $token,
- 'user_agent' => $this->ci->input->user_agent(),
- 'last_ip' => $this->ci->input->ip_address(),
- 'last_login' => date("y-m-d H:i:s", time()));
- // insert data into database
- $this->ci->db->insert($this->ci->config->item('remember_me_table'), $data);
-
- // prepare cookie data
- $cookie['identity'] = $identity;
- $cookie['token'] = $token;
-
- $cookie = base64_encode(serialize($cookie));
-
- // encrypt the cookie
- $identifier = $this->ci->encrypt->encode($cookie);
-
- // create the cookie
- setcookie($this->ci->config->item('remember_me_cookie'), $identifier, time()+$this->ci->config->item('remember_me_for'), '/', $this->ci->config->item('cookie_domain'));
- }
- /**
- * Delete Remember-me cookie
- *
- * @access private
- * @return void
- */
- protected function delete_cookie()
- {
- setcookie($this->ci->config->item('remember_me_cookie'), '0', time()-3600, '/', $this->ci->config->item('cookie_domain'));
- }
- } // class Auth
- // EOF: Auth.php