PageRenderTime 75ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 0ms

/bundles/sentry/sentry.php

https://bitbucket.org/wadep_ascensor/cffc-document-manager
PHP | 614 lines | 327 code | 84 blank | 203 comment | 40 complexity | cb0b7299390b6df27f2e7424fdd42014 MD5 | raw file
  1. <?php
  2. /**
  3. * Part of the Sentry bundle for Laravel.
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * Licensed under the 3-clause BSD License.
  8. *
  9. * This source file is subject to the 3-clause BSD License that is
  10. * bundled with this package in the LICENSE file. It is also available at
  11. * the following URL: http://www.opensource.org/licenses/BSD-3-Clause
  12. *
  13. * @package Sentry
  14. * @version 1.0
  15. * @author Cartalyst LLC
  16. * @license BSD License (3-clause)
  17. * @copyright (c) 2011 - 2012, Cartalyst LLC
  18. * @link http://cartalyst.com
  19. */
  20. namespace Sentry;
  21. use Config;
  22. use Cookie;
  23. use DB;
  24. use Request;
  25. use Session;
  26. use Lang;
  27. use Str;
  28. class SentryException extends \Exception {}
  29. class SentryConfigException extends SentryException {}
  30. /**
  31. * Sentry Auth class
  32. */
  33. class Sentry
  34. {
  35. /**
  36. * @var string Database instance
  37. */
  38. protected static $db_instance = null;
  39. /**
  40. * @var string Holds the column to use for login
  41. */
  42. protected static $login_column = null;
  43. /**
  44. * @var bool Whether suspension feature should be used or not
  45. */
  46. protected static $suspend = null;
  47. /**
  48. * @var Sentry_Attempts Holds the Sentry_Attempts object
  49. */
  50. protected static $attempts = null;
  51. /**
  52. * @var object Caches the current logged in user object
  53. */
  54. protected static $current_user = null;
  55. /**
  56. * @var array Caches all users accessed
  57. */
  58. protected static $user_cache = array();
  59. /**
  60. * Prevent instantiation
  61. */
  62. final private function __construct() {}
  63. /**
  64. * Run when class is loaded
  65. *
  66. * @return void
  67. */
  68. public static function _init()
  69. {
  70. // set static vars for later use
  71. static::$login_column = trim(Config::get('sentry::sentry.login_column'));
  72. static::$suspend = trim(Config::get('sentry::sentry.limit.enabled'));
  73. $db_instance = trim(Config::get('sentry::sentry.db_instance'));
  74. // db_instance check
  75. if ( ! empty($db_instance) )
  76. {
  77. static::$db_instance = $db_instance;
  78. }
  79. // login_column check
  80. if (empty(static::$login_column))
  81. {
  82. throw new SentryConfigException(__('sentry::sentry.login_column_empty'));
  83. }
  84. }
  85. /**
  86. * Get's either the currently logged in user or the specified user by id or Login
  87. * Column value.
  88. *
  89. * @param int|string User id or Login Column value to find.
  90. * @throws SentryException
  91. * @return Sentry_User
  92. */
  93. public static function user($id = null, $recache = false)
  94. {
  95. if ($id === null and $recache === false and static::$current_user !== null)
  96. {
  97. return static::$current_user;
  98. }
  99. elseif ($id !== null and $recache === false and isset(static::$user_cache[$id]))
  100. {
  101. return static::$user_cache[$id];
  102. }
  103. try
  104. {
  105. if ($id)
  106. {
  107. static::$user_cache[$id] = new Sentry_User($id);
  108. return static::$user_cache[$id];
  109. }
  110. // if session exists - default to user session
  111. elseif (static::check())
  112. {
  113. $user_id = Session::get(Config::get('sentry::sentry.session.user'));
  114. static::$current_user = new Sentry_User($user_id);
  115. return static::$current_user;
  116. }
  117. // else return empty user
  118. return new Sentry_User();
  119. }
  120. catch (SentryUserException $e)
  121. {
  122. throw new SentryException($e->getMessage());
  123. }
  124. }
  125. /**
  126. * Get's either the currently logged in user's group object or the
  127. * specified group by id or name.
  128. *
  129. * @param int|string Group id or or name
  130. * @return Sentry_User
  131. */
  132. public static function group($id = null)
  133. {
  134. if ($id)
  135. {
  136. return new Sentry_Group($id);
  137. }
  138. return new Sentry_Group();
  139. }
  140. /**
  141. * Gets the Sentry_Attempts object
  142. *
  143. * @return Sentry_Attempts
  144. */
  145. public static function attempts($login_id = null, $ip_address = null)
  146. {
  147. return new Sentry_Attempts($login_id, $ip_address);
  148. }
  149. /**
  150. * Attempt to log a user in.
  151. *
  152. * @param string Login column value
  153. * @param string Password entered
  154. * @param bool Whether to remember the user or not
  155. * @return bool
  156. * @throws SentryException
  157. */
  158. public static function login($login_column_value, $password, $remember = false)
  159. {
  160. // log the user out if they hit the login page
  161. static::logout();
  162. // get login attempts
  163. if (static::$suspend)
  164. {
  165. $attempts = static::attempts($login_column_value, Request::ip());
  166. // if attempts > limit - suspend the login/ip combo
  167. if ($attempts->get() >= $attempts->get_limit())
  168. {
  169. try
  170. {
  171. $attempts->suspend();
  172. }
  173. catch(SentryUserSuspendedException $e)
  174. {
  175. throw new SentryException($e->getMessage());
  176. }
  177. }
  178. }
  179. // make sure vars have values
  180. if (empty($login_column_value) or empty($password))
  181. {
  182. return false;
  183. }
  184. // if user is validated
  185. if ($user = static::validate_user($login_column_value, $password, 'password'))
  186. {
  187. if (static::$suspend)
  188. {
  189. // clear attempts for login since they got in
  190. $attempts->clear();
  191. }
  192. // set update array
  193. $update = array();
  194. // if they wish to be remembers, set the cookie and get the hash
  195. if ($remember)
  196. {
  197. $update['remember_me'] = static::remember($login_column_value);
  198. }
  199. // if there is a password reset hash and user logs in - remove the password reset
  200. if ($user->get('password_reset_hash'))
  201. {
  202. $update['password_reset_hash'] = '';
  203. $update['temp_password'] = '';
  204. }
  205. $update['last_login'] = static::sql_timestamp();
  206. $update['ip_address'] = Request::ip();
  207. // update user
  208. if (count($update))
  209. {
  210. $user->update($update, false);
  211. }
  212. // set session vars
  213. Session::put(Config::get('sentry::sentry.session.user'), (int) $user->get('id'));
  214. Session::put(Config::get('sentry::sentry.session.provider'), 'Sentry');
  215. return true;
  216. }
  217. return false;
  218. }
  219. /**
  220. * Force Login
  221. *
  222. * @param int|string user id or login value
  223. * @param provider what system was used to force the login
  224. * @return bool
  225. * @throws SentryException
  226. */
  227. public static function force_login($id, $provider = 'Sentry-Forced')
  228. {
  229. // check to make sure user exists
  230. if ( ! static::user_exists($id))
  231. {
  232. throw new SentryException(__('sentry::sentry.user_not_found'));
  233. }
  234. if ( ! is_int($id))
  235. {
  236. $id = static::user($id)->get('id');
  237. }
  238. Session::put(Config::get('sentry::sentry.session.user'), $id);
  239. Session::put(Config::get('sentry::sentry.session.provider'), $provider);
  240. return true;
  241. }
  242. /**
  243. * Checks if the current user is logged in.
  244. *
  245. * @return bool
  246. */
  247. public static function check()
  248. {
  249. // get session
  250. $user_id = Session::get(Config::get('sentry::sentry.session.user'));
  251. // invalid session values - kill the user session
  252. if ($user_id === null or ! is_numeric($user_id))
  253. {
  254. // if they are not logged in - check for cookie and log them in
  255. if (static::is_remembered())
  256. {
  257. return true;
  258. }
  259. //else log out
  260. static::logout();
  261. return false;
  262. }
  263. return true;
  264. }
  265. /**
  266. * Logs the current user out. Also invalidates the Remember Me setting.
  267. *
  268. * @return void
  269. */
  270. public static function logout()
  271. {
  272. Cookie::forget(Config::get('sentry::sentry.remember_me.cookie_name'));
  273. Session::forget(Config::get('sentry::sentry.session.user'));
  274. Session::forget(Config::get('sentry::sentry.session.provider'));
  275. }
  276. /**
  277. * Activate a user account
  278. *
  279. * @param string Encoded Login Column value
  280. * @param string User's activation code
  281. * @return bool|array
  282. * @throws SentryException
  283. */
  284. public static function activate_user($login_column_value, $code, $decode = true)
  285. {
  286. // decode login column
  287. if ($decode)
  288. {
  289. $login_column_value = base64_decode($login_column_value);
  290. }
  291. // make sure vars have values
  292. if (empty($login_column_value) or empty($code))
  293. {
  294. return false;
  295. }
  296. // if user is validated
  297. if ($user = static::validate_user($login_column_value, $code, 'activation_hash'))
  298. {
  299. // update pass to temp pass, reset temp pass and hash
  300. $user->update(array(
  301. 'activation_hash' => '',
  302. 'activated' => 1
  303. ), false);
  304. return $user;
  305. }
  306. return false;
  307. }
  308. /**
  309. * Starts the reset password process. Generates the necessary password
  310. * reset hash and returns the new user array. Password reset confirm
  311. * still needs called.
  312. *
  313. * @param string Login Column value
  314. * @param string User's new password
  315. * @return bool|array
  316. * @throws SentryException
  317. */
  318. public static function reset_password($login_column_value, $password)
  319. {
  320. // make sure a user id is set
  321. if (empty($login_column_value) or empty($password))
  322. {
  323. return false;
  324. }
  325. // check if user exists
  326. $user = static::user($login_column_value);
  327. // create a hash for reset_password link
  328. $hash = Str::random(24);
  329. // set update values
  330. $update = array(
  331. 'password_reset_hash' => $hash,
  332. 'temp_password' => $password,
  333. 'remember_me' => '',
  334. );
  335. // if database was updated return confirmation data
  336. if ($user->update($update))
  337. {
  338. $update = array(
  339. 'email' => $user->get('email'),
  340. 'password_reset_hash' => $hash,
  341. 'link' => base64_encode($login_column_value).'/'.$update['password_reset_hash']
  342. );
  343. return $update;
  344. }
  345. else
  346. {
  347. return false;
  348. }
  349. }
  350. /**
  351. * Confirms a password reset code against the database.
  352. *
  353. * @param string Login Column value
  354. * @param string Reset password code
  355. * @return bool
  356. * @throws SentryException
  357. */
  358. public static function reset_password_confirm($login_column_value, $code, $decode = true)
  359. {
  360. // decode login column
  361. if ($decode)
  362. {
  363. $login_column_value = base64_decode($login_column_value);
  364. }
  365. // make sure vars have values
  366. if (empty($login_column_value) or empty($code))
  367. {
  368. return false;
  369. }
  370. if (static::$suspend)
  371. {
  372. // get login attempts
  373. $attempts = static::attempts($login_column_value, Request::ip());
  374. // if attempts > limit - suspend the login/ip combo
  375. if ($attempts->get() >= $attempts->get_limit())
  376. {
  377. $attempts->suspend();
  378. }
  379. }
  380. // if user is validated
  381. if ($user = static::validate_user($login_column_value, $code, 'password_reset_hash'))
  382. {
  383. // update pass to temp pass, reset temp pass and hash
  384. $user->update(array(
  385. 'password' => $user->get('temp_password'),
  386. 'password_reset_hash' => '',
  387. 'temp_password' => '',
  388. 'remember_me' => '',
  389. ), false);
  390. return true;
  391. }
  392. return false;
  393. }
  394. /**
  395. * Checks if a user exists by Login Column value
  396. *
  397. * @param string|id Login column value or Id
  398. * @return bool
  399. */
  400. public static function user_exists($login_column_value)
  401. {
  402. try
  403. {
  404. $user = new Sentry_User($login_column_value, true);
  405. if ($user)
  406. {
  407. return true;
  408. }
  409. // this should never happen
  410. return false;
  411. }
  412. catch (SentryUserException $e)
  413. {
  414. return false;
  415. }
  416. }
  417. /**
  418. * Checks if the group exists
  419. *
  420. * @param string|int Group name|Group id
  421. * @return bool
  422. */
  423. public static function group_exists($group)
  424. {
  425. try
  426. {
  427. $group_exists = new Sentry_Group($group, true);
  428. if ($group_exists)
  429. {
  430. return true;
  431. }
  432. // this should never happen
  433. return false;
  434. }
  435. catch(SentryException $e)
  436. {
  437. $group_exists = false;
  438. }
  439. }
  440. /**
  441. * Remember User Login
  442. *
  443. * @param int
  444. */
  445. protected static function remember($login_column)
  446. {
  447. // generate random string for cookie password
  448. $cookie_pass = Str::random(24);
  449. // create and encode string
  450. $cookie_string = base64_encode($login_column.':'.$cookie_pass);
  451. // set cookie
  452. Cookie::put(
  453. Config::get('sentry::sentry.remember_me.cookie_name'),
  454. $cookie_string,
  455. Config::get('sentry::sentry.remember_me.expire')
  456. );
  457. return $cookie_pass;
  458. }
  459. /**
  460. * Check if remember me is set and valid
  461. */
  462. protected static function is_remembered()
  463. {
  464. $encoded_val = Cookie::get(Config::get('sentry::sentry.remember_me.cookie_name'));
  465. if ($encoded_val)
  466. {
  467. $val = base64_decode($encoded_val);
  468. list($login_column, $hash) = explode(':', $val);
  469. // if user is validated
  470. if ($user = static::validate_user($login_column, $hash, 'remember_me'))
  471. {
  472. // update last login
  473. $user->update(array(
  474. 'last_login' => static::sql_timestamp(),
  475. ));
  476. // set session vars
  477. Session::put(Config::get('sentry::sentry.session.user'), (int) $user->get('id'));
  478. Session::put(Config::get('sentry::sentry.session.provider'), 'Sentry');
  479. return true;
  480. }
  481. static::logout();
  482. return false;
  483. }
  484. return false;
  485. }
  486. /**
  487. * Validates a Login and Password. This takes a password type so it can be
  488. * used to validate password reset hashes as well.
  489. *
  490. * @param string Login column value
  491. * @param string Password to validate with
  492. * @param string Field name (password type)
  493. * @return bool|Sentry_User
  494. */
  495. protected static function validate_user($login_column_value, $password, $field)
  496. {
  497. // get user
  498. $user = static::user($login_column_value);
  499. // check activation status
  500. if ($user->activated != 1 and $field != 'activation_hash')
  501. {
  502. throw new SentryException(__('sentry::sentry.account_not_activated'));
  503. }
  504. // check user status
  505. if ($user->status != 1)
  506. {
  507. throw new SentryException(__('sentry::sentry.account_is_disabled'));
  508. }
  509. // check password
  510. if ( ! $user->check_password($password, $field))
  511. {
  512. if (static::$suspend and ($field == 'password' or $field == 'password_reset_hash'))
  513. {
  514. static::attempts($login_column_value, Request::ip())->add();
  515. }
  516. return false;
  517. }
  518. return $user;
  519. }
  520. /**
  521. * Returns an SQL timestamp appropriate
  522. * for the currect database driver.
  523. *
  524. * @return string
  525. */
  526. protected static function sql_timestamp()
  527. {
  528. return date(DB::connection(static::$db_instance)->grammar()->grammar->datetime);
  529. }
  530. }