PageRenderTime 25ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/libs/Nette/Web/User.php

https://github.com/PJK/Nette-Exceptions---Independent-Components
PHP | 461 lines | 219 code | 108 blank | 134 comment | 28 complexity | e200ca309431741745ffb9867782bb48 MD5 | raw file
  1. <?php
  2. /**
  3. * Nette Framework
  4. *
  5. * @copyright Copyright (c) 2004, 2010 David Grudl
  6. * @license http://nette.org/license Nette license
  7. * @link http://nette.org
  8. * @category Nette
  9. * @package Nette\Web
  10. */
  11. namespace Nette\Web;
  12. use Nette,
  13. Nette\Environment,
  14. Nette\Security\IAuthenticator,
  15. Nette\Security\IAuthorizator,
  16. Nette\Security\IIdentity;
  17. /**
  18. * User authentication and authorization.
  19. *
  20. * @copyright Copyright (c) 2004, 2010 David Grudl
  21. * @package Nette\Web
  22. *
  23. * @property-read Nette\Security\IIdentity $identity
  24. * @property Nette\Security\IAuthenticator $authenticationHandler
  25. * @property Nette\Security\IAuthorizator $authorizationHandler
  26. * @property-read int $logoutReason
  27. * @property-read array $roles
  28. * @property-read bool $authenticated
  29. */
  30. class User extends Nette\Object implements IUser
  31. {
  32. /**#@+ log-out reason {@link User::getLogoutReason()} */
  33. const MANUAL = 1;
  34. const INACTIVITY = 2;
  35. const BROWSER_CLOSED = 3;
  36. /**#@-*/
  37. /** @var string default role for unauthenticated user */
  38. public $guestRole = 'guest';
  39. /** @var string default role for authenticated user without own identity */
  40. public $authenticatedRole = 'authenticated';
  41. /** @var array of function(User $sender); Occurs when the user is successfully logged in */
  42. public $onLoggedIn;
  43. /** @var array of function(User $sender); Occurs when the user is logged out */
  44. public $onLoggedOut;
  45. /** @var Nette\Security\IAuthenticator */
  46. private $authenticationHandler;
  47. /** @var Nette\Security\IAuthorizator */
  48. private $authorizationHandler;
  49. /** @var string */
  50. private $namespace = '';
  51. /** @var SessionNamespace */
  52. private $session;
  53. /********************* Authentication ****************d*g**/
  54. /**
  55. * Conducts the authentication process. Parameters are optional.
  56. * @param mixed optional parameter (e.g. username)
  57. * @param mixed optional parameter (e.g. password)
  58. * @return void
  59. * @throws Nette\Security\AuthenticationException if authentication was not successful
  60. */
  61. public function login($username = NULL, $password = NULL)
  62. {
  63. $handler = $this->getAuthenticationHandler();
  64. if ($handler === NULL) {
  65. throw new \InvalidStateException('Authentication handler has not been set.');
  66. }
  67. $this->logout(TRUE);
  68. $credentials = func_get_args();
  69. $this->setIdentity($handler->authenticate($credentials));
  70. $this->setAuthenticated(TRUE);
  71. $this->onLoggedIn($this);
  72. }
  73. /**
  74. * Logs out the user from the current session.
  75. * @param bool clear the identity from persistent storage?
  76. * @return void
  77. */
  78. final public function logout($clearIdentity = FALSE)
  79. {
  80. if ($this->isLoggedIn()) {
  81. $this->setAuthenticated(FALSE);
  82. $this->onLoggedOut($this);
  83. }
  84. if ($clearIdentity) {
  85. $this->setIdentity(NULL);
  86. }
  87. }
  88. /**
  89. * Is this user authenticated?
  90. * @return bool
  91. */
  92. final public function isLoggedIn()
  93. {
  94. $session = $this->getSessionNamespace(FALSE);
  95. return $session && $session->authenticated;
  96. }
  97. /**
  98. * Returns current user identity, if any.
  99. * @return Nette\Security\IIdentity
  100. */
  101. final public function getIdentity()
  102. {
  103. $session = $this->getSessionNamespace(FALSE);
  104. return $session ? $session->identity : NULL;
  105. }
  106. /**
  107. * Returns current user ID, if any.
  108. * @return mixed
  109. */
  110. public function getId()
  111. {
  112. $identity = $this->getIdentity();
  113. return $identity ? $identity->getId() : NULL;
  114. }
  115. /**
  116. * Sets authentication handler.
  117. * @param Nette\Security\IAuthenticator
  118. * @return User provides a fluent interface
  119. */
  120. public function setAuthenticationHandler(IAuthenticator $handler)
  121. {
  122. $this->authenticationHandler = $handler;
  123. return $this;
  124. }
  125. /**
  126. * Returns authentication handler.
  127. * @return Nette\Security\IAuthenticator
  128. */
  129. final public function getAuthenticationHandler()
  130. {
  131. if ($this->authenticationHandler === NULL) {
  132. $this->authenticationHandler = Environment::getService('Nette\\Security\\IAuthenticator');
  133. }
  134. return $this->authenticationHandler;
  135. }
  136. /**
  137. * Changes namespace; allows more users to share a session.
  138. * @param string
  139. * @return User provides a fluent interface
  140. */
  141. public function setNamespace($namespace)
  142. {
  143. if ($this->namespace !== $namespace) {
  144. $this->namespace = (string) $namespace;
  145. $this->session = NULL;
  146. }
  147. return $this;
  148. }
  149. /**
  150. * Returns current namespace.
  151. * @return string
  152. */
  153. final public function getNamespace()
  154. {
  155. return $this->namespace;
  156. }
  157. /**
  158. * Enables log out after inactivity.
  159. * @param string|int|DateTime number of seconds or timestamp
  160. * @param bool log out when the browser is closed?
  161. * @param bool clear the identity from persistent storage?
  162. * @return User provides a fluent interface
  163. */
  164. public function setExpiration($time, $whenBrowserIsClosed = TRUE, $clearIdentity = FALSE)
  165. {
  166. $session = $this->getSessionNamespace(TRUE);
  167. if ($time) {
  168. $time = Nette\Tools::createDateTime($time)->format('U');
  169. $session->expireTime = $time;
  170. $session->expireDelta = $time - time();
  171. } else {
  172. unset($session->expireTime, $session->expireDelta);
  173. }
  174. $session->expireIdentity = (bool) $clearIdentity;
  175. $session->expireBrowser = (bool) $whenBrowserIsClosed;
  176. $session->browserCheck = TRUE;
  177. $session->setExpiration(0, 'browserCheck');
  178. return $this;
  179. }
  180. /**
  181. * Why was user logged out?
  182. * @return int
  183. */
  184. final public function getLogoutReason()
  185. {
  186. $session = $this->getSessionNamespace(FALSE);
  187. return $session ? $session->reason : NULL;
  188. }
  189. /**
  190. * Returns and initializes $this->session.
  191. * @return SessionNamespace
  192. */
  193. protected function getSessionNamespace($need)
  194. {
  195. if ($this->session !== NULL) {
  196. return $this->session;
  197. }
  198. $sessionHandler = $this->getSession();
  199. if (!$need && !$sessionHandler->exists()) {
  200. return NULL;
  201. }
  202. $this->session = $session = $sessionHandler->getNamespace('Nette.Web.User/' . $this->namespace);
  203. if (!($session->identity instanceof IIdentity) || !is_bool($session->authenticated)) {
  204. $session->remove();
  205. }
  206. if ($session->authenticated && $session->expireBrowser && !$session->browserCheck) { // check if browser was closed?
  207. $session->reason = self::BROWSER_CLOSED;
  208. $session->authenticated = FALSE;
  209. $this->onLoggedOut($this);
  210. if ($session->expireIdentity) {
  211. unset($session->identity);
  212. }
  213. }
  214. if ($session->authenticated && $session->expireDelta > 0) { // check time expiration
  215. if ($session->expireTime < time()) {
  216. $session->reason = self::INACTIVITY;
  217. $session->authenticated = FALSE;
  218. $this->onLoggedOut($this);
  219. if ($session->expireIdentity) {
  220. unset($session->identity);
  221. }
  222. }
  223. $session->expireTime = time() + $session->expireDelta; // sliding expiration
  224. }
  225. if (!$session->authenticated) {
  226. unset($session->expireTime, $session->expireDelta, $session->expireIdentity,
  227. $session->expireBrowser, $session->browserCheck, $session->authTime);
  228. }
  229. return $this->session;
  230. }
  231. /**
  232. * Sets the authenticated status of this user.
  233. * @param bool flag indicating the authenticated status of user
  234. * @return User provides a fluent interface
  235. */
  236. protected function setAuthenticated($state)
  237. {
  238. $session = $this->getSessionNamespace(TRUE);
  239. $session->authenticated = (bool) $state;
  240. // Session Fixation defence
  241. $this->getSession()->regenerateId();
  242. if ($state) {
  243. $session->reason = NULL;
  244. $session->authTime = time(); // informative value
  245. } else {
  246. $session->reason = self::MANUAL;
  247. $session->authTime = NULL;
  248. }
  249. return $this;
  250. }
  251. /**
  252. * Sets the user identity.
  253. * @param IIdentity
  254. * @return User provides a fluent interface
  255. */
  256. protected function setIdentity(IIdentity $identity = NULL)
  257. {
  258. $this->getSessionNamespace(TRUE)->identity = $identity;
  259. return $this;
  260. }
  261. /********************* Authorization ****************d*g**/
  262. /**
  263. * Returns a list of effective roles that a user has been granted.
  264. * @return array
  265. */
  266. public function getRoles()
  267. {
  268. if (!$this->isLoggedIn()) {
  269. return array($this->guestRole);
  270. }
  271. $identity = $this->getIdentity();
  272. return $identity ? $identity->getRoles() : array($this->authenticatedRole);
  273. }
  274. /**
  275. * Is a user in the specified effective role?
  276. * @param string
  277. * @return bool
  278. */
  279. final public function isInRole($role)
  280. {
  281. return in_array($role, $this->getRoles(), TRUE);
  282. }
  283. /**
  284. * Has a user effective access to the Resource?
  285. * If $resource is NULL, then the query applies to all resources.
  286. * @param string resource
  287. * @param string privilege
  288. * @return bool
  289. */
  290. public function isAllowed($resource = IAuthorizator::ALL, $privilege = IAuthorizator::ALL)
  291. {
  292. $handler = $this->getAuthorizationHandler();
  293. if (!$handler) {
  294. throw new \InvalidStateException("Authorization handler has not been set.");
  295. }
  296. foreach ($this->getRoles() as $role) {
  297. if ($handler->isAllowed($role, $resource, $privilege)) return TRUE;
  298. }
  299. return FALSE;
  300. }
  301. /**
  302. * Sets authorization handler.
  303. * @param Nette\Security\IAuthorizator
  304. * @return User provides a fluent interface
  305. */
  306. public function setAuthorizationHandler(IAuthorizator $handler)
  307. {
  308. $this->authorizationHandler = $handler;
  309. return $this;
  310. }
  311. /**
  312. * Returns current authorization handler.
  313. * @return Nette\Security\IAuthorizator
  314. */
  315. final public function getAuthorizationHandler()
  316. {
  317. if ($this->authorizationHandler === NULL) {
  318. $this->authorizationHandler = Environment::getService('Nette\\Security\\IAuthorizator');
  319. }
  320. return $this->authorizationHandler;
  321. }
  322. /********************* backend ****************d*g**/
  323. /**
  324. * Returns session handler.
  325. * @return Nette\Web\Session
  326. */
  327. protected function getSession()
  328. {
  329. return Environment::getSession();
  330. }
  331. /**#@+ @deprecated */
  332. function authenticate($username, $password, $extra = NULL)
  333. {
  334. trigger_error(__METHOD__ . '() is deprecated; use login() instead.', E_USER_WARNING);
  335. return $this->login($username, $password, $extra);
  336. }
  337. function signOut($clearIdentity = FALSE)
  338. {
  339. trigger_error(__METHOD__ . '() is deprecated; use logout() instead.', E_USER_WARNING);
  340. return $this->logout($clearIdentity);
  341. }
  342. function isAuthenticated()
  343. {
  344. trigger_error(__METHOD__ . '() is deprecated; use isLoggedIn() instead.', E_USER_WARNING);
  345. return $this->isLoggedIn();
  346. }
  347. function getSignOutReason()
  348. {
  349. trigger_error(__METHOD__ . '() is deprecated; use getLogoutReason() instead.', E_USER_WARNING);
  350. return $this->getLogoutReason();
  351. }
  352. /**#@-*/
  353. }