|
Lines 304-309
class UMCP_Dispatcher(object):
Link Here
|
| 304 |
except KeyError: |
304 |
except KeyError: |
| 305 |
CORE.info('Session %r not found' % (sessionid,)) |
305 |
CORE.info('Session %r not found' % (sessionid,)) |
| 306 |
|
306 |
|
|
|
307 |
@classmethod |
| 308 |
def session_timeout_timer(cls): |
| 309 |
now = time.time() |
| 310 |
for sessionid, user in list(Ressource.sessions.items()): |
| 311 |
session = UMCP_Dispatcher.sessions.get(sessionid) |
| 312 |
if (not session or not session._requestid2response_queue) and user.timed_out(now): |
| 313 |
CORE.info('session %r timed out' % (sessionid,)) |
| 314 |
Ressource.sessions.pop(user.sessionid, None) |
| 315 |
user.on_logout() |
| 316 |
return True # execute again! |
| 317 |
|
| 307 |
|
318 |
|
| 308 |
class UploadManager(dict): |
319 |
class UploadManager(dict): |
| 309 |
|
320 |
|
|
Lines 359-393
class QueueRequest(object):
Link Here
|
| 359 |
|
370 |
|
| 360 |
class User(object): |
371 |
class User(object): |
| 361 |
|
372 |
|
| 362 |
__slots__ = ('sessionid', 'username', 'password', 'saml', '_time_remaining') |
373 |
__slots__ = ('sessionid', 'username', 'password', 'saml', '_timeout') |
| 363 |
|
374 |
|
| 364 |
def __init__(self, sessionid, username, password, saml=None): |
375 |
def __init__(self, sessionid, username, password, saml=None): |
| 365 |
self.sessionid = sessionid |
376 |
self.sessionid = sessionid |
| 366 |
self.username = username |
377 |
self.username = username |
| 367 |
self.password = password |
378 |
self.password = password |
| 368 |
self.saml = saml |
379 |
self.saml = saml |
| 369 |
self._time_remaining = _session_timeout |
|
|
| 370 |
self.reset_timeout() |
380 |
self.reset_timeout() |
| 371 |
|
381 |
|
| 372 |
def reset_timeout(self): |
382 |
def reset_timeout(self): |
| 373 |
self._time_remaining = self.session_validity |
383 |
self._timeout = time.time() + _session_timeout |
| 374 |
|
384 |
|
| 375 |
@property |
385 |
def timed_out(self, now): |
| 376 |
def session_validity(self): |
386 |
return self.session_end_time < now |
| 377 |
if self.saml is not None: |
|
|
| 378 |
return self.time_remaining |
| 379 |
return _session_timeout |
| 380 |
|
387 |
|
| 381 |
@property |
388 |
@property |
| 382 |
def time_remaining(self): |
389 |
def session_end_time(self): |
| 383 |
remaining = [] |
390 |
if self.is_saml_user() and self.saml.not_on_or_after: |
| 384 |
if self.saml is not None: |
391 |
return self.saml.not_on_or_after |
| 385 |
remaining.append(self.saml.time_remaining) |
392 |
return self._timeout |
| 386 |
remaining.append(self._time_remaining) |
|
|
| 387 |
try: |
| 388 |
return min(remaining) |
| 389 |
except ValueError: # no SAML, no client |
| 390 |
return 0 |
| 391 |
|
393 |
|
| 392 |
def is_saml_user(self): |
394 |
def is_saml_user(self): |
| 393 |
# self.saml indicates that it was originally a |
395 |
# self.saml indicates that it was originally a |
|
Lines 412-420
class User(object):
Link Here
|
| 412 |
else: |
414 |
else: |
| 413 |
return None |
415 |
return None |
| 414 |
|
416 |
|
| 415 |
def timed_out(self): |
|
|
| 416 |
return self.saml.timed_out() |
| 417 |
|
| 418 |
def __repr__(self): |
417 |
def __repr__(self): |
| 419 |
return '<User(%s, %s, %s)>' % (self.username, self.sessionid, self.saml is not None) |
418 |
return '<User(%s, %s, %s)>' % (self.username, self.sessionid, self.saml is not None) |
| 420 |
|
419 |
|
|
Lines 429-445
class SAMLUser(object):
Link Here
|
| 429 |
self.message = message |
428 |
self.message = message |
| 430 |
self.username = u''.join(response.ava['uid']) |
429 |
self.username = u''.join(response.ava['uid']) |
| 431 |
|
430 |
|
| 432 |
@property |
|
|
| 433 |
def time_remaining(self): |
| 434 |
if self.not_on_or_after == 0: |
| 435 |
return 0 |
| 436 |
return int(self.not_on_or_after - time.time()) |
| 437 |
|
| 438 |
def timed_out(self): |
| 439 |
if self.not_on_or_after == 0: |
| 440 |
return False |
| 441 |
return self.time_remaining < 0 |
| 442 |
|
| 443 |
|
431 |
|
| 444 |
traceback_pattern = re.compile(r'(Traceback.*most recent call|File.*line.*in.*\d)') |
432 |
traceback_pattern = re.compile(r'(Traceback.*most recent call|File.*line.*in.*\d)') |
| 445 |
|
433 |
|
|
Lines 668-674
class Ressource(object):
Link Here
|
| 668 |
|
656 |
|
| 669 |
def check_saml_session_validity(self): |
657 |
def check_saml_session_validity(self): |
| 670 |
user = self.get_user() |
658 |
user = self.get_user() |
| 671 |
if user and user.saml is not None and user.time_remaining < 1: |
659 |
if user and user.saml is not None and user.timed_out(time.time()): |
| 672 |
raise UMC_HTTPError(UNAUTHORIZED) |
660 |
raise UMC_HTTPError(UNAUTHORIZED) |
| 673 |
|
661 |
|
| 674 |
def set_cookies(self, *cookies, **kwargs): |
662 |
def set_cookies(self, *cookies, **kwargs): |
|
Lines 695-702
class Ressource(object):
Link Here
|
| 695 |
olduser = self.get_user() |
683 |
olduser = self.get_user() |
| 696 |
|
684 |
|
| 697 |
user = User(sessionid, username, password, saml or olduser and olduser.saml) |
685 |
user = User(sessionid, username, password, saml or olduser and olduser.saml) |
| 698 |
self._session_timeout_timer(user) |
|
|
| 699 |
|
| 700 |
self.sessions[sessionid] = user |
686 |
self.sessions[sessionid] = user |
| 701 |
self.set_cookies(('UMCSessionId', sessionid), ('UMCUsername', username)) |
687 |
self.set_cookies(('UMCSessionId', sessionid), ('UMCUsername', username)) |
| 702 |
return user |
688 |
return user |
|
Lines 715-743
class Ressource(object):
Link Here
|
| 715 |
if not value or value not in self.sessions: |
701 |
if not value or value not in self.sessions: |
| 716 |
return |
702 |
return |
| 717 |
user = self.sessions[value] |
703 |
user = self.sessions[value] |
| 718 |
if user.time_remaining <= 0: |
704 |
if user.timed_out(time.time()): |
| 719 |
return |
705 |
return |
| 720 |
return user |
706 |
return user |
| 721 |
|
707 |
|
| 722 |
def _session_timeout_timer(self, user): |
|
|
| 723 |
"""In order to avoid problems when the system time is changed (e.g., |
| 724 |
via rdate), we register a timer event that counts down the session |
| 725 |
timeout second-wise.""" |
| 726 |
|
| 727 |
# count down the remaining time |
| 728 |
user._time_remaining -= 1 |
| 729 |
|
| 730 |
session = UMCP_Dispatcher.sessions.get(user.sessionid) |
| 731 |
if user._time_remaining <= 0 and (not session or not session._requestid2response_queue): |
| 732 |
self._log('info', 'session timed out') |
| 733 |
self.sessions.pop(user.sessionid, None) |
| 734 |
user.on_logout() |
| 735 |
return |
| 736 |
|
| 737 |
# count down the timer second-wise (in order to avoid problems when |
| 738 |
# changing the system time, e.g. via rdate) |
| 739 |
notifier.timer_add(1000, lambda: self._session_timeout_timer(user)) |
| 740 |
|
| 741 |
|
708 |
|
| 742 |
class CPgeneric(Ressource): |
709 |
class CPgeneric(Ressource): |
| 743 |
|
710 |
|
|
Lines 902-909
class CPGet(CPgeneric):
Link Here
|
| 902 |
raise UMC_HTTPError(UNAUTHORIZED) |
869 |
raise UMC_HTTPError(UNAUTHORIZED) |
| 903 |
info['username'] = user.username |
870 |
info['username'] = user.username |
| 904 |
info['auth_type'] = user.saml and 'SAML' |
871 |
info['auth_type'] = user.saml and 'SAML' |
| 905 |
info['remaining'] = user.time_remaining |
872 |
info['remaining'] = int(user.session_end_time - time.time()) |
| 906 |
info['validity'] = user.session_validity |
|
|
| 907 |
return json.dumps({"status": 200, "result": info, "message": ""}).encode('ASCII') |
873 |
return json.dumps({"status": 200, "result": info, "message": ""}).encode('ASCII') |
| 908 |
|
874 |
|
| 909 |
@cherrypy.expose |
875 |
@cherrypy.expose |
|
Lines 1035-1041
class CPAuth(CPgeneric):
Link Here
|
| 1035 |
CORE.info('CPAuth/auth/sso: got new auth request (%s:%s <=> %s)' % (get_ip_address(), remote.port, remote.name)) |
1001 |
CORE.info('CPAuth/auth/sso: got new auth request (%s:%s <=> %s)' % (get_ip_address(), remote.port, remote.name)) |
| 1036 |
|
1002 |
|
| 1037 |
user = self.get_user() |
1003 |
user = self.get_user() |
| 1038 |
if not user or not user.saml or user.timed_out(): |
1004 |
if not user or not user.saml or user.timed_out(time.time()): |
| 1039 |
# redirect user to login page in case he's not authenticated or his session timed out |
1005 |
# redirect user to login page in case he's not authenticated or his session timed out |
| 1040 |
raise HTTPRedirect('/univention/saml/') |
1006 |
raise HTTPRedirect('/univention/saml/') |
| 1041 |
|
1007 |
|
|
Lines 1638-1643
class UMC_HTTP_Daemon(DaemonRunner):
Link Here
|
| 1638 |
notifier.init(notifier.GENERIC) |
1604 |
notifier.init(notifier.GENERIC) |
| 1639 |
notifier.dispatch.MIN_TIMER = get_int('umc/http/dispatch-interval', notifier.dispatch.MIN_TIMER) |
1605 |
notifier.dispatch.MIN_TIMER = get_int('umc/http/dispatch-interval', notifier.dispatch.MIN_TIMER) |
| 1640 |
notifier.dispatcher_add(UMCP_Dispatcher.check_queue) |
1606 |
notifier.dispatcher_add(UMCP_Dispatcher.check_queue) |
|
|
1607 |
notifier.timer_add(1000, UMCP_Dispatcher.session_timeout_timer) |
| 1641 |
notifier.loop() |
1608 |
notifier.loop() |
| 1642 |
except (SystemExit, KeyboardInterrupt) as exc: |
1609 |
except (SystemExit, KeyboardInterrupt) as exc: |
| 1643 |
# stop the web server |
1610 |
# stop the web server |