29 from rql import BadRQLQuery |
29 from rql import BadRQLQuery |
30 |
30 |
31 from cubicweb import set_log_methods, cwvreg |
31 from cubicweb import set_log_methods, cwvreg |
32 from cubicweb import ( |
32 from cubicweb import ( |
33 ValidationError, Unauthorized, AuthenticationError, NoSelectableObject, |
33 ValidationError, Unauthorized, AuthenticationError, NoSelectableObject, |
34 RepositoryError, CW_EVENT_MANAGER) |
34 RepositoryError, BadConnectionId, CW_EVENT_MANAGER) |
35 from cubicweb.dbapi import DBAPISession |
35 from cubicweb.dbapi import DBAPISession |
36 from cubicweb.web import LOGGER, component |
36 from cubicweb.web import LOGGER, component |
37 from cubicweb.web import ( |
37 from cubicweb.web import ( |
38 StatusResponse, DirectResponse, Redirect, NotFound, LogOut, |
38 StatusResponse, DirectResponse, Redirect, NotFound, LogOut, |
39 RemoteCallFailed, InvalidSession, RequestError) |
39 RemoteCallFailed, InvalidSession, RequestError) |
46 """manage session data associated to a session identifier""" |
46 """manage session data associated to a session identifier""" |
47 __regid__ = 'sessionmanager' |
47 __regid__ = 'sessionmanager' |
48 |
48 |
49 def __init__(self, vreg): |
49 def __init__(self, vreg): |
50 self.session_time = vreg.config['http-session-time'] or None |
50 self.session_time = vreg.config['http-session-time'] or None |
51 if self.session_time is not None: |
|
52 assert self.session_time > 0 |
|
53 self.cleanup_session_time = self.session_time |
|
54 else: |
|
55 self.cleanup_session_time = vreg.config['cleanup-session-time'] or 1440 * 60 |
|
56 assert self.cleanup_session_time > 0 |
|
57 self.cleanup_anon_session_time = vreg.config['cleanup-anonymous-session-time'] or 5 * 60 |
|
58 assert self.cleanup_anon_session_time > 0 |
|
59 self.authmanager = vreg['components'].select('authmanager', vreg=vreg) |
51 self.authmanager = vreg['components'].select('authmanager', vreg=vreg) |
|
52 interval = (self.session_time or 0) / 2. |
60 if vreg.config.anonymous_user() is not None: |
53 if vreg.config.anonymous_user() is not None: |
61 self.clean_sessions_interval = max( |
54 self.cleanup_anon_session_time = vreg.config['cleanup-anonymous-session-time'] or 5 * 60 |
62 5 * 60, min(self.cleanup_session_time / 2., |
55 assert self.cleanup_anon_session_time > 0 |
63 self.cleanup_anon_session_time / 2.)) |
56 if self.session_time is not None: |
64 else: |
57 self.cleanup_anon_session_time = min(self.session_time, |
65 self.clean_sessions_interval = max( |
58 self.cleanup_anon_session_time) |
66 5 * 60, |
59 interval = self.cleanup_anon_session_time / 2. |
67 self.cleanup_session_time / 2.) |
60 # we don't want to check session more than once every 5 minutes |
|
61 self.clean_sessions_interval = max(5 * 60, interval) |
68 |
62 |
69 def clean_sessions(self): |
63 def clean_sessions(self): |
70 """cleanup sessions which has not been unused since a given amount of |
64 """cleanup sessions which has not been unused since a given amount of |
71 time. Return the number of sessions which have been closed. |
65 time. Return the number of sessions which have been closed. |
72 """ |
66 """ |
73 self.debug('cleaning http sessions') |
67 self.debug('cleaning http sessions') |
|
68 session_time = self.session_time |
74 closed, total = 0, 0 |
69 closed, total = 0, 0 |
75 for session in self.current_sessions(): |
70 for session in self.current_sessions(): |
76 no_use_time = (time() - session.last_usage_time) |
|
77 total += 1 |
71 total += 1 |
78 if session.anonymous_session: |
72 try: |
79 if no_use_time >= self.cleanup_anon_session_time: |
73 last_usage_time = session.cnx.check() |
|
74 except BadConnectionId: |
|
75 self.close_session(session) |
|
76 closed += 1 |
|
77 else: |
|
78 no_use_time = (time() - last_usage_time) |
|
79 if session.anonymous_session: |
|
80 if no_use_time >= self.cleanup_anon_session_time: |
|
81 self.close_session(session) |
|
82 closed += 1 |
|
83 elif session_time is not None and no_use_time >= session_time: |
80 self.close_session(session) |
84 self.close_session(session) |
81 closed += 1 |
85 closed += 1 |
82 elif no_use_time >= self.cleanup_session_time: |
|
83 self.close_session(session) |
|
84 closed += 1 |
|
85 return closed, total - closed |
86 return closed, total - closed |
86 |
|
87 def has_expired(self, session): |
|
88 """return True if the web session associated to the session is expired |
|
89 """ |
|
90 return not (self.session_time is None or |
|
91 time() < session.last_usage_time + self.session_time) |
|
92 |
87 |
93 def current_sessions(self): |
88 def current_sessions(self): |
94 """return currently open sessions""" |
89 """return currently open sessions""" |
95 raise NotImplementedError() |
90 raise NotImplementedError() |
96 |
91 |
211 try: |
206 try: |
212 session = self.open_session(req) |
207 session = self.open_session(req) |
213 except AuthenticationError: |
208 except AuthenticationError: |
214 req.remove_cookie(cookie, self.SESSION_VAR) |
209 req.remove_cookie(cookie, self.SESSION_VAR) |
215 raise |
210 raise |
216 # remember last usage time for web session tracking |
|
217 session.last_usage_time = time() |
|
218 |
211 |
219 def get_session(self, req, sessionid): |
212 def get_session(self, req, sessionid): |
220 return self.session_manager.get_session(req, sessionid) |
213 return self.session_manager.get_session(req, sessionid) |
221 |
214 |
222 def open_session(self, req): |
215 def open_session(self, req): |
223 session = self.session_manager.open_session(req) |
216 session = self.session_manager.open_session(req) |
224 cookie = req.get_cookie() |
217 cookie = req.get_cookie() |
225 cookie[self.SESSION_VAR] = session.sessionid |
218 cookie[self.SESSION_VAR] = session.sessionid |
226 req.set_cookie(cookie, self.SESSION_VAR, maxage=None) |
219 req.set_cookie(cookie, self.SESSION_VAR, maxage=None) |
227 # remember last usage time for web session tracking |
|
228 session.last_usage_time = time() |
|
229 if not session.anonymous_session: |
220 if not session.anonymous_session: |
230 self._postlogin(req) |
221 self._postlogin(req) |
231 return session |
222 return session |
232 |
223 |
233 def _update_last_login_time(self, req): |
224 def _update_last_login_time(self, req): |