1: <?php
  2: 
  3:   4:   5:   6:   7:   8:   9:  10: 
 11: 
 12: namespace Nette\Web;
 13: 
 14: use Nette,
 15:     Nette\Environment,
 16:     Nette\Security\IAuthenticator,
 17:     Nette\Security\IAuthorizator,
 18:     Nette\Security\IIdentity;
 19: 
 20: 
 21: 
 22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33: 
 34: class User extends Nette\Object implements IUser
 35: {
 36:     
 37:     const MANUAL = 1;
 38:     const INACTIVITY = 2;
 39:     const BROWSER_CLOSED = 3;
 40:     
 41: 
 42:     
 43:     public $guestRole = 'guest';
 44: 
 45:     
 46:     public $authenticatedRole = 'authenticated';
 47: 
 48:     
 49:     public $onLoggedIn;
 50: 
 51:     
 52:     public $onLoggedOut;
 53: 
 54:     
 55:     public $onAuthenticated;
 56: 
 57:     
 58:     public $onSignedOut;
 59: 
 60:     
 61:     private $authenticationHandler;
 62: 
 63:     
 64:     private $authorizationHandler;
 65: 
 66:     
 67:     private $namespace = '';
 68: 
 69:     
 70:     private $session;
 71: 
 72: 
 73: 
 74:     public function __construct()
 75:     {
 76:         
 77:         $this->onLoggedIn = & $this->onAuthenticated;
 78:         $this->onLoggedOut = & $this->onSignedOut;
 79:     }
 80: 
 81: 
 82: 
 83:     
 84: 
 85: 
 86: 
 87:      88:  89:  90:  91:  92:  93:  94: 
 95:     public function login($username, $password, $extra = NULL)
 96:     {
 97:         $handler = $this->getAuthenticationHandler();
 98:         if ($handler === NULL) {
 99:             throw new \InvalidStateException('Authentication handler has not been set.');
100:         }
101: 
102:         $this->logout(TRUE);
103: 
104:         $credentials = array(
105:             IAuthenticator::USERNAME => $username,
106:             IAuthenticator::PASSWORD => $password,
107:             'extra' => $extra,
108:         );
109: 
110:         $this->setIdentity($handler->authenticate($credentials));
111:         $this->setAuthenticated(TRUE);
112:         $this->onLoggedIn($this);
113:     }
114: 
115: 
116: 
117:     118: 119: 120: 121: 
122:     final public function logout($clearIdentity = FALSE)
123:     {
124:         if ($this->isLoggedIn()) {
125:             $this->setAuthenticated(FALSE);
126:             $this->onLoggedOut($this);
127:         }
128: 
129:         if ($clearIdentity) {
130:             $this->setIdentity(NULL);
131:         }
132:     }
133: 
134: 
135: 
136:     137: 138: 139: 
140:     final public function isLoggedIn()
141:     {
142:         $session = $this->getSessionNamespace(FALSE);
143:         return $session && $session->authenticated;
144:     }
145: 
146: 
147: 
148:     149: 150: 151: 
152:     final public function getIdentity()
153:     {
154:         $session = $this->getSessionNamespace(FALSE);
155:         return $session ? $session->identity : NULL;
156:     }
157: 
158: 
159: 
160:     161: 162: 163: 164: 
165:     public function setAuthenticationHandler(IAuthenticator $handler)
166:     {
167:         $this->authenticationHandler = $handler;
168:         return $this;
169:     }
170: 
171: 
172: 
173:     174: 175: 176: 
177:     final public function getAuthenticationHandler()
178:     {
179:         if ($this->authenticationHandler === NULL) {
180:             $this->authenticationHandler = Environment::getService('Nette\\Security\\IAuthenticator');
181:         }
182:         return $this->authenticationHandler;
183:     }
184: 
185: 
186: 
187:     188: 189: 190: 191: 
192:     public function setNamespace($namespace)
193:     {
194:         if ($this->namespace !== $namespace) {
195:             $this->namespace = (string) $namespace;
196:             $this->session = NULL;
197:         }
198:         return $this;
199:     }
200: 
201: 
202: 
203:     204: 205: 206: 
207:     final public function getNamespace()
208:     {
209:         return $this->namespace;
210:     }
211: 
212: 
213: 
214:     215: 216: 217: 218: 219: 220: 
221:     public function setExpiration($time, $whenBrowserIsClosed = TRUE, $clearIdentity = FALSE)
222:     {
223:         $session = $this->getSessionNamespace(TRUE);
224:         if ($time) {
225:             $time = Nette\DateTime::from($time)->format('U');
226:             $session->expireTime = $time;
227:             $session->expireDelta = $time - time();
228: 
229:         } else {
230:             unset($session->expireTime, $session->expireDelta);
231:         }
232: 
233:         $session->expireIdentity = (bool) $clearIdentity;
234:         $session->expireBrowser = (bool) $whenBrowserIsClosed;
235:         $session->browserCheck = TRUE;
236:         $session->setExpiration(0, 'browserCheck');
237:         return $this;
238:     }
239: 
240: 
241: 
242:     243: 244: 245: 
246:     final public function getLogoutReason()
247:     {
248:         $session = $this->getSessionNamespace(FALSE);
249:         return $session ? $session->reason : NULL;
250:     }
251: 
252: 
253: 
254:     255: 256: 257: 
258:     protected function getSessionNamespace($need)
259:     {
260:         if ($this->session !== NULL) {
261:             return $this->session;
262:         }
263: 
264:         $sessionHandler = $this->getSession();
265:         if (!$need && !$sessionHandler->exists()) {
266:             return NULL;
267:         }
268: 
269:         $this->session = $session = $sessionHandler->getNamespace('Nette.Web.User/' . $this->namespace);
270: 
271:         if (!($session->identity instanceof IIdentity) || !is_bool($session->authenticated)) {
272:             $session->remove();
273:         }
274: 
275:         if ($session->authenticated && $session->expireBrowser && !$session->browserCheck) { 
276:             $session->reason = self::BROWSER_CLOSED;
277:             $session->authenticated = FALSE;
278:             $this->onLoggedOut($this);
279:             if ($session->expireIdentity) {
280:                 unset($session->identity);
281:             }
282:         }
283: 
284:         if ($session->authenticated && $session->expireDelta > 0) { 
285:             if ($session->expireTime < time()) {
286:                 $session->reason = self::INACTIVITY;
287:                 $session->authenticated = FALSE;
288:                 $this->onLoggedOut($this);
289:                 if ($session->expireIdentity) {
290:                     unset($session->identity);
291:                 }
292:             }
293:             $session->expireTime = time() + $session->expireDelta; 
294:         }
295: 
296:         if (!$session->authenticated) {
297:             unset($session->expireTime, $session->expireDelta, $session->expireIdentity,
298:                 $session->expireBrowser, $session->browserCheck, $session->authTime);
299:         }
300: 
301:         return $this->session;
302:     }
303: 
304: 
305: 
306:     307: 308: 309: 310: 
311:     protected function setAuthenticated($state)
312:     {
313:         $session = $this->getSessionNamespace(TRUE);
314:         $session->authenticated = (bool) $state;
315: 
316:         
317:         $this->getSession()->regenerateId();
318: 
319:         if ($state) {
320:             $session->reason = NULL;
321:             $session->authTime = time(); 
322: 
323:         } else {
324:             $session->reason = self::MANUAL;
325:             $session->authTime = NULL;
326:         }
327:         return $this;
328:     }
329: 
330: 
331: 
332:     333: 334: 335: 336: 
337:     protected function setIdentity(IIdentity $identity = NULL)
338:     {
339:         $this->getSessionNamespace(TRUE)->identity = $identity;
340:         return $this;
341:     }
342: 
343: 
344: 
345:     
346: 
347: 
348: 
349:     350: 351: 352: 
353:     public function getRoles()
354:     {
355:         if (!$this->isLoggedIn()) {
356:             return array($this->guestRole);
357:         }
358: 
359:         $identity = $this->getIdentity();
360:         return $identity ? $identity->getRoles() : array($this->authenticatedRole);
361:     }
362: 
363: 
364: 
365:     366: 367: 368: 369: 
370:     final public function isInRole($role)
371:     {
372:         return in_array($role, $this->getRoles(), TRUE);
373:     }
374: 
375: 
376: 
377:     378: 379: 380: 381: 382: 383: 
384:     public function isAllowed($resource = IAuthorizator::ALL, $privilege = IAuthorizator::ALL)
385:     {
386:         $handler = $this->getAuthorizationHandler();
387:         if (!$handler) {
388:             throw new \InvalidStateException("Authorization handler has not been set.");
389:         }
390: 
391:         foreach ($this->getRoles() as $role) {
392:             if ($handler->isAllowed($role, $resource, $privilege)) return TRUE;
393:         }
394: 
395:         return FALSE;
396:     }
397: 
398: 
399: 
400:     401: 402: 403: 404: 
405:     public function setAuthorizationHandler(IAuthorizator $handler)
406:     {
407:         $this->authorizationHandler = $handler;
408:         return $this;
409:     }
410: 
411: 
412: 
413:     414: 415: 416: 
417:     final public function getAuthorizationHandler()
418:     {
419:         if ($this->authorizationHandler === NULL) {
420:             $this->authorizationHandler = Environment::getService('Nette\\Security\\IAuthorizator');
421:         }
422:         return $this->authorizationHandler;
423:     }
424: 
425: 
426: 
427:     
428: 
429: 
430: 
431:     432: 433: 434: 
435:     protected function getSession()
436:     {
437:         return Environment::getSession();
438:     }
439: 
440: 
441: 
442:     
443:     function authenticate($username, $password, $extra = NULL)
444:     {
445:         trigger_error(__METHOD__ . '() is deprecated; use login() instead.', E_USER_WARNING);
446:         return $this->login($username, $password, $extra);
447:     }
448: 
449:     function signOut($clearIdentity = FALSE)
450:     {
451:         trigger_error(__METHOD__ . '() is deprecated; use logout() instead.', E_USER_WARNING);
452:         return $this->logout($clearIdentity);
453:     }
454: 
455:     function isAuthenticated()
456:     {
457:         trigger_error(__METHOD__ . '() is deprecated; use isLoggedIn() instead.', E_USER_WARNING);
458:         return $this->isLoggedIn();
459:     }
460: 
461:     function getSignOutReason()
462:     {
463:         trigger_error(__METHOD__ . '() is deprecated; use getLogoutReason() instead.', E_USER_WARNING);
464:         return $this->getLogoutReason();
465:     }
466:     
467: 
468: }
469: