goa/appobjects/sessions.py
branchtls-sprint
changeset 1802 d628defebc17
parent 1131 544609e83317
child 1977 606923dff11b
equal deleted inserted replaced
1801:672acc730ce5 1802:d628defebc17
    39     """
    39     """
    40 
    40 
    41     def __init__(self, *args, **kwargs):
    41     def __init__(self, *args, **kwargs):
    42         super(GAEAuthenticationManager, self).__init__(*args, **kwargs)
    42         super(GAEAuthenticationManager, self).__init__(*args, **kwargs)
    43         self._repo = self.config.repository(vreg=self.vreg)
    43         self._repo = self.config.repository(vreg=self.vreg)
    44         
    44 
    45     def authenticate(self, req, _login=None, _password=None):
    45     def authenticate(self, req, _login=None, _password=None):
    46         """authenticate user and return an established connection for this user
    46         """authenticate user and return an established connection for this user
    47         
    47 
    48         :raise ExplicitLogin: if authentication is required (no authentication
    48         :raise ExplicitLogin: if authentication is required (no authentication
    49         info found or wrong user/password)
    49         info found or wrong user/password)
    50         """
    50         """
    51         if _login is not None:
    51         if _login is not None:
    52             login, password = _login, _password
    52             login, password = _login, _password
    73     """manage session data associated to a session identifier"""
    73     """manage session data associated to a session identifier"""
    74 
    74 
    75     def __init__(self, *args, **kwargs):
    75     def __init__(self, *args, **kwargs):
    76         super(GAEPersistentSessionManager, self).__init__(*args, **kwargs)
    76         super(GAEPersistentSessionManager, self).__init__(*args, **kwargs)
    77         self._repo = self.config.repository(vreg=self.vreg)
    77         self._repo = self.config.repository(vreg=self.vreg)
    78         
    78 
    79     def get_session(self, req, sessionid):
    79     def get_session(self, req, sessionid):
    80         """return existing session for the given session identifier"""
    80         """return existing session for the given session identifier"""
    81         # search a record for the given session
    81         # search a record for the given session
    82         key = Key.from_path('CubicWebSession', 'key_' + sessionid, parent=None)
    82         key = Key.from_path('CubicWebSession', 'key_' + sessionid, parent=None)
    83         try:
    83         try:
   124         record['login'] = cnx.login
   124         record['login'] = cnx.login
   125         record['password'] = cnx.password
   125         record['password'] = cnx.password
   126         record['anonymous_connection'] = cnx.anonymous_connection
   126         record['anonymous_connection'] = cnx.anonymous_connection
   127         Put(record)
   127         Put(record)
   128         return self._get_proxy(req, record, cnx, user)
   128         return self._get_proxy(req, record, cnx, user)
   129     
   129 
   130     def close_session(self, proxy):
   130     def close_session(self, proxy):
   131         """close session on logout or on invalid session detected (expired out,
   131         """close session on logout or on invalid session detected (expired out,
   132         corrupted...)
   132         corrupted...)
   133         """
   133         """
   134         proxy.close()
   134         proxy.close()
   135 
   135 
   136     def current_sessions(self):
   136     def current_sessions(self):
   137         for record in Query('CubicWebSession').Run():
   137         for record in Query('CubicWebSession').Run():
   138             yield ConnectionProxy(record)
   138             yield ConnectionProxy(record)
   139             
   139 
   140     def _get_proxy(self, req, record, cnx, user):
   140     def _get_proxy(self, req, record, cnx, user):
   141         proxy = ConnectionProxy(record, cnx, user)
   141         proxy = ConnectionProxy(record, cnx, user)
   142         user.req = req
   142         user.req = req
   143         req.set_connection(proxy, user)
   143         req.set_connection(proxy, user)
   144         return proxy
   144         return proxy
   145 
   145 
   146 
   146 
   147 class ConnectionProxy(object):
   147 class ConnectionProxy(object):
   148     
   148 
   149     def __init__(self, record, cnx=None, user=None):
   149     def __init__(self, record, cnx=None, user=None):
   150         self.__record = record
   150         self.__record = record
   151         self.__cnx = cnx
   151         self.__cnx = cnx
   152         self.__user = user
   152         self.__user = user
   153         self.__data = None
   153         self.__data = None
   154         self.__is_dirty = False
   154         self.__is_dirty = False
   155         self.sessionid = record.key().name()[4:] # remove 'key_' prefix
   155         self.sessionid = record.key().name()[4:] # remove 'key_' prefix
   156         
   156 
   157     def __repr__(self):
   157     def __repr__(self):
   158         sstr = '<ConnectionProxy %s' % self.sessionid
   158         sstr = '<ConnectionProxy %s' % self.sessionid
   159         if self.anonymous_connection:
   159         if self.anonymous_connection:
   160             sstr += ' (anonymous)'
   160             sstr += ' (anonymous)'
   161         elif self.__user:
   161         elif self.__user:
   162             sstr += ' for %s' % self.__user.login
   162             sstr += ' for %s' % self.__user.login
   163         sstr += ', last used %s>' % strftime('%T', localtime(self.last_usage_time))
   163         sstr += ', last used %s>' % strftime('%T', localtime(self.last_usage_time))
   164         return sstr
   164         return sstr
   165         
   165 
   166     def __getattribute__(self, name):
   166     def __getattribute__(self, name):
   167         try:
   167         try:
   168             return super(ConnectionProxy, self).__getattribute__(name)
   168             return super(ConnectionProxy, self).__getattribute__(name)
   169         except AttributeError:
   169         except AttributeError:
   170             return getattr(self.__cnx, name)
   170             return getattr(self.__cnx, name)
   172     def _set_last_usage_time(self, value):
   172     def _set_last_usage_time(self, value):
   173         self.__is_dirty = True
   173         self.__is_dirty = True
   174         self.__record['last_usage_time'] = value
   174         self.__record['last_usage_time'] = value
   175     def _get_last_usage_time(self):
   175     def _get_last_usage_time(self):
   176         return self.__record['last_usage_time']
   176         return self.__record['last_usage_time']
   177     
   177 
   178     last_usage_time = property(_get_last_usage_time, _set_last_usage_time)
   178     last_usage_time = property(_get_last_usage_time, _set_last_usage_time)
   179 
   179 
   180     @property
   180     @property
   181     def anonymous_connection(self):
   181     def anonymous_connection(self):
   182         # use get() for bw compat if sessions without anonymous information are
   182         # use get() for bw compat if sessions without anonymous information are
   183         # found. Set default to True to limit lifetime of those sessions.
   183         # found. Set default to True to limit lifetime of those sessions.
   184         return self.__record.get('anonymous_connection', True)
   184         return self.__record.get('anonymous_connection', True)
   185         
   185 
   186     @property
   186     @property
   187     @cached
   187     @cached
   188     def data(self):
   188     def data(self):
   189         if self.__record.get('data') is not None:
   189         if self.__record.get('data') is not None:
   190             try:
   190             try:
   192             except:
   192             except:
   193                 self.__is_dirty = True
   193                 self.__is_dirty = True
   194                 self.exception('corrupted session data for session %s',
   194                 self.exception('corrupted session data for session %s',
   195                                self.__cnx)
   195                                self.__cnx)
   196         return {}
   196         return {}
   197         
   197 
   198     def get_session_data(self, key, default=None, pop=False):
   198     def get_session_data(self, key, default=None, pop=False):
   199         """return value associated to `key` in session data"""
   199         """return value associated to `key` in session data"""
   200         if pop:
   200         if pop:
   201             try:
   201             try:
   202                 value = self.data.pop(key)
   202                 value = self.data.pop(key)
   204                 return value
   204                 return value
   205             except KeyError:
   205             except KeyError:
   206                 return default
   206                 return default
   207         else:
   207         else:
   208             return self.data.get(key, default)
   208             return self.data.get(key, default)
   209         
   209 
   210     def set_session_data(self, key, value):
   210     def set_session_data(self, key, value):
   211         """set value associated to `key` in session data"""
   211         """set value associated to `key` in session data"""
   212         self.data[key] = value
   212         self.data[key] = value
   213         self.__is_dirty = True
   213         self.__is_dirty = True
   214         
   214 
   215     def del_session_data(self, key):
   215     def del_session_data(self, key):
   216         """remove value associated to `key` in session data"""
   216         """remove value associated to `key` in session data"""
   217         try:
   217         try:
   218             del self.data[key]
   218             del self.data[key]
   219             self.__is_dirty = True
   219             self.__is_dirty = True
   220         except KeyError:
   220         except KeyError:
   221             pass    
   221             pass
   222             
   222 
   223     def commit(self):
   223     def commit(self):
   224         if self.__is_dirty:
   224         if self.__is_dirty:
   225             self.__save()
   225             self.__save()
   226         self.__cnx.commit()
   226         self.__cnx.commit()
   227 
   227 
   231 
   231 
   232     def close(self):
   232     def close(self):
   233         if self.__cnx is not None:
   233         if self.__cnx is not None:
   234             self.__cnx.close()
   234             self.__cnx.close()
   235         Delete(self.__record)
   235         Delete(self.__record)
   236         
   236 
   237     def __save(self):
   237     def __save(self):
   238         if self.__is_dirty:
   238         if self.__is_dirty:
   239             self.__record['data'] = Blob(dumps(self.data))
   239             self.__record['data'] = Blob(dumps(self.data))
   240             Put(self.__record)
   240             Put(self.__record)
   241             self.__is_dirty = False
   241             self.__is_dirty = False
   242 
   242 
   243     def user(self, req=None, props=None):
   243     def user(self, req=None, props=None):
   244         """return the User object associated to this connection"""
   244         """return the User object associated to this connection"""
   245         return self.__user
   245         return self.__user
   246         
   246 
   247 
   247 
   248 import logging
   248 import logging
   249 from cubicweb import set_log_methods
   249 from cubicweb import set_log_methods
   250 set_log_methods(ConnectionProxy, logging.getLogger('cubicweb.web.goa.session'))
   250 set_log_methods(ConnectionProxy, logging.getLogger('cubicweb.web.goa.session'))
   251 
   251 
   254 from cubicweb.web import application
   254 from cubicweb.web import application
   255 
   255 
   256 class SessionsCleaner(StartupView):
   256 class SessionsCleaner(StartupView):
   257     id = 'cleansessions'
   257     id = 'cleansessions'
   258     __select__ = none_rset() & match_user_groups('managers')
   258     __select__ = none_rset() & match_user_groups('managers')
   259     
   259 
   260     def call(self):
   260     def call(self):
   261         # clean web session
   261         # clean web session
   262         session_manager = application.SESSION_MANAGER
   262         session_manager = application.SESSION_MANAGER
   263         nbclosed, remaining = session_manager.clean_sessions()
   263         nbclosed, remaining = session_manager.clean_sessions()
   264         self.w(u'<div class="message">')
   264         self.w(u'<div class="message">')
   268         nbclosed = repo.clean_sessions()
   268         nbclosed = repo.clean_sessions()
   269         self.w(u'%s repository sessions closed<br/>\n' % nbclosed)
   269         self.w(u'%s repository sessions closed<br/>\n' % nbclosed)
   270         self.w(u'%s remaining sessions<br/>\n' % remaining)
   270         self.w(u'%s remaining sessions<br/>\n' % remaining)
   271         self.w(u'</div>')
   271         self.w(u'</div>')
   272 
   272 
   273         
   273 
   274 def registration_callback(vreg):
   274 def registration_callback(vreg):
   275     vreg.register(SessionsCleaner)
   275     vreg.register(SessionsCleaner)
   276     vreg.register(GAEAuthenticationManager, clear=True)
   276     vreg.register(GAEAuthenticationManager, clear=True)
   277     vreg.register(GAEPersistentSessionManager, clear=True)
   277     vreg.register(GAEPersistentSessionManager, clear=True)