PageRenderTime 58ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/sriedel/iccrm-wip
PHP | 542 lines | 343 code | 65 blank | 134 comment | 38 complexity | aa5653372736aec6ca93c0ee77b25332 MD5 | raw file
Possible License(s): MIT
  1. <?php
  2. /**
  3. * Fuel is a fast, lightweight, community driven PHP5 framework.
  4. *
  5. * @package Fuel
  6. * @version 1.0
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2011 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. \Session::set('username', $this->user['username']);
  120. \Session::set('login_hash', $this->create_login_hash());
  121. \Session::instance()->rotate();
  122. return true;
  123. }
  124. /**
  125. * Force login user
  126. *
  127. * @param string
  128. * @return bool
  129. */
  130. public function force_login($user_id = '')
  131. {
  132. if (empty($user_id))
  133. {
  134. return false;
  135. }
  136. $this->user = \DB::select_array(\Config::get('simpleauth.table_columns', array('*')))
  137. ->where_open()
  138. ->where('id', '=', $user_id)
  139. ->where_close()
  140. ->from(\Config::get('simpleauth.table_name'))
  141. ->execute(\Config::get('simpleauth.db_connection'))
  142. ->current();
  143. if ($this->user == false)
  144. {
  145. $this->user = \Config::get('simpleauth.guest_login', true) ? static::$guest_login : false;
  146. \Session::delete('username');
  147. \Session::delete('login_hash');
  148. return false;
  149. }
  150. \Session::set('username', $this->user['username']);
  151. \Session::set('login_hash', $this->create_login_hash());
  152. return true;
  153. }
  154. /**
  155. * Logout user
  156. *
  157. * @return bool
  158. */
  159. public function logout()
  160. {
  161. $this->user = \Config::get('simpleauth.guest_login', true) ? static::$guest_login : false;
  162. \Session::delete('username');
  163. \Session::delete('login_hash');
  164. return true;
  165. }
  166. /**
  167. * Create new user
  168. *
  169. * @param string
  170. * @param string
  171. * @param string must contain valid email address
  172. * @param int group id
  173. * @param Array
  174. * @return bool
  175. */
  176. public function create_user($username, $password, $email, $group = 1, Array $profile_fields = array())
  177. {
  178. $password = trim($password);
  179. $email = filter_var(trim($email), FILTER_VALIDATE_EMAIL);
  180. if (empty($username) or empty($password) or empty($email))
  181. {
  182. throw new \SimpleUserUpdateException('Username, password or email address is not given, or email address is invalid', 1);
  183. }
  184. $same_users = \DB::select_array(\Config::get('simpleauth.table_columns', array('*')))
  185. ->where('username', '=', $username)
  186. ->or_where('email', '=', $email)
  187. ->from(\Config::get('simpleauth.table_name'))
  188. ->execute(\Config::get('simpleauth.db_connection'));
  189. if ($same_users->count() > 0)
  190. {
  191. if (in_array(strtolower($email), array_map('strtolower', $same_users->current())))
  192. {
  193. throw new \SimpleUserUpdateException('Email address already exists', 2);
  194. }
  195. else
  196. {
  197. throw new \SimpleUserUpdateException('Username already exists', 3);
  198. }
  199. }
  200. $user = array(
  201. 'username' => (string) $username,
  202. 'password' => $this->hash_password((string) $password),
  203. 'email' => $email,
  204. 'group' => (int) $group,
  205. 'profile_fields' => serialize($profile_fields),
  206. 'last_login' => 0,
  207. 'login_hash' => '',
  208. 'created_at' => \Date::forge()->get_timestamp()
  209. );
  210. $result = \DB::insert(\Config::get('simpleauth.table_name'))
  211. ->set($user)
  212. ->execute(\Config::get('simpleauth.db_connection'));
  213. return ($result[1] > 0) ? $result[0] : false;
  214. }
  215. /**
  216. * Update a user's properties
  217. * Note: Username cannot be updated, to update password the old password must be passed as old_password
  218. *
  219. * @param Array properties to be updated including profile fields
  220. * @param string
  221. * @return bool
  222. */
  223. public function update_user($values, $username = null)
  224. {
  225. $username = $username ?: $this->user['username'];
  226. $current_values = \DB::select_array(\Config::get('simpleauth.table_columns', array('*')))
  227. ->where('username', '=', $username)
  228. ->from(\Config::get('simpleauth.table_name'))
  229. ->execute(\Config::get('simpleauth.db_connection'));
  230. if (empty($current_values))
  231. {
  232. throw new \SimpleUserUpdateException('Username not found', 4);
  233. }
  234. $update = array();
  235. if (array_key_exists('username', $values))
  236. {
  237. throw new \SimpleUserUpdateException('Username cannot be changed.', 5);
  238. }
  239. if (array_key_exists('password', $values))
  240. {
  241. if (empty($values['old_password'])
  242. or $current_values->get('password') != $this->hash_password(trim($values['old_password'])))
  243. {
  244. throw new \SimpleUserWrongPassword('Old password is invalid');
  245. }
  246. $password = trim(strval($values['password']));
  247. if ($password === '')
  248. {
  249. throw new \SimpleUserUpdateException('Password can\'t be empty.', 6);
  250. }
  251. $update['password'] = $this->hash_password($password);
  252. unset($values['password']);
  253. }
  254. if (array_key_exists('old_password', $values))
  255. {
  256. unset($values['old_password']);
  257. }
  258. if (array_key_exists('email', $values))
  259. {
  260. $email = filter_var(trim($values['email']), FILTER_VALIDATE_EMAIL);
  261. if ( ! $email)
  262. {
  263. throw new \SimpleUserUpdateException('Email address is not valid', 7);
  264. }
  265. $update['email'] = $email;
  266. unset($values['email']);
  267. }
  268. if (array_key_exists('group', $values))
  269. {
  270. if (is_numeric($values['group']))
  271. {
  272. $update['group'] = (int) $values['group'];
  273. }
  274. unset($values['group']);
  275. }
  276. if ( ! empty($values))
  277. {
  278. $profile_fields = @unserialize($current_values->get('profile_fields')) ?: array();
  279. foreach ($values as $key => $val)
  280. {
  281. if ($val === null)
  282. {
  283. unset($profile_fields[$key]);
  284. }
  285. else
  286. {
  287. $profile_fields[$key] = $val;
  288. }
  289. }
  290. $update['profile_fields'] = serialize($profile_fields);
  291. }
  292. $affected_rows = \DB::update(\Config::get('simpleauth.table_name'))
  293. ->set($update)
  294. ->where('username', '=', $username)
  295. ->execute(\Config::get('simpleauth.db_connection'));
  296. // Refresh user
  297. if ($this->user['username'] == $username)
  298. {
  299. $this->user = \DB::select_array(\Config::get('simpleauth.table_columns', array('*')))
  300. ->where('username', '=', $username)
  301. ->from(\Config::get('simpleauth.table_name'))
  302. ->execute(\Config::get('simpleauth.db_connection'))->current();
  303. }
  304. return $affected_rows > 0;
  305. }
  306. /**
  307. * Change a user's password
  308. *
  309. * @param string
  310. * @param string
  311. * @param string username or null for current user
  312. * @return bool
  313. */
  314. public function change_password($old_password, $new_password, $username = null)
  315. {
  316. try
  317. {
  318. return (bool) $this->update_user(array('old_password' => $old_password, 'password' => $new_password), $username);
  319. }
  320. // Only catch the wrong password exception
  321. catch (SimpleUserWrongPassword $e)
  322. {
  323. return false;
  324. }
  325. }
  326. /**
  327. * Generates new random password, sets it for the given username and returns the new password.
  328. * To be used for resetting a user's forgotten password, should be emailed afterwards.
  329. *
  330. * @param string $username
  331. * @return string
  332. */
  333. public function reset_password($username)
  334. {
  335. $new_password = \Str::random('alnum', 8);
  336. $password_hash = $this->hash_password($new_password);
  337. $affected_rows = \DB::update(\Config::get('simpleauth.table_name'))
  338. ->set(array('password' => $password_hash))
  339. ->where('username', '=', $username)
  340. ->execute(\Config::get('simpleauth.db_connection'));
  341. if ( ! $affected_rows)
  342. {
  343. throw new \SimpleUserUpdateException('Failed to reset password, user was invalid.', 8);
  344. }
  345. return $new_password;
  346. }
  347. /**
  348. * Deletes a given user
  349. *
  350. * @param string
  351. * @return bool
  352. */
  353. public function delete_user($username)
  354. {
  355. if (empty($username))
  356. {
  357. throw new \SimpleUserUpdateException('Cannot delete user with empty username', 9);
  358. }
  359. $affected_rows = \DB::delete(\Config::get('simpleauth.table_name'))
  360. ->where('username', '=', $username)
  361. ->execute(\Config::get('simpleauth.db_connection'));
  362. return $affected_rows > 0;
  363. }
  364. /**
  365. * Creates a temporary hash that will validate the current login
  366. *
  367. * @return string
  368. */
  369. public function create_login_hash()
  370. {
  371. if (empty($this->user))
  372. {
  373. throw new \SimpleUserUpdateException('User not logged in, can\'t create login hash.', 10);
  374. }
  375. $last_login = \Date::forge()->get_timestamp();
  376. $login_hash = sha1(\Config::get('simpleauth.login_hash_salt').$this->user['username'].$last_login);
  377. \DB::update(\Config::get('simpleauth.table_name'))
  378. ->set(array('last_login' => $last_login, 'login_hash' => $login_hash))
  379. ->where('username', '=', $this->user['username'])
  380. ->execute(\Config::get('simpleauth.db_connection'));
  381. $this->user['login_hash'] = $login_hash;
  382. return $login_hash;
  383. }
  384. /**
  385. * Get the user's ID
  386. *
  387. * @return Array containing this driver's ID & the user's ID
  388. */
  389. public function get_user_id()
  390. {
  391. if (empty($this->user))
  392. {
  393. return false;
  394. }
  395. return array($this->id, (int) $this->user['id']);
  396. }
  397. /**
  398. * Get the user's groups
  399. *
  400. * @return Array containing the group driver ID & the user's group ID
  401. */
  402. public function get_groups()
  403. {
  404. if (empty($this->user))
  405. {
  406. return false;
  407. }
  408. return array(array('SimpleGroup', $this->user['group']));
  409. }
  410. /**
  411. * Get the user's emailaddress
  412. *
  413. * @return string
  414. */
  415. public function get_email()
  416. {
  417. if (empty($this->user))
  418. {
  419. return false;
  420. }
  421. return $this->user['email'];
  422. }
  423. /**
  424. * Get the user's screen name
  425. *
  426. * @return string
  427. */
  428. public function get_screen_name()
  429. {
  430. if (empty($this->user))
  431. {
  432. return false;
  433. }
  434. return $this->user['username'];
  435. }
  436. /**
  437. * Get the user's profile fields
  438. *
  439. * @return Array
  440. */
  441. public function get_profile_fields($field = null, $default = null)
  442. {
  443. if (empty($this->user))
  444. {
  445. return false;
  446. }
  447. if (isset($this->user['profile_fields']))
  448. {
  449. is_array($this->user['profile_fields']) or $this->user['profile_fields'] = @unserialize($this->user['profile_fields']);
  450. }
  451. else
  452. {
  453. $this->user['profile_fields'] = array();
  454. }
  455. return is_null($field) ? $this->user['profile_fields'] : \Arr::get($this->user['profile_fields'], $field, $default);
  456. }
  457. /**
  458. * Extension of base driver method to default to user group instead of user id
  459. */
  460. public function has_access($condition, $driver = null, $user = null)
  461. {
  462. if (is_null($user))
  463. {
  464. $groups = $this->get_groups();
  465. $user = reset($groups);
  466. }
  467. return parent::has_access($condition, $driver, $user);
  468. }
  469. /**
  470. * Extension of base driver because this supports a guest login when switched on
  471. */
  472. public function guest_login()
  473. {
  474. return \Config::get('simpleauth.guest_login', true);
  475. }
  476. }
  477. // end of file simpleauth.php