02.25 php saved
MartinsAuth
Tags add more
Auth redirect sessio  
Note
Cake1.2 AuthComponent slightly altered to render logins-screen as a requestAction instead of a redirect. The up-side is that expired Sessions behave better IMHO. The down-side is that you can not have a Flash message on the login-screen.
  1. <?php
  2. /* SVN FILE: $Id: auth.php 6311 2008-01-02 06:33:52Z phpnut $ */
  3.  
  4. /**
  5. * Authentication component
  6. *
  7. * Manages user logins and permissions.
  8. *
  9. * PHP versions 4 and 5
  10. *
  11. * CakePHP(tm) :  Rapid Development Framework <http://www.cakephp.org/>
  12. * Copyright 2005-2008, Cake Software Foundation, Inc.
  13. *                1785 E. Sahara Avenue, Suite 490-204
  14. *                Las Vegas, Nevada 89104
  15. *
  16. * Licensed under The MIT License
  17. * Redistributions of files must retain the above copyright notice.
  18. *
  19. * @filesource
  20. * @copyright      Copyright 2005-2008, Cake Software Foundation, Inc.
  21. * @link                http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
  22. * @package   cake
  23. * @subpackage    cake.cake.libs.controller.components
  24. * @since         CakePHP(tm) v 0.10.0.1076
  25. * @version   $Revision: 6311 $
  26. * @modifiedby    $LastChangedBy: phpnut $
  27. * @lastmodified    $Date: 2008-01-02 00:33:52 -0600 (Wed, 02 Jan 2008) $
  28. * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
  29. */
  30.  
  31. uses('set', 'security');
  32.  
  33. /**
  34. * Authentication control component class
  35. *
  36. * Binds access control with user authentication and session management.
  37. *
  38. * @package  cake
  39. * @subpackage  cake.cake.libs.controller.components
  40. */
  41. class AuthComponent extends Object {
  42. /**
  43. * Maintains current user login state.
  44. *
  45. * @var boolean
  46. * @access private
  47. */
  48.     var $_loggedIn = false;
  49. /**
  50. * Other components utilized by AuthComponent
  51. *
  52. * @var array
  53. * @access public
  54. */
  55.     var $components = array('Session', 'RequestHandler');
  56. /**
  57. * A reference to the object used for authentication
  58. *
  59. * @var object
  60. * @access public
  61. */
  62.     var $authenticate = null;
  63. /**
  64. * The name of the component to use for Authorization or set this to
  65. * 'controller' will validate against Controller::isAuthorized()
  66. * 'actions' will validate Controller::action against an AclComponent::check()
  67. * 'crud' will validate mapActions against an AclComponent::check()
  68. * array('model'=> 'name'); will validate mapActions against model $name::isAuthorize(user, controller, mapAction)
  69. * 'object' will validate Controller::action against object::isAuthorized(user, controller, action)
  70. *
  71. * @var mixed
  72. * @access public
  73. */
  74.     var $authorize = false;
  75. /**
  76. * The name of an optional view element to render when an Ajax request is made
  77. * with an invalid or expired session
  78. *
  79. * @var string
  80. * @access public
  81. */
  82.     var $ajaxLogin = null;
  83. /**
  84. * The name of the model that represents users which will be authenticated.  Defaults to 'User'.
  85. *
  86. * @var string
  87. * @access public
  88. */
  89.     var $userModel = 'User';
  90. /**
  91. * Additional query conditions to use when looking up and authenticating users,
  92. * i.e. array('User.is_active' => 1).
  93. *
  94. * @var array
  95. * @access public
  96. */
  97.     var $userScope = array();
  98. /**
  99. * Allows you to specify non-default login name and password fields used in
  100. * $userModel, i.e. array('username' => 'login_name', 'password' => 'passwd').
  101. *
  102. * @var array
  103. * @access public
  104. */
  105.     var $fields = array('username' => 'username', 'password' => 'password');
  106. /**
  107. * The session key name where the record of the current user is stored.  If
  108. * unspecified, it will be "Auth.{$userModel name}".
  109. *
  110. * @var string
  111. * @access public
  112. */
  113.     var $sessionKey = null;
  114. /**
  115. * If using action-based access control, this defines how the paths to action
  116. * ACO nodes is computed.  If, for example, all controller nodes are nested
  117. * under an ACO node named 'Controllers', $actionPath should be set to
  118. * "Controllers/".
  119. *
  120. * @var string
  121. * @access public
  122. */
  123.     var $actionPath = null;
  124. /**
  125. * A URL (defined as a string or array) to the controller action that handles
  126. * logins.
  127. *
  128. * @var mixed
  129. * @access public
  130. */
  131.     var $loginAction = null;
  132. /**
  133. * Normally, if a user is redirected to the $loginAction page, the location they
  134. * were redirected from will be stored in the session so that they can be
  135. * redirected back after a successful login.  If this session value is not
  136. * set, the user will be redirected to the page specified in $loginRedirect.
  137. *
  138. * @var mixed
  139. * @access public
  140. */
  141.     var $loginRedirect = null;
  142. /**
  143. * The the default action to redirect to after the user is logged out.  While AuthComponent does
  144. * not handle post-logout redirection, a redirect URL will be returned from AuthComponent::logout().
  145. * Defaults to AuthComponent::$loginAction.
  146. *
  147. * @var mixed
  148. * @access public
  149. * @see AuthComponent::$loginAction
  150. * @see AuthComponent::logout()
  151. */
  152.     var $logoutRedirect = null;
  153. /**
  154. * The name of model or model object, or any other object has an isAuthorized method.
  155. *
  156. * @var string
  157. * @access public
  158. */
  159.     var $object = null;
  160. /**
  161. * Error to display when user login fails.  For security purposes, only one error is used for all
  162. * login failures, so as not to expose information on why the login failed.
  163. *
  164. * @var string
  165. * @access public
  166. */
  167.     var $loginError = null;
  168. /**
  169. * Error to display when user attempts to access an object or action to which they do not have
  170. * acccess.
  171. *
  172. * @var string
  173. * @access public
  174. */
  175.     var $authError = null;
  176. /**
  177. * Determines whether AuthComponent will automatically redirect and exit if login is successful.
  178. *
  179. * @var boolean
  180. * @access public
  181. */
  182.     var $autoRedirect = true;
  183. /**
  184. * Controller actions for which user validation is not required.
  185. *
  186. * @var array
  187. * @access public
  188. * @see AuthComponent::allow()
  189. */
  190.     var $allowedActions = array();
  191. /**
  192. * Maps actions to CRUD operations.  Used for controller-based validation ($validate = 'controller').
  193. *
  194. * @var array
  195. * @access public
  196. * @see AuthComponent::mapActions()
  197. */
  198.     var $actionMap = array(
  199.         'index'  => 'read',
  200.         'add'      => 'create',
  201.         'edit'    => 'update',
  202.         'view'    => 'read',
  203.         'remove'    => 'delete'
  204.     );
  205. /**
  206. * Form data from Controller::$data
  207. *
  208. * @var array
  209. * @access public
  210. */
  211.     var $data = array();
  212. /**
  213. * Parameter data from Controller::$params
  214. *
  215. * @var array
  216. * @access public
  217. */
  218.     var $params = array();
  219. /**
  220. * Initializes AuthComponent for use in the controller
  221. *
  222. * @param object $controller A reference to the instantiating controller object
  223. * @access public
  224. */
  225.     function initialize(&$controller) {
  226.         $this->params = $controller->params;
  227.         $crud = array('create', 'read', 'update', 'delete');
  228.         $this->actionMap = array_merge($this->actionMap, array_combine($crud, $crud));
  229.  
  230.         $admin = Configure::read('Routing.admin');
  231.         if (!empty($admin)) {
  232.             $this->actionMap = array_merge($this->actionMap, array(
  233.                 $admin . '_index'   => 'read',
  234.                 $admin . '_add'  => 'create',
  235.                 $admin . '_edit'    => 'update',
  236.                 $admin . '_view'    => 'read',
  237.                 $admin . '_remove'  => 'delete',
  238.                 $admin . '_create'  => 'create',
  239.                 $admin . '_read'    => 'read',
  240.                 $admin . '_update'  => 'update',
  241.                 $admin . '_delete'  => 'delete'
  242.             ));
  243.         }
  244.         if (Configure::read() > 0) {
  245.             uses('debugger');
  246.             Debugger::checkSessionKey();
  247.         }
  248.     }
  249. /**
  250. * Main execution method.  Handles redirecting of invalid users, and processing
  251. * of login form data.
  252. *
  253. * @param object $controller A reference to the instantiating controller object
  254. * @access public
  255. */
  256.     function startup(&$controller) {
  257.         if (!$this->loginError) {
  258.             $this->loginError = __('Login failed. Invalid username or password.', true);
  259.         }
  260.  
  261.         if (!$this->authError) {
  262.             $this->authError = __('You are not authorized to access that location.', true);
  263.         }
  264.  
  265.         if (strtolower($controller->name) == 'app' || (strtolower($controller->name) == 'tests' && Configure::read() > 0)) {
  266.             return;
  267.         }
  268.  
  269.         if (!$this->__setDefaults()) {
  270.             return false;
  271.         }
  272.  
  273.         $this->data = $controller->data = $this->hashPasswords($controller->data);
  274.  
  275.         if ($this->allowedActions == array('*') || in_array($controller->action, $this->allowedActions)) {
  276.             return false;
  277.         }
  278.  
  279.         if (!isset($controller->params['url']['url'])) {
  280.             $url = '';
  281.         } else {
  282.             $url = '/'.$controller->params['url']['url'];
  283.         }
  284.  
  285.         $this->loginAction = Router::normalize($this->loginAction);
  286.         if ($this->loginAction == Router::normalize($url)) {
  287.             if (empty($controller->data) || !isset($controller->data[$this->userModel])) {
  288.                 if (!$this->Session->check('Auth.redirect') && env('HTTP_REFERER')) {
  289.                     $this->Session->write('Auth.redirect', $controller->referer());
  290.                 }
  291.                 return false;
  292.             }
  293.  
  294.             $data = array(
  295.                 $this->userModel . '.' . $this->fields['username'] => '= ' . $controller->data[$this->userModel][$this->fields['username']],
  296.                 $this->userModel . '.' . $this->fields['password'] => '= ' . $controller->data[$this->userModel][$this->fields['password']]
  297.             );
  298.  
  299.             if ($this->login($data)) {
  300.                 if ($this->autoRedirect) {
  301.                     if (env('HTTP_REFERER') && ($this->loginAction != $controller->referer()) ) {
  302.                         $controller->redirect($controller->referer(), null, true);
  303.                     } else {
  304.                         $controller->redirect($this->redirect(), null, true);
  305.                     }
  306.                 }
  307.                 return true;
  308.             } else {
  309.                 $this->Session->setFlash($this->loginError, 'default', array(), 'auth');
  310.                 unset($controller->data[$this->userModel][$this->fields['password']]);
  311.             }
  312.             return false;
  313.         } else {
  314.             if (!$this->user()) {
  315.                 if (!$this->RequestHandler->isAjax()) {
  316.                     //$this->Session->setFlash($this->authError, 'default', array(), 'auth');
  317.                     $this->Session->write('Auth.redirect', $url);
  318.                     //$controller->redirect($this->loginAction, null, true);
  319.                     echo $controller->requestAction($this->loginAction, array('bare'=>0,'return') );
  320.                     exit();
  321.                     return false;
  322.                 } elseif (!empty($this->ajaxLogin)) {
  323.                     $controller->viewPath = 'elements';
  324.                     $controller->render($this->ajaxLogin, 'ajax');
  325.                     exit();
  326.                 }
  327.             }
  328.         }
  329.  
  330.         if ($this->authorize) {
  331.             extract($this->__authType());
  332.             switch ($type) {
  333.                 case 'controller':
  334.                     $this->object =& $controller;
  335.                 break;
  336.                 case 'crud':
  337.                 case 'actions':
  338.                     if (isset($controller->Acl)) {
  339.                         $this->Acl =& $controller->Acl;
  340.                     } else {
  341.                         trigger_error(__('Could not find AclComponent. Please include Acl in Controller::$components.', true), E_USER_WARNING);
  342.                     }
  343.                 break;
  344.                 case 'model':
  345.                     if (!isset($object)) {
  346.                         if (isset($controller->{$controller->modelClass}) && is_object($controller->{$controller->modelClass})) {
  347.                             $object = $controller->modelClass;
  348.                         } elseif (!empty($controller->uses) && isset($controller->{$controller->uses[0]}) && is_object($controller->{$controller->uses[0]})) {
  349.                             $object = $controller->uses[0];
  350.                         }
  351.                     }
  352.                     $type = array('model' => $object);
  353.                 break;
  354.             }
  355.  
  356.             if ($this->isAuthorized($type)) {
  357.                 return true;
  358.             }
  359.  
  360.             $this->Session->setFlash($this->authError, 'default', array(), 'auth');
  361.             $controller->redirect($controller->referer(), null, true);
  362.             return false;
  363.         } else {
  364.             return true;
  365.         }
  366.     }
  367. /**
  368. * Attempts to introspect the correct values for object properties including
  369. * $userModel and $sessionKey.
  370. *
  371. * @param object $controller A reference to the instantiating controller object
  372. * @access private
  373. */
  374.     function __setDefaults() {
  375.         if (empty($this->userModel)) {
  376.             trigger_error(__("Could not find \$userModel. Please set AuthComponent::\$userModel in beforeFilter().", true), E_USER_WARNING);
  377.             return false;
  378.         }
  379.         if (empty($this->loginAction)) {
  380.             $this->loginAction = Router::url(array('controller'=> Inflector::underscore(Inflector::pluralize($this->userModel)), 'action'=>'login'));
  381.         }
  382.         if (empty($this->sessionKey)) {
  383.             $this->sessionKey = 'Auth.' . $this->userModel;
  384.         }
  385.         if (empty($this->logoutRedirect)) {
  386.             $this->logoutRedirect = $this->loginAction;
  387.         }
  388.         return true;
  389.     }
  390. /**
  391. * Determines whether the given user is authorized to perform an action.  The type of authorization
  392. * used is based on the value of AuthComponent::$authorize or the passed $type param.
  393. *
  394. * Types:
  395. * 'controller' will validate against Controller::isAuthorized() if controller instance is passed in $object
  396. * 'actions' will validate Controller::action against an AclComponent::check()
  397. * 'crud' will validate mapActions against an AclComponent::check()
  398. * array('model'=> 'name'); will validate mapActions against model $name::isAuthorize(user, controller, mapAction)
  399. * 'object' will validate Controller::action against object::isAuthorized(user, controller, action)
  400. *
  401. * @param string $type Type of authorization
  402. * @param mixed $object object, model object, or model name
  403. * @param mixed $user The user to check the authorization of
  404. * @return boolean True if $user is authorized, otherwise false
  405. * @access public
  406. */
  407.     function isAuthorized($type = null, $object = null, $user = null) {
  408.         if (empty($user) && !$this->user()) {
  409.             return false;
  410.         } elseif (empty($user)) {
  411.             $user = $this->user();
  412.         }
  413.  
  414.         extract($this->__authType($type));
  415.  
  416.         if (!$object) {
  417.             $object = $this->object;
  418.         }
  419.  
  420.         $valid = false;
  421.         switch ($type) {
  422.             case 'controller':
  423.                 $valid = $object->isAuthorized();
  424.             break;
  425.             case 'actions':
  426.                 $valid = $this->Acl->check($user, $this->action());
  427.             break;
  428.             case 'crud':
  429.                 $this->mapActions();
  430.                 if (!isset($this->actionMap[$this->params['action']])) {
  431.                     trigger_error(sprintf(__('Auth::startup() - Attempted access of un-mapped action "%1$s" in controller "%2$s"', true), $this->params['action'], $this->params['controller']), E_USER_WARNING);
  432.                 } else {
  433.                     $valid = $this->Acl->check($user, $this->action(':controller'), $this->actionMap[$this->params['action']]);
  434.                 }
  435.             break;
  436.             case 'model':
  437.                 $this->mapActions();
  438.                 $action = $this->params['action'];
  439.                 if(isset($this->actionMap[$action])) {
  440.                     $action = $this->actionMap[$action];
  441.                 }
  442.                 if (is_string($object)) {
  443.                     $object = $this->getModel($object);
  444.                 }
  445.             case 'object':
  446.                 if (!isset($action)) {
  447.                     $action = $this->action(':action');
  448.                 }
  449.                 if (empty($object)) {
  450.                     trigger_error(sprintf(__('Could not find %s. Set AuthComponent::$object in beforeFilter() or pass a valid object', true), get_class($object)), E_USER_WARNING);
  451.                     return;
  452.                 }
  453.                 if (method_exists($object, 'isAuthorized')) {
  454.                     $valid = $object->isAuthorized($user, $this->action(':controller'), $action);
  455.                 } elseif ($object){
  456.                     trigger_error(sprintf(__('%s::isAuthorized() is not defined.', true), get_class($object)), E_USER_WARNING);
  457.                 }
  458.             break;
  459.             case null:
  460.             case false:
  461.                 return true;
  462.             break;
  463.             default:
  464.                 trigger_error(__('Auth::isAuthorized() - $authorize is set to an incorrect value.  Allowed settings are: "actions", "crud", "model" or null.', true), E_USER_WARNING);
  465.             break;
  466.         }
  467.         return $valid;
  468.     }
  469. /**
  470. * Get authorization type
  471. *
  472. * @param string $auth Type of authorization
  473. * @return array Associative array with: type, object
  474. * @access private
  475. */
  476.     function __authType($auth = null) {
  477.         if ($auth == null) {
  478.             $auth = $this->authorize;
  479.         }
  480.         $object = null;
  481.         if (is_array($auth)) {
  482.             $type = key($auth);
  483.             $object = $auth[$type];
  484.         } else {
  485.             $type = $auth;
  486.             return compact('type');
  487.         }
  488.         return compact('type', 'object');
  489.     }
  490. /**
  491. * Takes a list of actions in the current controller for which authentication is not required, or
  492. * no parameters to allow all actions.
  493. *
  494. * @param string $action Controller action name
  495. * @param string $action Controller action name
  496. * @param string ... etc.
  497. * @access public
  498. */
  499.     function allow() {
  500.         $args = func_get_args();
  501.         if (empty($args)) {
  502.             $this->allowedActions = array('*');
  503.         } else {
  504.             if (isset($args[0]) && is_array($args[0])) {
  505.                 $args = $args[0];
  506.             }
  507.             $this->allowedActions = array_merge($this->allowedActions, $args);
  508.         }
  509.     }
  510. /**
  511. * Removes items from the list of allowed actions.
  512. *
  513. * @param string $action Controller action name
  514. * @param string $action Controller action name
  515. * @param string ... etc.
  516. * @see AuthComponent::allow()
  517. * @access public
  518. */
  519.     function deny() {
  520.         $args = func_get_args();
  521.         foreach ($args as $arg) {
  522.             $i = array_search($arg, $this->allowedActions);
  523.             if (is_int($i)) {
  524.                 unset($this->allowedActions[$i]);
  525.             }
  526.         }
  527.         $this->allowedActions = array_values($this->allowedActions);
  528.     }
  529. /**
  530. * Maps action names to CRUD operations. Used for controller-based authentication.
  531. *
  532. * @param array $map Actions to map
  533. * @access public
  534. */
  535.     function mapActions($map = array()) {
  536.         $crud = array('create', 'read', 'update', 'delete');
  537.         foreach ($map as $action => $type) {
  538.             if (in_array($action, $crud) && is_array($type)) {
  539.                 foreach ($type as $typedAction) {
  540.                     $this->actionMap[$typedAction] = $action;
  541.                 }
  542.             } else {
  543.                 $this->actionMap[$action] = $type;
  544.             }
  545.         }
  546.     }
  547. /**
  548. * Manually log-in a user with the given parameter data.  The $data provided can be any data
  549. * structure used to identify a user in AuthComponent::identify().  If $data is empty or not
  550. * specified, POST data from Controller::$data will be used automatically.
  551. *
  552. * After (if) login is successful, the user record is written to the session key specified in
  553. * AuthComponent::$sessionKey.
  554. *
  555. * @param mixed $data User object
  556. * @return boolean True on login success, false on failure
  557. * @access public
  558. */
  559.     function login($data = null) {
  560.         $this->__setDefaults();
  561.         $this->_loggedIn = false;
  562.  
  563.         if (empty($data)) {
  564.             $data = $this->data;
  565.         }
  566.  
  567.         if ($user = $this->identify($data)) {
  568.             $this->Session->write($this->sessionKey, $user);
  569.             $this->_loggedIn = true;
  570.         }
  571.         return $this->_loggedIn;
  572.     }
  573. /**
  574. * Logs a user out, and returns the login action to redirect to.
  575. *
  576. * @param mixed $url Optional URL to redirect the user to after logout
  577. * @return string AuthComponent::$loginAction
  578. * @see AuthComponent::$loginAction
  579. * @access public
  580. */
  581.     function logout() {
  582.         $this->__setDefaults();
  583.         $this->Session->del($this->sessionKey);
  584.         $this->Session->del('Auth.redirect');
  585.         $this->_loggedIn = false;
  586.         return Router::normalize($this->logoutRedirect);
  587.     }
  588. /**
  589. * Get the current user from the session.
  590. *
  591. * @return array User record, or null if no user is logged in.
  592. * @access public
  593. */
  594.     function user($key = null) {
  595.         $this->__setDefaults();
  596.         if (!$this->Session->check($this->sessionKey)) {
  597.             return null;
  598.         }
  599.  
  600.         if ($key == null) {
  601.             return array($this->userModel => $this->Session->read($this->sessionKey));
  602.         } else {
  603.             $user = $this->Session->read($this->sessionKey);
  604.             if (isset($user[$key])) {
  605.                 return $user[$key];
  606.             } else {
  607.                 return null;
  608.             }
  609.         }
  610.     }
  611. /**
  612. * If no parameter is passed, gets the authentication redirect URL.
  613. *
  614. * @param mixed $url Optional URL to write as the login redirect URL.
  615. * @return string Redirect URL
  616. * @access public
  617. */
  618.     function redirect($url = null) {
  619.         if (!is_null($url)) {
  620.             return $this->Session->write('Auth.redirect', $url);
  621.         }
  622.         if ($this->Session->check('Auth.redirect')) {
  623.             $redir = $this->Session->read('Auth.redirect');
  624.             $this->Session->delete('Auth.redirect');
  625.             if (Router::normalize($redir) == $this->loginAction) {
  626.                 $redir = $this->loginRedirect;
  627.             }
  628.         } else {
  629.             $redir = $this->loginRedirect;
  630.         }
  631.         return Router::normalize($redir);
  632.     }
  633. /**
  634. * Validates a user against an abstract object.
  635. *
  636. * @param mixed $object  The object to validate the user against.
  637. * @param mixed $user    Optional.  The identity of the user to be validated.
  638. *                       Uses the current user session if none specified.  For
  639. *                       valid forms of identifying users, see
  640. *                       AuthComponent::identify().
  641. * @param string $action Optional. The action to validate against.
  642. * @see AuthComponent::identify()
  643. * @return boolean True if the user validates, false otherwise.
  644. * @access public
  645. */
  646.     function validate($object, $user = null, $action = null) {
  647.         if (empty($user)) {
  648.             $user = $this->user();
  649.         }
  650.         if (empty($user)) {
  651.             return false;
  652.         }
  653.         return $this->Acl->check($user, $object, $action);
  654.     }
  655. /**
  656. * Returns the path to the ACO node bound to a controller/action.
  657. *
  658. * @param string $action  Optional.  The controller/action path to validate the
  659. *                        user against.  The current request action is used if
  660. *                        none is specified.
  661. * @return boolean ACO node path
  662. * @access public
  663. */
  664.     function action($action = ':controller/:action') {
  665.         return str_replace(
  666.             array(':controller', ':action'),
  667.             array(Inflector::camelize($this->params['controller']), $this->params['action']),
  668.             $this->actionPath . $action
  669.         );
  670.     }
  671. /**
  672. * Returns a reference to the model object specified, and attempts
  673. * to load it if it is not found.
  674. *
  675. * @param string $name Model name (defaults to AuthComponent::$userModel)
  676. * @return object A reference to a model object
  677. * @access public
  678. */
  679.     function &getModel($name = null) {
  680.         $model = null;
  681.         if (!$name) {
  682.             $name = $this->userModel;
  683.         }
  684.  
  685.         if (PHP5) {
  686.             $model = ClassRegistry::init($name);
  687.         } else {
  688.             $model =& ClassRegistry::init($name);
  689.         }
  690.  
  691.         if (empty($model)) {
  692.             trigger_error(__('Auth::getModel() - Model is not set or could not be found', true), E_USER_WARNING);
  693.             return null;
  694.         }
  695.  
  696.         return $model;
  697.     }
  698. /**
  699. * Identifies a user based on specific criteria.
  700. *
  701. * @param mixed $user Optional. The identity of the user to be validated.
  702. *              Uses the current user session if none specified.
  703. * @param array $conditions Optional. Additional conditions to a find.
  704. * @return array User record data, or null, if the user could not be identified.
  705. * @access public