View | Details | Raw Unified | Return to bug 52272 | Differences between
and this patch

Collapse All | Expand All

(-)management/univention-management-console/univention-management-console-web-server (-55 / +22 lines)
 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

Return to bug 52272