3 abstract class SpidioAuth
extends AuthBase
implements DatabaseSession
, DatabaseKey
{
5 * Session representation within Auth system.
9 protected static $objSession;
12 * SessionKey representation within Auth system.
16 protected static $objSessionKey;
22 public function __construct() {
23 // Set authentication scheme.
24 $this->AuthenticationType
= AuthenticationType
::Sha1
;
30 $this->SessionStart();
32 // Collect garbage for Sessions.
33 $this->SessionGarbageCollect();
38 // Cleanup SessionKey table.
39 $this->KeyGarbageCollect();
43 * Check if user is logged in.
47 public function IsLoggedIn() {
48 return !is_null(self
::$objSession->User
);
52 * Reset current Session.
55 public function ResetSession() {
56 $this->AddLogEntry(LogTypes
::SESSIONRESET
);
57 if ($this->IsLoggedIn()) {
58 $this->AddLogEntry(LogTypes
::USERLOGOUTFORCE
);
61 $this->SessionDestroy();
65 * Check if user $strName exists.
67 * @param string $strName
70 public function UserExists($strName) {
71 return !is_null(User
::LoadByName(ucfirst(strtolower($strName))));
77 * @param int $intLogType constant of LogTypes
78 * @param string $strItemData data of item where the log entry is about
80 protected function AddLogEntry($intLogType, $strItemData = null) {
83 if ($intLogType != LogTypes
::SESSIONCREATED
&& $intLogType != LogTypes
::SESSIONTIMEOUT
) {
84 $objLog->UserId
= self
::$objSession->UserId
;
86 $objLog->UserId
= null;
89 $objLog->LogTypeId
= $intLogType;
90 $objLog->LogActionTypeId
= LogActionTypes
::NUL
;
91 $objLog->Date
= new QDateTime(QDateTime
::Now
);
92 $objLog->ItemId
= null;
93 $objLog->ItemData
= $strItemData;
94 $objLog->SessionName
= $this->SessionGetName();
95 $objLog->IpAddress
= (string) new IpAddress($this->UserIpAddress());
99 abstract public function SessionLoad();
102 * Register Session or update Session.
105 public function SessionStart() {
106 if (method_exists($this, 'SessionStartHookBegin')) {
107 $this->SessionStartHookBegin();
110 // Register when no session is registered, otherwise update.
111 if (is_null(self
::$objSession)) {
112 $this->SessionRegister();
114 $this->SessionUpdate();
117 if (method_exists($this, 'SessionStartHookEnd')) {
118 $this->SessionStartHookEnd();
123 * Register Session for first time.
126 protected function SessionRegister() {
127 if (method_exists($this, 'SessionRegisterHookBegin')) {
128 $this->SessionRegisterHookBegin();
131 // Create new Session.
132 self
::$objSession = new Session();
134 // Fill fields with data.
135 self
::$objSession->Id
= $this->UUID();
136 self
::$objSession->UserId
= null;
137 self
::$objSession->IpAddress
= (string) new IpAddress($this->UserIpAddress());
138 self
::$objSession->AutoLogin
= false;
140 // Save the new Session.
141 self
::$objSession->Save();
143 // Reload to load self::$objSession->Added value.
144 self
::$objSession->Reload();
147 $this->SetCookie('sid', self
::$objSession->Id
);
150 $this->AddLogEntry(LogTypes
::SESSIONCREATED
);
152 if (method_exists($this, 'SessionRegisterHookEnd')) {
153 $this->SessionRegisterHookEnd();
158 * Update Session with fresh data.
161 protected function SessionUpdate() {
162 if (method_exists($this, 'SessionUpdateHookBegin')) {
163 $this->SessionUpdateHookBegin();
166 // Set current IP address.
167 self
::$objSession->IpAddress
= (string) new IpAddress($this->UserIpAddress());
170 self
::$objSession->Save();
172 if (method_exists($this, 'SessionUpdateHookEnd')) {
173 $this->SessionUpdateHookEnd();
178 * Register User to Session.
180 * @param User $objUser
182 public function SessionRegisterUser(User
$objUser) {
183 if (method_exists($this, 'SessionRegisterUserHookBegin')) {
184 $this->SessionRegisterUserHookBegin();
187 // Assign User object to Session.
188 self
::$objSession->User
= $objUser;
191 self
::$objSession->Save();
193 if (method_exists($this, 'SessionRegisterUserHookEnd')) {
194 $this->SessionRegisterUserHookEnd();
199 * Unregister User from Session.
202 public function SessionUnRegisterUser() {
203 if (method_exists($this, 'SessionUnRegisterUserHookBegin')) {
204 $this->SessionUnRegisterUserHookBegin();
207 // Kill SessionKey related to this Session.
210 // Nullify User object this Session.
211 self
::$objSession->User
= null;
214 self
::$objSession->Save();
216 if (method_exists($this, 'SessionUnRegisterUserHookEnd')) {
217 $this->SessionUnRegisterUserHookEnd();
225 public function SessionDestroy() {
226 if (method_exists($this, 'SessionDestroyHookBegin')) {
227 $this->SessionDestroyHookBegin();
230 if (!is_null(self
::$objSession->UserId
)) {
232 $this->SessionUnRegisterUser();
236 self
::$objSession->Delete();
238 if (method_exists($this, 'SessionDestroyHookEnd')) {
239 $this->SessionDestroyHookEnd();
244 * Delete old sessions from database.
247 public function SessionGarbageCollect() {
248 if (method_exists($this, 'SessionGarbageCollectHookBegin')) {
249 $this->SessionGarbageCollectHookBegin();
252 // define timeout time.
253 $dttExpire = new QDateTime(QDateTime
::Now
);
254 $dttExpire->AddSeconds(-$this->SessionGetTimeout());
256 // Query table and delete the first 10 timed out sessions, delete only when there is no SessionKey assigned (checked via reverse relationship).
257 foreach (Session
::QueryArray(
259 QQ
::LessThan(QQN
::Session()->Changed
, $dttExpire),
260 QQ
::IsNull(QQN
::Session()->SessionKeyAsSession
->Id
)
266 $objSession->Delete();
267 $this->AddLogEntry(LogTypes
::SESSIONTIMEOUT
);
270 if (method_exists($this, 'SessionGarbageCollectHookEnd')) {
271 $this->SessionGarbageCollectHookEnd();
276 * Get Session timeout time in seconds.
280 protected function SessionGetTimeout() {
281 return $this->GetConfig('session_timeout', QType
::Integer);
289 public function SessionGetName() {
290 return self
::$objSession->Id
;
294 * Check if Session exists.
296 * @param string $strSessionId
299 public function SessionExists($strSessionId) {
300 return !is_null(Session
::Load($strSessionId));
304 * Check if Session exists and an User is logged.
306 * @param string $strSessionId
309 public function SessionIsValid($strSessionId) {
310 if (is_null($strSessionId)) {
313 return !is_null(Session
::Load($strSessionId)->UserId
);
318 * Lookup key for Session.
321 public function KeyLookup() {
322 if (method_exists($this, 'KeyLookupHookBegin')) {
323 $this->KeyLookupHookBegin();
326 // Load SessionKey from database
327 if ($this->KeyExists()) {
328 // Update SessionKey.
329 self
::$objSessionKey = SessionKey
::Load($this->GetCookie('kid'));
333 if (method_exists($this, 'KeyLookupHookEnd')) {
334 $this->KeyLookupHookEnd();
339 * Register SessionKey for Session.
342 public function KeyRegister() {
343 if (method_exists($this, 'KeyRegisterHookBegin')) {
344 $this->KeyRegisterHookBegin();
347 if (!SessionKey
::LoadBySessionId(self
::$objSession->Id
)) {
348 // Fill fields with data
349 self
::$objSessionKey = new SessionKey();
350 self
::$objSessionKey->Id
= $this->UUID();
351 self
::$objSessionKey->User
= self
::$objSession->User
;
352 self
::$objSessionKey->Session
= self
::$objSession;
353 self
::$objSessionKey->IpAddress
= self
::$objSession->IpAddress
;
355 // Save new SessionKey
356 self
::$objSessionKey->Save();
358 // Update AutoLogin flag.
359 self
::$objSession->AutoLogin
= true;
361 // Save Session changed session fields.
362 self
::$objSession->Save();
365 $dttExpire = new QDateTime(QDateTime
::Now
);
366 $dttExpire->AddSeconds($this->GetConfig('sessionkey_timeout', QType
::Integer));
367 $this->SetCookie('kid', self
::$objSessionKey->Id
, $dttExpire);
370 if (method_exists($this, 'KeyDeleteHookEnd')) {
371 $this->KeyDeleteHookEnd();
376 * Update SessionKey with fresh data.
379 protected function KeyUpdate() {
380 if (method_exists($this, 'KeyUpdateHookBegin')) {
381 $this->KeyUpdateHookBegin();
384 $dttExpire = new QDateTime(QDateTime
::Now
);
385 $dttExpire->AddSeconds(-$this->KeyGetChange());
387 // Update key id when item is longer than config value for session id changing.
388 if ($dttExpire->IsLaterThan(self
::$objSessionKey->Changed
)) {
389 // Generate SessionKey id.
390 self
::$objSessionKey->Id
= $this->UUID();
393 $dttExpire = new QDateTime(QDateTime
::Now
);
394 $dttExpire->AddSeconds($this->GetConfig('sessionkey_timeout', QType
::Integer));
395 $this->SetCookie('kid', self
::$objSessionKey->Id
, $dttExpire);
398 // Update Session in SessionKey when there is another Session for that SessionKey based on the database.
399 if (self
::$objSessionKey->Session
->Id
!= $this->SessionGetName()) {
400 self
::$objSessionKey->Session
= self
::$objSession;
402 self
::$objSession->UserId
= self
::$objSessionKey->UserId
;
403 self
::$objSession->AutoLogin
= true;
404 self
::$objSession->Save();
406 $this->AddLogEntry(LogTypes
::USERLOGIN
, sprintf('Key: %s', $this->KeyGetName()));
409 // Update IP address of SessionKey.
410 self
::$objSessionKey->IpAddress
= self
::$objSession->IpAddress
;
412 // Force update SessionKey because it is possible that the row is modified by another request from the same browser.
413 self
::$objSessionKey->Save(false, true);
415 // Log in Session with user from SessionKey
416 $this->SessionRegisterUser(self
::$objSessionKey->User
);
418 if (method_exists($this, 'KeyUpdateHookEnd')) {
419 $this->KeyUpdateHookEnd();
427 public function KeyDestroy() {
428 if (method_exists($this, 'KeyDeleteHookBegin')) {
429 $this->KeyDeleteHookBegin();
432 // Delete SessionKey.
433 if (!is_null(self
::$objSessionKey)) {
434 self
::$objSessionKey->Delete();
437 if (method_exists($this, 'KeyDeleteHookEnd')) {
438 $this->KeyDeleteHookEnd();
443 * Delete all sessionkeys for this User.
446 public function KeyDestroyAll() {
447 if (method_exists($this, 'KeyDeleteAllHookBegin')) {
448 $this->KeyDeleteAllHookBegin();
453 foreach (SessionKey
::LoadArrayByUserId(self
::$objSession->UserId
) as $objSessionKey) {
454 $objSessionKey->Delete();
457 if (method_exists($this, 'KeyDestroyAllHookEnd')) {
458 $this->KeyDestroyAllHookEnd();
463 * Collect garbage of SessionKeyytable.
466 public function KeyGarbageCollect() {
467 if (method_exists($this, 'KeyGarbageCollectHookBegin')) {
468 $this->KeyGarbageCollectHookBegin();
471 $dttExpire = new QDateTime(QDateTime
::Now
);
472 $dttExpire->AddSeconds(-$this->KeyGetTimeout());
474 // Query table and delete the first 10 timed out sessionkeys.
475 foreach (SessionKey
::QueryArray(
476 QQ
::LessThan(QQN
::SessionKey()->Changed
, $dttExpire),
480 ) as $objSessionKey) {
481 $objSessionKey->Delete();
484 if (method_exists($this, 'KeyGarbageCollectHookEnd')) {
485 $this->KeyGarbageCollectHookEnd();
490 * Return SessionKey Id.
494 public function KeyGetName() {
495 return self
::$objSessionKey->Id
;
499 * Check if SessionKey exists.
503 public function KeyExists() {
504 if ($this->ExistCookie('kid')) {
505 return (SessionKey
::Load($this->GetCookie('kid')));
512 * Get SessionKey timeout time in seconds.
516 protected function KeyGetChange() {
517 return $this->GetConfig('sessionkey_change', QType
::Integer);
521 * Get SessionKey timeout time in seconds.
525 protected function KeyGetTimeout() {
526 return $this->GetConfig('sessionkey_timeout', QType
::Integer);
532 * @param string $strName
535 protected function GetCookie($strName) {
536 $objCookie = CookieStore
::UpdateCookie(sprintf('%s_%s', strtolower($this->GetConfig('software_coresystem_name')), $strName));
537 return $objCookie->Value
;
541 * Check if Cookie exists.
543 * @param string $strName
546 protected function ExistCookie($strName) {
547 return CookieStore
::ExistCookie(sprintf('%s_%s', strtolower($this->GetConfig('software_coresystem_name')), $strName));
551 * Set or update cookie.
553 * @param string $strName
554 * @param string $strValue
555 * @param null|QDateTime $dttExpire
557 protected function SetCookie($strName, $strValue, $dttExpire = null) {
558 $objCookie = CookieStore
::UpdateCookie(sprintf('%s_%s', strtolower($this->GetConfig('software_coresystem_name')), $strName));
559 $objCookie->Value
= $strValue;
560 $objCookie->Path
= sprintf('%s%s/', __VIRTUAL_DIRECTORY__
, __SUBDIRECTORY__
);
562 if (!is_null($dttExpire)) {
563 $objCookie->Expire
= $dttExpire;
566 if (method_exists($this, 'SetCookieHook')) {
567 $this->SetCookieHook($objCookie);
571 public function __get($strName) {
573 case 'Session': return self
::$objSession;
574 case 'SessionKey': return self
::$objSessionKey;
578 return parent
::__get($strName);
579 } catch (QCallerException
$objExc) {
580 $objExc->IncrementOffset();
586 public function __set($strName, $mixValue) {
590 return (self
::$objSession = QType
::Cast($mixValue, 'Session'));
591 } catch (QCallerException
$objExc) {
592 $objExc->IncrementOffset();
597 return (self
::$objSessionKey = QType
::Cast($mixValue, 'SessionKey'));
598 } catch (QCallerException
$objExc) {
599 $objExc->IncrementOffset();
605 return parent
::__set($strName, $mixValue);
606 } catch (QCallerException
$objExc) {
607 $objExc->IncrementOffset();