PageRenderTime 42ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/fuel/packages/auth/classes/auth/login/simpleauth.php

https://bitbucket.org/codeyash/bootstrap
PHP | 545 lines | 344 code | 66 blank | 135 comment | 38 complexity | 76a85923b31e4f9546659dba032c604c MD5 | raw file
Possible License(s): MIT, Apache-2.0
  1. <?php
  2. /**
  3. * Fuel is a fast, lightweight, community driven PHP5 framework.
  4. *
  5. * @package Fuel
  6. * @version 1.5
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2013 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Auth;
  13. class SimpleUserUpdateException extends \FuelException {}
  14. class SimpleUserWrongPassword extends \FuelException {}
  15. /**
  16. * SimpleAuth basic login driver
  17. *
  18. * @package Fuel
  19. * @subpackage Auth
  20. */
  21. class Auth_Login_SimpleAuth extends \Auth_Login_Driver
  22. {
  23. public static function _init()
  24. {
  25. \Config::load('simpleauth', true, true, true);
  26. }
  27. /**
  28. * @var Database_Result when login succeeded
  29. */
  30. protected $user = null;
  31. /**
  32. * @var array value for guest login
  33. */
  34. protected static $guest_login = array(
  35. 'id' => 0,
  36. 'username' => 'guest',
  37. 'group' => '0',
  38. 'login_hash' => false,
  39. 'email' => false
  40. );
  41. /**
  42. * @var array SimpleAuth class config
  43. */
  44. protected $config = array(
  45. 'drivers' => array('group' => array('SimpleGroup')),
  46. 'additional_fields' => array('profile_fields'),
  47. );
  48. /**
  49. * Check for login
  50. *
  51. * @return bool
  52. */
  53. protected function perform_check()
  54. {
  55. $username = \Session::get('username');
  56. $login_hash = \Session::get('login_hash');
  57. // only worth checking if there's both a username and login-hash
  58. if ( ! empty($username) and ! empty($login_hash))
  59. {
  60. if (is_null($this->user) or ($this->user['username'] != $username and $this->user != static::$guest_login))
  61. {
  62. $this->user = \DB::select_array(\Config::get('simpleauth.table_columns', array('*')))
  63. ->where('username', '=', $username)
  64. ->from(\Config::get('simpleauth.table_name'))
  65. ->execute(\Config::get('simpleauth.db_connection'))->current();
  66. }
  67. // return true when login was verified
  68. if ($this->user and $this->user['login_hash'] === $login_hash)
  69. {
  70. return true;
  71. }
  72. }
  73. // no valid login when still here, ensure empty session and optionally set guest_login
  74. $this->user = \Config::get('simpleauth.guest_login', true) ? static::$guest_login : false;
  75. \Session::delete('username');
  76. \Session::delete('login_hash');
  77. return false;
  78. }
  79. /**
  80. * Check the user exists before logging in
  81. *
  82. * @return bool
  83. */
  84. public function validate_user($username_or_email = '', $password = '')
  85. {
  86. $username_or_email = trim($username_or_email) ?: trim(\Input::post(\Config::get('simpleauth.username_post_key', 'username')));
  87. $password = trim($password) ?: trim(\Input::post(\Config::get('simpleauth.password_post_key', 'password')));
  88. if (empty($username_or_email) or empty($password))
  89. {
  90. return false;
  91. }
  92. $password = $this->hash_password($password);
  93. $this->user = \DB::select_array(\Config::get('simpleauth.table_columns', array('*')))
  94. ->where_open()
  95. ->where('username', '=', $username_or_email)
  96. ->or_where('email', '=', $username_or_email)
  97. ->where_close()
  98. ->where('password', '=', $password)
  99. ->from(\Config::get('simpleauth.table_name'))
  100. ->execute(\Config::get('simpleauth.db_connection'))->current();
  101. return $this->user ?: false;
  102. }
  103. /**
  104. * Login user
  105. *
  106. * @param string
  107. * @param string
  108. * @return bool
  109. */
  110. public function login($username_or_email = '', $password = '')
  111. {
  112. if ( ! ($this->user = $this->validate_user($username_or_email, $password)))
  113. {
  114. $this->user = \Config::get('simpleauth.guest_login', true) ? static::$guest_login : false;
  115. \Session::delete('username');
  116. \Session::delete('login_hash');
  117. return false;
  118. }
  119. // register so Auth::logout() can find us
  120. Auth::_register_verified($this);
  121. \Session::set('username', $this->user['username']);
  122. \Session::set('login_hash', $this->create_login_hash());
  123. \Session::instance()->rotate();
  124. return true;
  125. }
  126. /**
  127. * Force login user
  128. *
  129. * @param string
  130. * @return bool
  131. */
  132. public function force_login($user_id = '')
  133. {
  134. if (empty($user_id))
  135. {
  136. return false;
  137. }
  138. $this->user = \DB::select_array(\Config::get('simpleauth.table_columns', array('*')))
  139. ->where_open()
  140. ->where('id', '=', $user_id)
  141. ->where_close()
  142. ->from(\Config::get('simpleauth.table_name'))
  143. ->execute(\Config::get('simpleauth.db_connection'))
  144. ->current();
  145. if ($this->user == false)
  146. {
  147. $this->user = \Config::get('simpleauth.guest_login', true) ? static::$guest_login : false;
  148. \Session::delete('username');
  149. \Session::delete('login_hash');
  150. return false;
  151. }
  152. \Session::set('username', $this->user['username']);
  153. \Session::set('login_hash', $this->create_login_hash());
  154. return true;
  155. }
  156. /**
  157. * Logout user
  158. *
  159. * @return bool
  160. */
  161. public function logout()
  162. {
  163. $this->user = \Config::get('simpleauth.guest_login', true) ? static::$guest_login : false;
  164. \Session::delete('username');
  165. \Session::delete('login_hash');
  166. return true;
  167. }
  168. /**
  169. * Create new user
  170. *
  171. * @param string
  172. * @param string
  173. * @param string must contain valid email address
  174. * @param int group id
  175. * @param Array
  176. * @return bool
  177. */
  178. public function create_user($username, $password, $email, $group = 1, Array $profile_fields = array())
  179. {
  180. $password = trim($password);
  181. $email = filter_var(trim($email), FILTER_VALIDATE_EMAIL);
  182. if (empty($username) or empty($password) or empty($email))
  183. {
  184. throw new \SimpleUserUpdateException('Username, password or email address is not given, or email address is invalid', 1);
  185. }
  186. $same_users = \DB::select_array(\Config::get('simpleauth.table_columns', array('*')))
  187. ->where('username', '=', $username)
  188. ->or_where('email', '=', $email)
  189. ->from(\Config::get('simpleauth.table_name'))
  190. ->execute(\Config::get('simpleauth.db_connection'));
  191. if ($same_users->count() > 0)
  192. {
  193. if (in_array(strtolower($email), array_map('strtolower', $same_users->current())))
  194. {
  195. throw new \SimpleUserUpdateException('Email address already exists', 2);
  196. }
  197. else
  198. {
  199. throw new \SimpleUserUpdateException('Username already exists', 3);
  200. }
  201. }
  202. $user = array(
  203. 'username' => (string) $username,
  204. 'password' => $this->hash_password((string) $password),
  205. 'email' => $email,
  206. 'group' => (int) $group,
  207. 'profile_fields' => serialize($profile_fields),
  208. 'last_login' => 0,
  209. 'login_hash' => '',
  210. 'created_at' => \Date::forge()->get_timestamp()
  211. );
  212. $result = \DB::insert(\Config::get('simpleauth.table_name'))
  213. ->set($user)
  214. ->execute(\Config::get('simpleauth.db_connection'));
  215. return ($result[1] > 0) ? $result[0] : false;
  216. }
  217. /**
  218. * Update a user's properties
  219. * Note: Username cannot be updated, to update password the old password must be passed as old_password
  220. *
  221. * @param Array properties to be updated including profile fields
  222. * @param string
  223. * @return bool
  224. */
  225. public function update_user($values, $username = null)
  226. {
  227. $username = $username ?: $this->user['username'];
  228. $current_values = \DB::select_array(\Config::get('simpleauth.table_columns', array('*')))
  229. ->where('username', '=', $username)
  230. ->from(\Config::get('simpleauth.table_name'))
  231. ->execute(\Config::get('simpleauth.db_connection'));
  232. if (empty($current_values))
  233. {
  234. throw new \SimpleUserUpdateException('Username not found', 4);
  235. }
  236. $update = array();
  237. if (array_key_exists('username', $values))
  238. {
  239. throw new \SimpleUserUpdateException('Username cannot be changed.', 5);
  240. }
  241. if (array_key_exists('password', $values))
  242. {
  243. if (empty($values['old_password'])
  244. or $current_values->get('password') != $this->hash_password(trim($values['old_password'])))
  245. {
  246. throw new \SimpleUserWrongPassword('Old password is invalid');
  247. }
  248. $password = trim(strval($values['password']));
  249. if ($password === '')
  250. {
  251. throw new \SimpleUserUpdateException('Password can\'t be empty.', 6);
  252. }
  253. $update['password'] = $this->hash_password($password);
  254. unset($values['password']);
  255. }
  256. if (array_key_exists('old_password', $values))
  257. {
  258. unset($values['old_password']);
  259. }
  260. if (array_key_exists('email', $values))
  261. {
  262. $email = filter_var(trim($values['email']), FILTER_VALIDATE_EMAIL);
  263. if ( ! $email)
  264. {
  265. throw new \SimpleUserUpdateException('Email address is not valid', 7);
  266. }
  267. $update['email'] = $email;
  268. unset($values['email']);
  269. }
  270. if (array_key_exists('group', $values))
  271. {
  272. if (is_numeric($values['group']))
  273. {
  274. $update['group'] = (int) $values['group'];
  275. }
  276. unset($values['group']);
  277. }
  278. if ( ! empty($values))
  279. {
  280. $profile_fields = @unserialize($current_values->get('profile_fields')) ?: array();
  281. foreach ($values as $key => $val)
  282. {
  283. if ($val === null)
  284. {
  285. unset($profile_fields[$key]);
  286. }
  287. else
  288. {
  289. $profile_fields[$key] = $val;
  290. }
  291. }
  292. $update['profile_fields'] = serialize($profile_fields);
  293. }
  294. $affected_rows = \DB::update(\Config::get('simpleauth.table_name'))
  295. ->set($update)
  296. ->where('username', '=', $username)
  297. ->execute(\Config::get('simpleauth.db_connection'));
  298. // Refresh user
  299. if ($this->user['username'] == $username)
  300. {
  301. $this->user = \DB::select_array(\Config::get('simpleauth.table_columns', array('*')))
  302. ->where('username', '=', $username)
  303. ->from(\Config::get('simpleauth.table_name'))
  304. ->execute(\Config::get('simpleauth.db_connection'))->current();
  305. }
  306. return $affected_rows > 0;
  307. }
  308. /**
  309. * Change a user's password
  310. *
  311. * @param string
  312. * @param string
  313. * @param string username or null for current user
  314. * @return bool
  315. */
  316. public function change_password($old_password, $new_password, $username = null)
  317. {
  318. try
  319. {
  320. return (bool) $this->update_user(array('old_password' => $old_password, 'password' => $new_password), $username);
  321. }
  322. // Only catch the wrong password exception
  323. catch (SimpleUserWrongPassword $e)
  324. {
  325. return false;
  326. }
  327. }
  328. /**
  329. * Generates new random password, sets it for the given username and returns the new password.
  330. * To be used for resetting a user's forgotten password, should be emailed afterwards.
  331. *
  332. * @param string $username
  333. * @return string
  334. */
  335. public function reset_password($username)
  336. {
  337. $new_password = \Str::random('alnum', 8);
  338. $password_hash = $this->hash_password($new_password);
  339. $affected_rows = \DB::update(\Config::get('simpleauth.table_name'))
  340. ->set(array('password' => $password_hash))
  341. ->where('username', '=', $username)
  342. ->execute(\Config::get('simpleauth.db_connection'));
  343. if ( ! $affected_rows)
  344. {
  345. throw new \SimpleUserUpdateException('Failed to reset password, user was invalid.', 8);
  346. }
  347. return $new_password;
  348. }
  349. /**
  350. * Deletes a given user
  351. *
  352. * @param string
  353. * @return bool
  354. */
  355. public function delete_user($username)
  356. {
  357. if (empty($username))
  358. {
  359. throw new \SimpleUserUpdateException('Cannot delete user with empty username', 9);
  360. }
  361. $affected_rows = \DB::delete(\Config::get('simpleauth.table_name'))
  362. ->where('username', '=', $username)
  363. ->execute(\Config::get('simpleauth.db_connection'));
  364. return $affected_rows > 0;
  365. }
  366. /**
  367. * Creates a temporary hash that will validate the current login
  368. *
  369. * @return string
  370. */
  371. public function create_login_hash()
  372. {
  373. if (empty($this->user))
  374. {
  375. throw new \SimpleUserUpdateException('User not logged in, can\'t create login hash.', 10);
  376. }
  377. $last_login = \Date::forge()->get_timestamp();
  378. $login_hash = sha1(\Config::get('simpleauth.login_hash_salt').$this->user['username'].$last_login);
  379. \DB::update(\Config::get('simpleauth.table_name'))
  380. ->set(array('last_login' => $last_login, 'login_hash' => $login_hash))
  381. ->where('username', '=', $this->user['username'])
  382. ->execute(\Config::get('simpleauth.db_connection'));
  383. $this->user['login_hash'] = $login_hash;
  384. return $login_hash;
  385. }
  386. /**
  387. * Get the user's ID
  388. *
  389. * @return Array containing this driver's ID & the user's ID
  390. */
  391. public function get_user_id()
  392. {
  393. if (empty($this->user))
  394. {
  395. return false;
  396. }
  397. return array($this->id, (int) $this->user['id']);
  398. }
  399. /**
  400. * Get the user's groups
  401. *
  402. * @return Array containing the group driver ID & the user's group ID
  403. */
  404. public function get_groups()
  405. {
  406. if (empty($this->user))
  407. {
  408. return false;
  409. }
  410. return array(array('SimpleGroup', $this->user['group']));
  411. }
  412. /**
  413. * Get the user's emailaddress
  414. *
  415. * @return string
  416. */
  417. public function get_email()
  418. {
  419. if (empty($this->user))
  420. {
  421. return false;
  422. }
  423. return $this->user['email'];
  424. }
  425. /**
  426. * Get the user's screen name
  427. *
  428. * @return string
  429. */
  430. public function get_screen_name()
  431. {
  432. if (empty($this->user))
  433. {
  434. return false;
  435. }
  436. return $this->user['username'];
  437. }
  438. /**
  439. * Get the user's profile fields
  440. *
  441. * @return Array
  442. */
  443. public function get_profile_fields($field = null, $default = null)
  444. {
  445. if (empty($this->user))
  446. {
  447. return false;
  448. }
  449. if (isset($this->user['profile_fields']))
  450. {
  451. is_array($this->user['profile_fields']) or $this->user['profile_fields'] = @unserialize($this->user['profile_fields']);
  452. }
  453. else
  454. {
  455. $this->user['profile_fields'] = array();
  456. }
  457. return is_null($field) ? $this->user['profile_fields'] : \Arr::get($this->user['profile_fields'], $field, $default);
  458. }
  459. /**
  460. * Extension of base driver method to default to user group instead of user id
  461. */
  462. public function has_access($condition, $driver = null, $user = null)
  463. {
  464. if (is_null($user))
  465. {
  466. $groups = $this->get_groups();
  467. $user = reset($groups);
  468. }
  469. return parent::has_access($condition, $driver, $user);
  470. }
  471. /**
  472. * Extension of base driver because this supports a guest login when switched on
  473. */
  474. public function guest_login()
  475. {
  476. return \Config::get('simpleauth.guest_login', true);
  477. }
  478. }
  479. // end of file simpleauth.php