24 from cubicweb import (RepositoryError, Unauthorized, AuthenticationError, |
24 from cubicweb import (RepositoryError, Unauthorized, AuthenticationError, |
25 BadConnectionId) |
25 BadConnectionId) |
26 from cubicweb.web import InvalidSession, Redirect |
26 from cubicweb.web import InvalidSession, Redirect |
27 from cubicweb.web.application import AbstractSessionManager |
27 from cubicweb.web.application import AbstractSessionManager |
28 from cubicweb.dbapi import ProgrammingError, DBAPISession |
28 from cubicweb.dbapi import ProgrammingError, DBAPISession |
|
29 from cubicweb import repoapi |
29 |
30 |
30 |
31 |
31 class InMemoryRepositorySessionManager(AbstractSessionManager): |
32 class InMemoryRepositorySessionManager(AbstractSessionManager): |
32 """manage session data associated to a session identifier""" |
33 """manage session data associated to a session identifier""" |
33 |
34 |
51 def get_session(self, req, sessionid): |
52 def get_session(self, req, sessionid): |
52 """return existing session for the given session identifier""" |
53 """return existing session for the given session identifier""" |
53 if sessionid not in self._sessions: |
54 if sessionid not in self._sessions: |
54 raise InvalidSession() |
55 raise InvalidSession() |
55 session = self._sessions[sessionid] |
56 session = self._sessions[sessionid] |
56 if session.cnx: |
57 try: |
57 try: |
58 user = self.authmanager.validate_session(req, session) |
58 user = self.authmanager.validate_session(req, session) |
59 except InvalidSession: |
59 except InvalidSession: |
60 self.close_session(session) |
60 # invalid session |
61 raise |
61 self.close_session(session) |
62 if session.closed: |
62 raise |
63 self.close_session(session) |
|
64 raise InvalidSession() |
63 return session |
65 return session |
64 |
66 |
65 def open_session(self, req): |
67 def open_session(self, req): |
66 """open and return a new session for the given request. The session is |
68 """open and return a new session for the given request. The session is |
67 also bound to the request. |
69 also bound to the request. |
68 |
70 |
69 raise :exc:`cubicweb.AuthenticationError` if authentication failed |
71 raise :exc:`cubicweb.AuthenticationError` if authentication failed |
70 (no authentication info found or wrong user/password) |
72 (no authentication info found or wrong user/password) |
71 """ |
73 """ |
72 cnx, login = self.authmanager.authenticate(req) |
74 session, login = self.authmanager.authenticate(req) |
73 session = DBAPISession(cnx, login) |
|
74 self._sessions[session.sessionid] = session |
75 self._sessions[session.sessionid] = session |
75 return session |
76 return session |
76 |
77 |
77 def postlogin(self, req, session): |
78 def postlogin(self, req, session): |
78 """postlogin: the user have been related to a session |
79 """postlogin: the user have been related to a session |
85 # XXX: this should be in a post login hook in the repository, but there |
86 # XXX: this should be in a post login hook in the repository, but there |
86 # we can't differentiate actual login of automatic session |
87 # we can't differentiate actual login of automatic session |
87 # reopening. Is it actually a problem? |
88 # reopening. Is it actually a problem? |
88 if 'last_login_time' in req.vreg.schema: |
89 if 'last_login_time' in req.vreg.schema: |
89 self._update_last_login_time(session) |
90 self._update_last_login_time(session) |
90 req.set_message(req._('welcome %s !') % session.cnx.user().login) |
91 req.set_message(req._('welcome %s !') % session.user.login) |
91 |
92 |
92 def _update_last_login_time(self, session): |
93 def _update_last_login_time(self, session): |
93 # XXX should properly detect missing permission / non writeable source |
94 # XXX should properly detect missing permission / non writeable source |
94 # and avoid "except (RepositoryError, Unauthorized)" below |
95 # and avoid "except (RepositoryError, Unauthorized)" below |
95 try: |
96 try: |
96 cu = session.cnx.cursor() |
97 cnx = repoapi.ClientConnection(session) |
97 cu.execute('SET X last_login_time NOW WHERE X eid %(x)s', |
98 with cnx: |
98 {'x' : session.cnx.user().eid}) |
99 cnx.execute('SET X last_login_time NOW WHERE X eid %(x)s', |
99 session.cnx.commit() |
100 {'x' : session.user.eid}) |
|
101 cnx.commit() |
100 except (RepositoryError, Unauthorized): |
102 except (RepositoryError, Unauthorized): |
101 session.cnx.rollback() |
103 pass |
102 except Exception: |
|
103 session.cnx.rollback() |
|
104 raise |
|
105 |
104 |
106 def close_session(self, session): |
105 def close_session(self, session): |
107 """close session on logout or on invalid session detected (expired out, |
106 """close session on logout or on invalid session detected (expired out, |
108 corrupted...) |
107 corrupted...) |
109 """ |
108 """ |
110 self.info('closing http session %s' % session.sessionid) |
109 self.info('closing http session %s' % session.sessionid) |
111 del self._sessions[session.sessionid] |
110 self._sessions.pop(session.sessionid, None) |
112 if session.cnx: |
111 if not session.closed: |
113 try: |
112 session.repo.close(session.id) |
114 session.cnx.close() |
|
115 except (ProgrammingError, BadConnectionId): # expired on the repository side |
|
116 pass |
|
117 session.cnx = None |
|