AuthComponent.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. <?php
  2. /**
  3. * Authentication component
  4. *
  5. * Manages user logins and permissions.
  6. *
  7. * PHP 5
  8. *
  9. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  10. * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. *
  12. * Licensed under The MIT License
  13. * Redistributions of files must retain the above copyright notice.
  14. *
  15. * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
  16. * @link http://cakephp.org CakePHP(tm) Project
  17. * @package cake
  18. * @subpackage cake.cake.libs.controller.components
  19. * @since CakePHP(tm) v 0.10.0.1076
  20. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  21. */
  22. App::uses('Router', 'Routing');
  23. App::uses('Security', 'Core');
  24. App::uses('Debugger', 'Utility');
  25. /**
  26. * Authentication control component class
  27. *
  28. * Binds access control with user authentication and session management.
  29. *
  30. * @package cake
  31. * @subpackage cake.cake.libs.controller.components
  32. * @link http://book.cakephp.org/view/1250/Authentication
  33. */
  34. class AuthComponent extends Component {
  35. /**
  36. * Maintains current user login state.
  37. *
  38. * @var boolean
  39. */
  40. protected $_loggedIn = false;
  41. /**
  42. * Other components utilized by AuthComponent
  43. *
  44. * @var array
  45. */
  46. public $components = array('Session', 'RequestHandler');
  47. /**
  48. * A reference to the object used for authentication
  49. *
  50. * @var object
  51. * @link http://book.cakephp.org/view/1278/authenticate
  52. */
  53. public $authenticate = null;
  54. /**
  55. * The name of the component to use for Authorization or set this to
  56. * 'controller' will validate against Controller::isAuthorized()
  57. * 'actions' will validate Controller::action against an AclComponent::check()
  58. * 'crud' will validate mapActions against an AclComponent::check()
  59. * array('model'=> 'name'); will validate mapActions against model $name::isAuthorized(user, controller, mapAction)
  60. * 'object' will validate Controller::action against object::isAuthorized(user, controller, action)
  61. *
  62. * @var mixed
  63. * @link http://book.cakephp.org/view/1275/authorize
  64. */
  65. public $authorize = false;
  66. /**
  67. * The name of an optional view element to render when an Ajax request is made
  68. * with an invalid or expired session
  69. *
  70. * @var string
  71. * @link http://book.cakephp.org/view/1277/ajaxLogin
  72. */
  73. public $ajaxLogin = null;
  74. /**
  75. * The name of the element used for SessionComponent::setFlash
  76. *
  77. * @var string
  78. */
  79. public $flashElement = 'default';
  80. /**
  81. * The name of the model that represents users which will be authenticated. Defaults to 'User'.
  82. *
  83. * @var string
  84. * @link http://book.cakephp.org/view/1266/userModel
  85. */
  86. public $userModel = 'User';
  87. /**
  88. * Additional query conditions to use when looking up and authenticating users,
  89. * i.e. array('User.is_active' => 1).
  90. *
  91. * @var array
  92. * @link http://book.cakephp.org/view/1268/userScope
  93. */
  94. public $userScope = array();
  95. /**
  96. * Allows you to specify non-default login name and password fields used in
  97. * $userModel, i.e. array('username' => 'login_name', 'password' => 'passwd').
  98. *
  99. * @var array
  100. * @link http://book.cakephp.org/view/1267/fields
  101. */
  102. public $fields = array('username' => 'username', 'password' => 'password');
  103. /**
  104. * The session key name where the record of the current user is stored. If
  105. * unspecified, it will be "Auth.{$userModel name}".
  106. *
  107. * @var string
  108. * @link http://book.cakephp.org/view/1276/sessionKey
  109. */
  110. public $sessionKey = null;
  111. /**
  112. * If using action-based access control, this defines how the paths to action
  113. * ACO nodes is computed. If, for example, all controller nodes are nested
  114. * under an ACO node named 'Controllers', $actionPath should be set to
  115. * "Controllers/".
  116. *
  117. * @var string
  118. * @link http://book.cakephp.org/view/1279/actionPath
  119. */
  120. public $actionPath = null;
  121. /**
  122. * A URL (defined as a string or array) to the controller action that handles
  123. * logins.
  124. *
  125. * @var mixed
  126. * @link http://book.cakephp.org/view/1269/loginAction
  127. */
  128. public $loginAction = null;
  129. /**
  130. * Normally, if a user is redirected to the $loginAction page, the location they
  131. * were redirected from will be stored in the session so that they can be
  132. * redirected back after a successful login. If this session value is not
  133. * set, the user will be redirected to the page specified in $loginRedirect.
  134. *
  135. * @var mixed
  136. * @link http://book.cakephp.org/view/1270/loginRedirect
  137. */
  138. public $loginRedirect = null;
  139. /**
  140. * The default action to redirect to after the user is logged out. While AuthComponent does
  141. * not handle post-logout redirection, a redirect URL will be returned from AuthComponent::logout().
  142. * Defaults to AuthComponent::$loginAction.
  143. *
  144. * @var mixed
  145. * @see AuthComponent::$loginAction
  146. * @see AuthComponent::logout()
  147. * @link http://book.cakephp.org/view/1271/logoutRedirect
  148. */
  149. public $logoutRedirect = null;
  150. /**
  151. * The name of model or model object, or any other object has an isAuthorized method.
  152. *
  153. * @var string
  154. */
  155. public $object = null;
  156. /**
  157. * Error to display when user login fails. For security purposes, only one error is used for all
  158. * login failures, so as not to expose information on why the login failed.
  159. *
  160. * @var string
  161. * @link http://book.cakephp.org/view/1272/loginError
  162. */
  163. public $loginError = null;
  164. /**
  165. * Error to display when user attempts to access an object or action to which they do not have
  166. * acccess.
  167. *
  168. * @var string
  169. * @link http://book.cakephp.org/view/1273/authError
  170. */
  171. public $authError = null;
  172. /**
  173. * Determines whether AuthComponent will automatically redirect and exit if login is successful.
  174. *
  175. * @var boolean
  176. * @link http://book.cakephp.org/view/1274/autoRedirect
  177. */
  178. public $autoRedirect = true;
  179. /**
  180. * Controller actions for which user validation is not required.
  181. *
  182. * @var array
  183. * @see AuthComponent::allow()
  184. * @link http://book.cakephp.org/view/1251/Setting-Auth-Component-Variables
  185. */
  186. public $allowedActions = array();
  187. /**
  188. * Maps actions to CRUD operations. Used for controller-based validation ($validate = 'controller').
  189. *
  190. * @var array
  191. * @see AuthComponent::mapActions()
  192. */
  193. public $actionMap = array(
  194. 'index' => 'read',
  195. 'add' => 'create',
  196. 'edit' => 'update',
  197. 'view' => 'read',
  198. 'remove' => 'delete'
  199. );
  200. /**
  201. * Request object
  202. *
  203. * @var CakeRequest
  204. */
  205. public $request;
  206. /**
  207. * Form data from Controller::$data
  208. *
  209. * @deprecated Use $this->request->data instead
  210. * @var array
  211. */
  212. public $data = array();
  213. /**
  214. * Parameter data from Controller::$params
  215. *
  216. * @deprecated Use $this->request instead
  217. * @var array
  218. */
  219. public $params = array();
  220. /**
  221. * AclComponent instance if using Acl + Auth
  222. *
  223. * @var AclComponent
  224. */
  225. public $Acl;
  226. /**
  227. * Method list for bound controller
  228. *
  229. * @var array
  230. */
  231. protected $_methods = array();
  232. /**
  233. * Initializes AuthComponent for use in the controller
  234. *
  235. * @param object $controller A reference to the instantiating controller object
  236. * @return void
  237. */
  238. public function initialize(Controller $controller, $settings = array()) {
  239. $this->request = $controller->request;
  240. $this->params = $this->request;
  241. $crud = array('create', 'read', 'update', 'delete');
  242. $this->actionMap = array_merge($this->actionMap, array_combine($crud, $crud));
  243. $this->_methods = $controller->methods;
  244. $prefixes = Router::prefixes();
  245. if (!empty($prefixes)) {
  246. foreach ($prefixes as $prefix) {
  247. $this->actionMap = array_merge($this->actionMap, array(
  248. $prefix . '_index' => 'read',
  249. $prefix . '_add' => 'create',
  250. $prefix . '_edit' => 'update',
  251. $prefix . '_view' => 'read',
  252. $prefix . '_remove' => 'delete',
  253. $prefix . '_create' => 'create',
  254. $prefix . '_read' => 'read',
  255. $prefix . '_update' => 'update',
  256. $prefix . '_delete' => 'delete'
  257. ));
  258. }
  259. }
  260. if (Configure::read('debug') > 0) {
  261. Debugger::checkSecurityKeys();
  262. }
  263. }
  264. /**
  265. * Main execution method. Handles redirecting of invalid users, and processing
  266. * of login form data.
  267. *
  268. * @param object $controller A reference to the instantiating controller object
  269. * @return boolean
  270. */
  271. public function startup(&$controller) {
  272. $isErrorOrTests = (
  273. strtolower($controller->name) == 'cakeerror' ||
  274. (strtolower($controller->name) == 'tests' && Configure::read('debug') > 0)
  275. );
  276. if ($isErrorOrTests) {
  277. return true;
  278. }
  279. $methods = array_flip($controller->methods);
  280. $action = $controller->request->params['action'];
  281. $isMissingAction = (
  282. $controller->scaffold === false &&
  283. !isset($methods[$action])
  284. );
  285. if ($isMissingAction) {
  286. return true;
  287. }
  288. if (!$this->__setDefaults()) {
  289. return false;
  290. }
  291. $request = $controller->request;
  292. $this->request->data = $controller->request->data = $this->hashPasswords($request->data);
  293. $url = '';
  294. if (isset($request->query['url'])) {
  295. $url = $request->query['url'];
  296. }
  297. $url = Router::normalize($url);
  298. $loginAction = Router::normalize($this->loginAction);
  299. $allowedActions = $this->allowedActions;
  300. $isAllowed = (
  301. $this->allowedActions == array('*') ||
  302. in_array($action, $allowedActions)
  303. );
  304. if ($loginAction != $url && $isAllowed) {
  305. return true;
  306. }
  307. if ($loginAction == $url) {
  308. $model = $this->getModel();
  309. if (empty($request->data) || !isset($request->data[$model->alias])) {
  310. if (!$this->Session->check('Auth.redirect') && !$this->loginRedirect && env('HTTP_REFERER')) {
  311. $this->Session->write('Auth.redirect', $controller->referer(null, true));
  312. }
  313. return false;
  314. }
  315. $isValid = !empty($request->data[$model->alias][$this->fields['username']]) &&
  316. !empty($request->data[$model->alias][$this->fields['password']]);
  317. if ($isValid) {
  318. $username = $request->data[$model->alias][$this->fields['username']];
  319. $password = $request->data[$model->alias][$this->fields['password']];
  320. $data = array(
  321. $model->alias . '.' . $this->fields['username'] => $username,
  322. $model->alias . '.' . $this->fields['password'] => $password
  323. );
  324. if ($this->login($data)) {
  325. if ($this->autoRedirect) {
  326. $controller->redirect($this->redirect(), null, true);
  327. }
  328. return true;
  329. }
  330. }
  331. $this->Session->setFlash($this->loginError, $this->flashElement, array(), 'auth');
  332. $request->data[$model->alias][$this->fields['password']] = null;
  333. return false;
  334. } else {
  335. if (!$this->user()) {
  336. if (!$request->is('ajax')) {
  337. $this->Session->setFlash($this->authError, $this->flashElement, array(), 'auth');
  338. if (!empty($request->query) && count($request->query) >= 2) {
  339. $query = $request->query;
  340. unset($query['url'], $query['ext']);
  341. $url .= Router::queryString($query, array());
  342. }
  343. $this->Session->write('Auth.redirect', $url);
  344. $controller->redirect($loginAction);
  345. return false;
  346. } elseif (!empty($this->ajaxLogin)) {
  347. $controller->viewPath = 'elements';
  348. echo $controller->render($this->ajaxLogin, $this->RequestHandler->ajaxLayout);
  349. $this->_stop();
  350. return false;
  351. } else {
  352. $controller->redirect(null, 403);
  353. }
  354. }
  355. }
  356. if (!$this->authorize) {
  357. return true;
  358. }
  359. extract($this->__authType());
  360. switch ($type) {
  361. case 'controller':
  362. $this->object = $controller;
  363. break;
  364. case 'crud':
  365. case 'actions':
  366. if (isset($controller->Acl)) {
  367. $this->Acl = $controller->Acl;
  368. } else {
  369. trigger_error(__('Could not find AclComponent. Please include Acl in Controller::$components.'), E_USER_WARNING);
  370. }
  371. break;
  372. case 'model':
  373. if (!isset($object)) {
  374. $hasModel = (
  375. isset($controller->{$controller->modelClass}) &&
  376. is_object($controller->{$controller->modelClass})
  377. );
  378. $isUses = (
  379. !empty($controller->uses) && isset($controller->{$controller->uses[0]}) &&
  380. is_object($controller->{$controller->uses[0]})
  381. );
  382. if ($hasModel) {
  383. $object = $controller->modelClass;
  384. } elseif ($isUses) {
  385. $object = $controller->uses[0];
  386. }
  387. }
  388. $type = array('model' => $object);
  389. break;
  390. }
  391. if ($this->isAuthorized($type)) {
  392. return true;
  393. }
  394. $this->Session->setFlash($this->authError, $this->flashElement, array(), 'auth');
  395. $controller->redirect($controller->referer(), null, true);
  396. return false;
  397. }
  398. /**
  399. * Attempts to introspect the correct values for object properties including
  400. * $userModel and $sessionKey.
  401. *
  402. * @param object $controller A reference to the instantiating controller object
  403. * @return boolean
  404. * @access private
  405. */
  406. function __setDefaults() {
  407. if (empty($this->userModel)) {
  408. trigger_error(__("Could not find \$userModel. Please set AuthComponent::\$userModel in beforeFilter()."), E_USER_WARNING);
  409. return false;
  410. }
  411. list($plugin, $model) = pluginSplit($this->userModel);
  412. $defaults = array(
  413. 'loginAction' => array(
  414. 'controller' => Inflector::underscore(Inflector::pluralize($model)),
  415. 'action' => 'login',
  416. 'plugin' => Inflector::underscore($plugin),
  417. ),
  418. 'sessionKey' => 'Auth.' . $model,
  419. 'logoutRedirect' => $this->loginAction,
  420. 'loginError' => __('Login failed. Invalid username or password.'),
  421. 'authError' => __('You are not authorized to access that location.')
  422. );
  423. foreach ($defaults as $key => $value) {
  424. if (empty($this->{$key})) {
  425. $this->{$key} = $value;
  426. }
  427. }
  428. return true;
  429. }
  430. /**
  431. * Determines whether the given user is authorized to perform an action. The type of
  432. * authorization used is based on the value of AuthComponent::$authorize or the
  433. * passed $type param.
  434. *
  435. * Types:
  436. * 'controller' will validate against Controller::isAuthorized() if controller instance is
  437. * passed in $object
  438. * 'actions' will validate Controller::action against an AclComponent::check()
  439. * 'crud' will validate mapActions against an AclComponent::check()
  440. * array('model'=> 'name'); will validate mapActions against model
  441. * $name::isAuthorized(user, controller, mapAction)
  442. * 'object' will validate Controller::action against
  443. * object::isAuthorized(user, controller, action)
  444. *
  445. * @param string $type Type of authorization
  446. * @param mixed $object object, model object, or model name
  447. * @param mixed $user The user to check the authorization of
  448. * @return boolean True if $user is authorized, otherwise false
  449. */
  450. public function isAuthorized($type = null, $object = null, $user = null) {
  451. if (empty($user) && !$this->user()) {
  452. return false;
  453. } elseif (empty($user)) {
  454. $user = $this->user();
  455. }
  456. extract($this->__authType($type));
  457. if (!$object) {
  458. $object = $this->object;
  459. }
  460. $valid = false;
  461. switch ($type) {
  462. case 'controller':
  463. $valid = $object->isAuthorized();
  464. break;
  465. case 'actions':
  466. $valid = $this->Acl->check($user, $this->action());
  467. break;
  468. case 'crud':
  469. if (!isset($this->actionMap[$this->request['action']])) {
  470. trigger_error(
  471. sprintf(__('Auth::startup() - Attempted access of un-mapped action "%1$s" in controller "%2$s"'), $this->request['action'], $this->request['controller']),
  472. E_USER_WARNING
  473. );
  474. } else {
  475. $valid = $this->Acl->check(
  476. $user,
  477. $this->action(':controller'),
  478. $this->actionMap[$this->request['action']]
  479. );
  480. }
  481. break;
  482. case 'model':
  483. $action = $this->request['action'];
  484. if (isset($this->actionMap[$action])) {
  485. $action = $this->actionMap[$action];
  486. }
  487. if (is_string($object)) {
  488. $object = $this->getModel($object);
  489. }
  490. case 'object':
  491. if (!isset($action)) {
  492. $action = $this->action(':action');
  493. }
  494. if (empty($object)) {
  495. trigger_error(sprintf(__('Could not find %s. Set AuthComponent::$object in beforeFilter() or pass a valid object'), get_class($object)), E_USER_WARNING);
  496. return;
  497. }
  498. if (method_exists($object, 'isAuthorized')) {
  499. $valid = $object->isAuthorized($user, $this->action(':controller'), $action);
  500. } elseif ($object) {
  501. trigger_error(sprintf(__('%s::isAuthorized() is not defined.'), get_class($object)), E_USER_WARNING);
  502. }
  503. break;
  504. case null:
  505. case false:
  506. return true;
  507. break;
  508. default:
  509. trigger_error(__('Auth::isAuthorized() - $authorize is set to an incorrect value. Allowed settings are: "actions", "crud", "model" or null.'), E_USER_WARNING);
  510. break;
  511. }
  512. return $valid;
  513. }
  514. /**
  515. * Get authorization type
  516. *
  517. * @param string $auth Type of authorization
  518. * @return array Associative array with: type, object
  519. * @access private
  520. */
  521. function __authType($auth = null) {
  522. if ($auth == null) {
  523. $auth = $this->authorize;
  524. }
  525. $object = null;
  526. if (is_array($auth)) {
  527. $type = key($auth);
  528. $object = $auth[$type];
  529. } else {
  530. $type = $auth;
  531. return compact('type');
  532. }
  533. return compact('type', 'object');
  534. }
  535. /**
  536. * Takes a list of actions in the current controller for which authentication is not required, or
  537. * no parameters to allow all actions.
  538. *
  539. * @param mixed $action Controller action name or array of actions
  540. * @param string $action Controller action name
  541. * @param string ... etc.
  542. * @return void
  543. * @link http://book.cakephp.org/view/1257/allow
  544. */
  545. public function allow() {
  546. $args = func_get_args();
  547. if (empty($args) || $args == array('*')) {
  548. $this->allowedActions = $this->_methods;
  549. } else {
  550. if (isset($args[0]) && is_array($args[0])) {
  551. $args = $args[0];
  552. }
  553. $this->allowedActions = array_merge($this->allowedActions, $args);
  554. }
  555. }
  556. /**
  557. * Removes items from the list of allowed actions.
  558. *
  559. * @param mixed $action Controller action name or array of actions
  560. * @param string $action Controller action name
  561. * @param string ... etc.
  562. * @return void
  563. * @see AuthComponent::allow()
  564. * @link http://book.cakephp.org/view/1258/deny
  565. */
  566. public function deny() {
  567. $args = func_get_args();
  568. if (isset($args[0]) && is_array($args[0])) {
  569. $args = $args[0];
  570. }
  571. foreach ($args as $arg) {
  572. $i = array_search($arg, $this->allowedActions);
  573. if (is_int($i)) {
  574. unset($this->allowedActions[$i]);
  575. }
  576. }
  577. $this->allowedActions = array_values($this->allowedActions);
  578. }
  579. /**
  580. * Maps action names to CRUD operations. Used for controller-based authentication.
  581. *
  582. * @param array $map Actions to map
  583. * @return void
  584. * @link http://book.cakephp.org/view/1260/mapActions
  585. */
  586. public function mapActions($map = array()) {
  587. $crud = array('create', 'read', 'update', 'delete');
  588. foreach ($map as $action => $type) {
  589. if (in_array($action, $crud) && is_array($type)) {
  590. foreach ($type as $typedAction) {
  591. $this->actionMap[$typedAction] = $action;
  592. }
  593. } else {
  594. $this->actionMap[$action] = $type;
  595. }
  596. }
  597. }
  598. /**
  599. * Manually log-in a user with the given parameter data. The $data provided can be any data
  600. * structure used to identify a user in AuthComponent::identify(). If $data is empty or not
  601. * specified, POST data from Controller::$data will be used automatically.
  602. *
  603. * After (if) login is successful, the user record is written to the session key specified in
  604. * AuthComponent::$sessionKey.
  605. *
  606. * @param mixed $data User object
  607. * @return boolean True on login success, false on failure
  608. * @link http://book.cakephp.org/view/1261/login
  609. */
  610. public function login($data = null) {
  611. $this->__setDefaults();
  612. $this->_loggedIn = false;
  613. if (empty($data)) {
  614. $data = $this->data;
  615. }
  616. if ($user = $this->identify($data)) {
  617. $this->Session->write($this->sessionKey, $user);
  618. $this->_loggedIn = true;
  619. }
  620. return $this->_loggedIn;
  621. }
  622. /**
  623. * Logs a user out, and returns the login action to redirect to.
  624. *
  625. * @param mixed $url Optional URL to redirect the user to after logout
  626. * @return string AuthComponent::$loginAction
  627. * @see AuthComponent::$loginAction
  628. * @link http://book.cakephp.org/view/1262/logout
  629. */
  630. public function logout() {
  631. $this->__setDefaults();
  632. $this->Session->delete($this->sessionKey);
  633. $this->Session->delete('Auth.redirect');
  634. $this->_loggedIn = false;
  635. return Router::normalize($this->logoutRedirect);
  636. }
  637. /**
  638. * Get the current user from the session.
  639. *
  640. * @param string $key field to retrive. Leave null to get entire User record
  641. * @return mixed User record. or null if no user is logged in.
  642. * @link http://book.cakephp.org/view/1264/user
  643. */
  644. public function user($key = null) {
  645. $this->__setDefaults();
  646. if (!$this->Session->check($this->sessionKey)) {
  647. return null;
  648. }
  649. if ($key == null) {
  650. $model = $this->getModel();
  651. return array($model->alias => $this->Session->read($this->sessionKey));
  652. } else {
  653. $user = $this->Session->read($this->sessionKey);
  654. if (isset($user[$key])) {
  655. return $user[$key];
  656. }
  657. return null;
  658. }
  659. }
  660. /**
  661. * If no parameter is passed, gets the authentication redirect URL.
  662. *
  663. * @param mixed $url Optional URL to write as the login redirect URL.
  664. * @return string Redirect URL
  665. */
  666. public function redirect($url = null) {
  667. if (!is_null($url)) {
  668. $redir = $url;
  669. $this->Session->write('Auth.redirect', $redir);
  670. } elseif ($this->Session->check('Auth.redirect')) {
  671. $redir = $this->Session->read('Auth.redirect');
  672. $this->Session->delete('Auth.redirect');
  673. if (Router::normalize($redir) == Router::normalize($this->loginAction)) {
  674. $redir = $this->loginRedirect;
  675. }
  676. } else {
  677. $redir = $this->loginRedirect;
  678. }
  679. return Router::normalize($redir);
  680. }
  681. /**
  682. * Validates a user against an abstract object.
  683. *
  684. * @param mixed $object The object to validate the user against.
  685. * @param mixed $user Optional. The identity of the user to be validated.
  686. * Uses the current user session if none specified. For
  687. * valid forms of identifying users, see
  688. * AuthComponent::identify().
  689. * @param string $action Optional. The action to validate against.
  690. * @see AuthComponent::identify()
  691. * @return boolean True if the user validates, false otherwise.
  692. */
  693. public function validate($object, $user = null, $action = null) {
  694. if (empty($user)) {
  695. $user = $this->user();
  696. }
  697. if (empty($user)) {
  698. return false;
  699. }
  700. return $this->Acl->check($user, $object, $action);
  701. }
  702. /**
  703. * Returns the path to the ACO node bound to a controller/action.
  704. *
  705. * @param string $action Optional. The controller/action path to validate the
  706. * user against. The current request action is used if
  707. * none is specified.
  708. * @return boolean ACO node path
  709. * @link http://book.cakephp.org/view/1256/action
  710. */
  711. public function action($action = ':plugin/:controller/:action') {
  712. $plugin = empty($this->request['plugin']) ? null : Inflector::camelize($this->request['plugin']) . '/';
  713. return str_replace(
  714. array(':controller', ':action', ':plugin/'),
  715. array(Inflector::camelize($this->request['controller']), $this->request['action'], $plugin),
  716. $this->actionPath . $action
  717. );
  718. }
  719. /**
  720. * Returns a reference to the model object specified, and attempts
  721. * to load it if it is not found.
  722. *
  723. * @param string $name Model name (defaults to AuthComponent::$userModel)
  724. * @return object A reference to a model object
  725. */
  726. public function &getModel($name = null) {
  727. $model = null;
  728. if (!$name) {
  729. $name = $this->userModel;
  730. }
  731. $model = ClassRegistry::init($name);
  732. if (empty($model)) {
  733. trigger_error(__('Auth::getModel() - Model is not set or could not be found'), E_USER_WARNING);
  734. return null;
  735. }
  736. return $model;
  737. }
  738. /**
  739. * Identifies a user based on specific criteria.
  740. *
  741. * @param mixed $user Optional. The identity of the user to be validated.
  742. * Uses the current user session if none specified.
  743. * @param array $conditions Optional. Additional conditions to a find.
  744. * @return array User record data, or null, if the user could not be identified.
  745. */
  746. public function identify($user = null, $conditions = null) {
  747. if ($conditions === false) {
  748. $conditions = null;
  749. } elseif (is_array($conditions)) {
  750. $conditions = array_merge((array)$this->userScope, $conditions);
  751. } else {
  752. $conditions = $this->userScope;
  753. }
  754. $model = $this->getModel();
  755. if (empty($user)) {
  756. $user = $this->user();
  757. if (empty($user)) {
  758. return null;
  759. }
  760. } elseif (is_object($user) && is_a($user, 'Model')) {
  761. if (!$user->exists()) {
  762. return null;
  763. }
  764. $user = $user->read();
  765. $user = $user[$model->alias];
  766. } elseif (is_array($user) && isset($user[$model->alias])) {
  767. $user = $user[$model->alias];
  768. }
  769. if (is_array($user) && (isset($user[$this->fields['username']]) || isset($user[$model->alias . '.' . $this->fields['username']]))) {
  770. if (isset($user[$this->fields['username']]) && !empty($user[$this->fields['username']]) && !empty($user[$this->fields['password']])) {
  771. if (trim($user[$this->fields['username']]) == '=' || trim($user[$this->fields['password']]) == '=') {
  772. return false;
  773. }
  774. $find = array(
  775. $model->alias.'.'.$this->fields['username'] => $user[$this->fields['username']],
  776. $model->alias.'.'.$this->fields['password'] => $user[$this->fields['password']]
  777. );
  778. } elseif (isset($user[$model->alias . '.' . $this->fields['username']]) && !empty($user[$model->alias . '.' . $this->fields['username']])) {
  779. if (trim($user[$model->alias . '.' . $this->fields['username']]) == '=' || trim($user[$model->alias . '.' . $this->fields['password']]) == '=') {
  780. return false;
  781. }
  782. $find = array(
  783. $model->alias.'.'.$this->fields['username'] => $user[$model->alias . '.' . $this->fields['username']],
  784. $model->alias.'.'.$this->fields['password'] => $user[$model->alias . '.' . $this->fields['password']]
  785. );
  786. } else {
  787. return false;
  788. }
  789. $data = $model->find('first', array(
  790. 'conditions' => array_merge($find, $conditions),
  791. 'recursive' => 0
  792. ));
  793. if (empty($data) || empty($data[$model->alias])) {
  794. return null;
  795. }
  796. } elseif (!empty($user) && is_string($user)) {
  797. $data = $model->find('first', array(
  798. 'conditions' => array_merge(array($model->escapeField() => $user), $conditions),
  799. ));
  800. if (empty($data) || empty($data[$model->alias])) {
  801. return null;
  802. }
  803. }
  804. if (!empty($data)) {
  805. if (!empty($data[$model->alias][$this->fields['password']])) {
  806. unset($data[$model->alias][$this->fields['password']]);
  807. }
  808. return $data[$model->alias];
  809. }
  810. return null;
  811. }
  812. /**
  813. * Hash any passwords found in $data using $userModel and $fields['password']
  814. *
  815. * @param array $data Set of data to look for passwords
  816. * @return array Data with passwords hashed
  817. * @link http://book.cakephp.org/view/1259/hashPasswords
  818. */
  819. public function hashPasswords($data) {
  820. if (is_object($this->authenticate) && method_exists($this->authenticate, 'hashPasswords')) {
  821. return $this->authenticate->hashPasswords($data);
  822. }
  823. if (is_array($data)) {
  824. $model = $this->getModel();
  825. if(isset($data[$model->alias])) {
  826. if (isset($data[$model->alias][$this->fields['username']]) && isset($data[$model->alias][$this->fields['password']])) {
  827. $data[$model->alias][$this->fields['password']] = $this->password($data[$model->alias][$this->fields['password']]);
  828. }
  829. }
  830. }
  831. return $data;
  832. }
  833. /**
  834. * Hash a password with the application's salt value (as defined with Configure::write('Security.salt');
  835. *
  836. * @param string $password Password to hash
  837. * @return string Hashed password
  838. * @link http://book.cakephp.org/view/1263/password
  839. */
  840. public function password($password) {
  841. return Security::hash($password, null, true);
  842. }
  843. /**
  844. * Component shutdown. If user is logged in, wipe out redirect.
  845. *
  846. * @param object $controller Instantiating controller
  847. */
  848. public function shutdown(&$controller) {
  849. if ($this->_loggedIn) {
  850. $this->Session->delete('Auth.redirect');
  851. }
  852. }
  853. /**
  854. * Sets or gets whether the user is logged in
  855. *
  856. * @param boolean $logged sets the status of the user, true to logged in, false to logged out
  857. * @return boolean true if the user is logged in, false otherwise
  858. * @access public
  859. */
  860. public function loggedIn($logged = null) {
  861. if (!is_null($logged)) {
  862. $this->_loggedIn = $logged;
  863. }
  864. return $this->_loggedIn;
  865. }
  866. }