|
Lines 299-304
class UMCP_Dispatcher(object):
Link Here
|
| 299 |
except KeyError: |
299 |
except KeyError: |
| 300 |
CORE.info('Session %r not found' % (sessionid,)) |
300 |
CORE.info('Session %r not found' % (sessionid,)) |
| 301 |
|
301 |
|
|
|
302 |
@classmethod |
| 303 |
def clean_sessions(cls): |
| 304 |
now = time.time() |
| 305 |
for sessionid, user in list(Ressource.sessions.items()): |
| 306 |
session = UMCP_Dispatcher.sessions.get(sessionid) |
| 307 |
if (not session or not session._requestid2response_queue) and user.timed_out(now): |
| 308 |
CORE.info('session %r timed out' % (sessionid,)) |
| 309 |
Ressource.sessions.pop(user.sessionid, None) |
| 310 |
return True # execute again! |
| 311 |
|
| 302 |
|
312 |
|
| 303 |
class UploadManager(dict): |
313 |
class UploadManager(dict): |
| 304 |
|
314 |
|
|
Lines 357-385
class User(object):
Link Here
|
| 357 |
self.username = username |
367 |
self.username = username |
| 358 |
self.password = password |
368 |
self.password = password |
| 359 |
self.saml = saml |
369 |
self.saml = saml |
| 360 |
self._time_remaining = _session_timeout |
|
|
| 361 |
self.reset_timeout() |
370 |
self.reset_timeout() |
| 362 |
self.data = data or {} |
371 |
self.data = data or {} |
| 363 |
|
372 |
|
| 364 |
def reset_timeout(self): |
373 |
def reset_timeout(self): |
| 365 |
self._time_remaining = self.session_validity |
374 |
self._timeout = time.time() + _session_timeout |
| 366 |
|
375 |
|
| 367 |
@property |
376 |
def timed_out(self, now): |
| 368 |
def session_validity(self): |
377 |
return self.session_end_time < now |
| 369 |
if self.saml is not None: |
|
|
| 370 |
return self.time_remaining |
| 371 |
return _session_timeout |
| 372 |
|
378 |
|
| 373 |
@property |
379 |
@property |
| 374 |
def time_remaining(self): |
380 |
def session_end_time(self): |
| 375 |
remaining = [] |
381 |
if self.is_saml_user() and self.saml.response.not_on_or_after: |
| 376 |
if self.saml is not None: |
382 |
return self.saml.response.not_on_or_after |
| 377 |
remaining.append(self.saml.time_remaining) |
383 |
return self._timeout |
| 378 |
remaining.append(self._time_remaining) |
|
|
| 379 |
try: |
| 380 |
return min(remaining) |
| 381 |
except ValueError: # no SAML, no client |
| 382 |
return 0 |
| 383 |
|
384 |
|
| 384 |
def is_saml_user(self): |
385 |
def is_saml_user(self): |
| 385 |
# self.saml indicates that it was originally a |
386 |
# self.saml indicates that it was originally a |
|
Lines 400-408
class User(object):
Link Here
|
| 400 |
else: |
401 |
else: |
| 401 |
return None |
402 |
return None |
| 402 |
|
403 |
|
| 403 |
def timed_out(self): |
|
|
| 404 |
return self.saml.timed_out() |
| 405 |
|
| 406 |
def __repr__(self): |
404 |
def __repr__(self): |
| 407 |
return '<User(%s, %s, %s)>' % (self.username, self.sessionid, self.saml is not None) |
405 |
return '<User(%s, %s, %s)>' % (self.username, self.sessionid, self.saml is not None) |
| 408 |
|
406 |
|
|
Lines 415-431
class SAMLUser(object):
Link Here
|
| 415 |
self.data = response.ava |
413 |
self.data = response.ava |
| 416 |
self.username = u''.join(self.data['uid']) |
414 |
self.username = u''.join(self.data['uid']) |
| 417 |
|
415 |
|
| 418 |
@property |
|
|
| 419 |
def time_remaining(self): |
| 420 |
if self.response.not_on_or_after == 0: |
| 421 |
return 0 |
| 422 |
return int(self.response.not_on_or_after - time.time()) |
| 423 |
|
| 424 |
def timed_out(self): |
| 425 |
if self.response.not_on_or_after == 0: |
| 426 |
return False |
| 427 |
return self.time_remaining < 0 |
| 428 |
|
| 429 |
|
416 |
|
| 430 |
traceback_pattern = re.compile(r'(Traceback.*most recent call|File.*line.*in.*\d)') |
417 |
traceback_pattern = re.compile(r'(Traceback.*most recent call|File.*line.*in.*\d)') |
| 431 |
|
418 |
|
|
Lines 654-660
class Ressource(object):
Link Here
|
| 654 |
|
641 |
|
| 655 |
def check_saml_session_validity(self): |
642 |
def check_saml_session_validity(self): |
| 656 |
user = self.get_user() |
643 |
user = self.get_user() |
| 657 |
if user and user.saml is not None and user.time_remaining < 1: |
644 |
if user and user.saml is not None and user.timed_out(time.time()): |
| 658 |
raise UMC_HTTPError(UNAUTHORIZED) |
645 |
raise UMC_HTTPError(UNAUTHORIZED) |
| 659 |
|
646 |
|
| 660 |
def set_cookies(self, *cookies, **kwargs): |
647 |
def set_cookies(self, *cookies, **kwargs): |
|
Lines 681-688
class Ressource(object):
Link Here
|
| 681 |
olduser = self.get_user() |
668 |
olduser = self.get_user() |
| 682 |
|
669 |
|
| 683 |
user = User(sessionid, username, password, saml or olduser and olduser.saml, kwargs) |
670 |
user = User(sessionid, username, password, saml or olduser and olduser.saml, kwargs) |
| 684 |
self._session_timeout_timer(user) |
|
|
| 685 |
|
| 686 |
self.sessions[sessionid] = user |
671 |
self.sessions[sessionid] = user |
| 687 |
self.set_cookies(('UMCSessionId', sessionid), ('UMCUsername', username)) |
672 |
self.set_cookies(('UMCSessionId', sessionid), ('UMCUsername', username)) |
| 688 |
return user |
673 |
return user |
|
Lines 699-726
class Ressource(object):
Link Here
|
| 699 |
if not value or value not in self.sessions: |
684 |
if not value or value not in self.sessions: |
| 700 |
return |
685 |
return |
| 701 |
user = self.sessions[value] |
686 |
user = self.sessions[value] |
| 702 |
if user.time_remaining <= 0: |
687 |
if user.timed_out(time.time()): |
| 703 |
return |
688 |
return |
| 704 |
return user |
689 |
return user |
| 705 |
|
690 |
|
| 706 |
def _session_timeout_timer(self, user): |
|
|
| 707 |
"""In order to avoid problems when the system time is changed (e.g., |
| 708 |
via rdate), we register a timer event that counts down the session |
| 709 |
timeout second-wise.""" |
| 710 |
|
| 711 |
# count down the remaining time |
| 712 |
user._time_remaining -= 1 |
| 713 |
|
| 714 |
session = UMCP_Dispatcher.sessions.get(user.sessionid) |
| 715 |
if user._time_remaining <= 0 and (not session or not session._requestid2response_queue): |
| 716 |
self._log('info', 'session timed out') |
| 717 |
self.sessions.pop(user.sessionid, None) |
| 718 |
return |
| 719 |
|
| 720 |
# count down the timer second-wise (in order to avoid problems when |
| 721 |
# changing the system time, e.g. via rdate) |
| 722 |
notifier.timer_add(1000, lambda: self._session_timeout_timer(user)) |
| 723 |
|
| 724 |
|
691 |
|
| 725 |
class CPgeneric(Ressource): |
692 |
class CPgeneric(Ressource): |
| 726 |
|
693 |
|
|
Lines 884-891
class CPGet(CPgeneric):
Link Here
|
| 884 |
raise UMC_HTTPError(UNAUTHORIZED) |
851 |
raise UMC_HTTPError(UNAUTHORIZED) |
| 885 |
info['username'] = user.username |
852 |
info['username'] = user.username |
| 886 |
info['auth_type'] = user.saml and 'SAML' |
853 |
info['auth_type'] = user.saml and 'SAML' |
| 887 |
info['remaining'] = user.time_remaining |
854 |
info['remaining'] = user.session_end_time - time.time() |
| 888 |
info['validity'] = user.session_validity |
|
|
| 889 |
return json.dumps({"status": 200, "result": info, "message": ""}).encode('ASCII') |
855 |
return json.dumps({"status": 200, "result": info, "message": ""}).encode('ASCII') |
| 890 |
|
856 |
|
| 891 |
@cherrypy.expose |
857 |
@cherrypy.expose |
|
Lines 1017-1023
class CPAuth(CPgeneric):
Link Here
|
| 1017 |
CORE.info('CPAuth/auth/sso: got new auth request (%s:%s <=> %s)' % (get_ip_address(), remote.port, remote.name)) |
983 |
CORE.info('CPAuth/auth/sso: got new auth request (%s:%s <=> %s)' % (get_ip_address(), remote.port, remote.name)) |
| 1018 |
|
984 |
|
| 1019 |
user = self.get_user() |
985 |
user = self.get_user() |
| 1020 |
if not user or not user.saml or user.timed_out(): |
986 |
if not user or not user.saml or user.timed_out(time.time()): |
| 1021 |
# redirect user to login page in case he's not authenticated or his session timed out |
987 |
# redirect user to login page in case he's not authenticated or his session timed out |
| 1022 |
raise HTTPRedirect('/univention/saml/') |
988 |
raise HTTPRedirect('/univention/saml/') |
| 1023 |
|
989 |
|
|
Lines 1619-1624
class UMC_HTTP_Daemon(DaemonRunner):
Link Here
|
| 1619 |
notifier.init(notifier.GENERIC) |
1585 |
notifier.init(notifier.GENERIC) |
| 1620 |
notifier.dispatch.MIN_TIMER = get_int('umc/http/dispatch-interval', notifier.dispatch.MIN_TIMER) |
1586 |
notifier.dispatch.MIN_TIMER = get_int('umc/http/dispatch-interval', notifier.dispatch.MIN_TIMER) |
| 1621 |
notifier.dispatcher_add(UMCP_Dispatcher.check_queue) |
1587 |
notifier.dispatcher_add(UMCP_Dispatcher.check_queue) |
|
|
1588 |
notifier.timer_add(1000, UMCP_Dispatcher.clean_sessions) |
| 1622 |
notifier.loop() |
1589 |
notifier.loop() |
| 1623 |
except (SystemExit, KeyboardInterrupt) as exc: |
1590 |
except (SystemExit, KeyboardInterrupt) as exc: |
| 1624 |
# stop the web server |
1591 |
# stop the web server |