Univention Bugzilla – Attachment 10571 Details for
Bug 52272
UMC-Web-Server: cleanup sessions with one timer
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
patch
session_timeout.patch (text/plain), 9.35 KB, created by
Florian Best
on 2020-11-30 22:25:30 CET
(
hide
)
Description:
patch
Filename:
MIME Type:
Creator:
Florian Best
Created:
2020-11-30 22:25:30 CET
Size:
9.35 KB
patch
obsolete
>commit 20ffa78b6fdd51701cb383a349ae81532ab69f7d >Author: Florian Best <best@univention.de> >Date: Wed Oct 28 21:03:53 2020 +0100 > > Bug #52272: cleanup all sessions with one timer > > don't call N_SESSION timer functions every second but only one function. > >diff --git management/univention-management-console/src/univention/management/console/protocol/server.py management/univention-management-console/src/univention/management/console/protocol/server.py >index 1d7541adc5..76adca9b57 100644 >--- management/univention-management-console/src/univention/management/console/protocol/server.py >+++ management/univention-management-console/src/univention/management/console/protocol/server.py >@@ -38,6 +38,7 @@ Defines the basic class for an UMC server. > import os > import errno > import fcntl >+import time > import socket > import resource > import traceback >@@ -70,6 +71,7 @@ class MagicBucket(object): > > def __init__(self): > self.__states = {} >+ notifier.timer_add(1000, self._timeout_connections) > > def new(self, client, socket): > """Is called by the Server object to announce a new incoming >@@ -83,19 +85,15 @@ class MagicBucket(object): > state.session.signal_connect('success', notifier.Callback(self._response, state)) > self.__states[socket] = state > notifier.socket_add(socket, self._receive) >- self._timeout_connection(state) > >- def _timeout_connection(self, state): >+ def _timeout_connections(self): > """Closes the connection after a specified timeout""" >- state.time_remaining -= 1 >+ timed_out = [sock for sock, state in self.__states.items() if state.timed_out()] >+ for sock in timed_out: >+ CORE.process('Session timed out. (sock=%r)' % (sock,)) >+ self._cleanup(sock) > >- if state.time_remaining <= 0 and not state.requests and not state.session.has_active_module_processes(): >- CORE.process('Session timed out.') >- self._cleanup(state.socket) >- else: >- # count down the timer second-wise (in order to avoid problems when >- # changing the system time, e.g. via rdate) >- notifier.timer_add(1000, lambda: self._timeout_connection(state)) >+ return True > > def exit(self): > '''Closes all open connections.''' >@@ -513,7 +511,7 @@ class State(object): > :param fd socket: file descriptor or socket object > """ > >- __slots__ = ('client', 'socket', 'buffer', 'requests', 'resend_queue', 'session', 'time_remaining') >+ __slots__ = ('client', 'socket', 'buffer', 'requests', 'resend_queue', 'session', 'session_end_time') > > def __init__(self, client, socket): > self.client = client >@@ -525,7 +523,14 @@ class State(object): > self.reset_connection_timeout() > > def reset_connection_timeout(self): >- self.time_remaining = SERVER_CONNECTION_TIMEOUT >+ self.session_end_time = int(time.time() + SERVER_CONNECTION_TIMEOUT) >+ >+ def timed_out(self): >+ return not self.requests and not self.session.has_active_module_processes() and self.time_remaining <= 0 >+ >+ @property >+ def time_remaining(self): >+ return int(self.session_end_time - time.time()) > > def __repr__(self): > return '<State(%s %r buffer=%d requests=%d time_remaining=%r)>' % (self.client, self.socket, len(self.buffer), len(self.requests), self.time_remaining) > >commit 2c778585265d083a9fb9070a3c4b6892ca5faee5 >Author: Florian Best <best@univention.de> >Date: Wed Oct 28 11:30:56 2020 +0100 > > Bug #52272: UMC-Webserver: cleanup all sessions with one timer > > The UMC-Web-Server creates a timer which counts down the session second wise for each session to check if it can be destroyed. > > When 1000 uses are logged in currently, every second 1000 timer-callbacks are called. > We should register one timer which iterates over all sessions instead. > >diff --git management/univention-management-console/univention-management-console-web-server management/univention-management-console/univention-management-console-web-server >index 9fe5c7be2d..97dae6eee8 100755 >--- management/univention-management-console/univention-management-console-web-server >+++ management/univention-management-console/univention-management-console-web-server >@@ -304,6 +304,17 @@ class UMCP_Dispatcher(object): > except KeyError: > CORE.info('Session %r not found' % (sessionid,)) > >+ @classmethod >+ def session_timeout_timer(cls): >+ now = time.time() >+ for sessionid, user in list(Ressource.sessions.items()): >+ session = UMCP_Dispatcher.sessions.get(sessionid) >+ if (not session or not session._requestid2response_queue) and user.timed_out(now): >+ CORE.info('session %r timed out' % (sessionid,)) >+ Ressource.sessions.pop(user.sessionid, None) >+ user.on_logout() >+ return True # execute again! >+ > > class UploadManager(dict): > >@@ -359,35 +370,26 @@ class QueueRequest(object): > > class User(object): > >- __slots__ = ('sessionid', 'username', 'password', 'saml', '_time_remaining') >+ __slots__ = ('sessionid', 'username', 'password', 'saml', '_timeout') > > def __init__(self, sessionid, username, password, saml=None): > self.sessionid = sessionid > self.username = username > self.password = password > self.saml = saml >- self._time_remaining = _session_timeout > self.reset_timeout() > > def reset_timeout(self): >- self._time_remaining = self.session_validity >+ self._timeout = time.time() + _session_timeout > >- @property >- def session_validity(self): >- if self.saml is not None: >- return self.time_remaining >- return _session_timeout >+ def timed_out(self, now): >+ return self.session_end_time < now > > @property >- def time_remaining(self): >- remaining = [] >- if self.saml is not None: >- remaining.append(self.saml.time_remaining) >- remaining.append(self._time_remaining) >- try: >- return min(remaining) >- except ValueError: # no SAML, no client >- return 0 >+ def session_end_time(self): >+ if self.is_saml_user() and self.saml.not_on_or_after: >+ return self.saml.not_on_or_after >+ return self._timeout > > def is_saml_user(self): > # self.saml indicates that it was originally a >@@ -412,9 +414,6 @@ class User(object): > else: > return None > >- def timed_out(self): >- return self.saml.timed_out() >- > def __repr__(self): > return '<User(%s, %s, %s)>' % (self.username, self.sessionid, self.saml is not None) > >@@ -429,17 +428,6 @@ class SAMLUser(object): > self.message = message > self.username = u''.join(response.ava['uid']) > >- @property >- def time_remaining(self): >- if self.not_on_or_after == 0: >- return 0 >- return int(self.not_on_or_after - time.time()) >- >- def timed_out(self): >- if self.not_on_or_after == 0: >- return False >- return self.time_remaining < 0 >- > > traceback_pattern = re.compile(r'(Traceback.*most recent call|File.*line.*in.*\d)') > >@@ -668,7 +656,7 @@ class Ressource(object): > > def check_saml_session_validity(self): > user = self.get_user() >- if user and user.saml is not None and user.time_remaining < 1: >+ if user and user.saml is not None and user.timed_out(time.time()): > raise UMC_HTTPError(UNAUTHORIZED) > > def set_cookies(self, *cookies, **kwargs): >@@ -695,8 +683,6 @@ class Ressource(object): > olduser = self.get_user() > > user = User(sessionid, username, password, saml or olduser and olduser.saml) >- self._session_timeout_timer(user) >- > self.sessions[sessionid] = user > self.set_cookies(('UMCSessionId', sessionid), ('UMCUsername', username)) > return user >@@ -715,29 +701,10 @@ class Ressource(object): > if not value or value not in self.sessions: > return > user = self.sessions[value] >- if user.time_remaining <= 0: >+ if user.timed_out(time.time()): > return > return user > >- def _session_timeout_timer(self, user): >- """In order to avoid problems when the system time is changed (e.g., >- via rdate), we register a timer event that counts down the session >- timeout second-wise.""" >- >- # count down the remaining time >- user._time_remaining -= 1 >- >- session = UMCP_Dispatcher.sessions.get(user.sessionid) >- if user._time_remaining <= 0 and (not session or not session._requestid2response_queue): >- self._log('info', 'session timed out') >- self.sessions.pop(user.sessionid, None) >- user.on_logout() >- return >- >- # count down the timer second-wise (in order to avoid problems when >- # changing the system time, e.g. via rdate) >- notifier.timer_add(1000, lambda: self._session_timeout_timer(user)) >- > > class CPgeneric(Ressource): > >@@ -902,8 +869,7 @@ class CPGet(CPgeneric): > raise UMC_HTTPError(UNAUTHORIZED) > info['username'] = user.username > info['auth_type'] = user.saml and 'SAML' >- info['remaining'] = user.time_remaining >- info['validity'] = user.session_validity >+ info['remaining'] = int(user.session_end_time - time.time()) > return json.dumps({"status": 200, "result": info, "message": ""}).encode('ASCII') > > @cherrypy.expose >@@ -1035,7 +1001,7 @@ class CPAuth(CPgeneric): > CORE.info('CPAuth/auth/sso: got new auth request (%s:%s <=> %s)' % (get_ip_address(), remote.port, remote.name)) > > user = self.get_user() >- if not user or not user.saml or user.timed_out(): >+ if not user or not user.saml or user.timed_out(time.time()): > # redirect user to login page in case he's not authenticated or his session timed out > raise HTTPRedirect('/univention/saml/') > >@@ -1638,6 +1604,7 @@ class UMC_HTTP_Daemon(DaemonRunner): > notifier.init(notifier.GENERIC) > notifier.dispatch.MIN_TIMER = get_int('umc/http/dispatch-interval', notifier.dispatch.MIN_TIMER) > notifier.dispatcher_add(UMCP_Dispatcher.check_queue) >+ notifier.timer_add(1000, UMCP_Dispatcher.session_timeout_timer) > notifier.loop() > except (SystemExit, KeyboardInterrupt) as exc: > # stop the web server
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 52272
:
10536
| 10571