server/repository.py
branchstable
changeset 5587 72679e450f6d
parent 5426 0d4853a6e5ee
child 5590 a56eb02f9ce7
child 5606 61b28589d33f
equal deleted inserted replaced
5586:aabe082fee02 5587:72679e450f6d
    23 
    23 
    24 * brings these classes all together to provide a single access
    24 * brings these classes all together to provide a single access
    25   point to a cubicweb instance.
    25   point to a cubicweb instance.
    26 * handles session management
    26 * handles session management
    27 * provides method for pyro registration, to call if pyro is enabled
    27 * provides method for pyro registration, to call if pyro is enabled
    28 
       
    29 
       
    30 """
    28 """
       
    29 
    31 from __future__ import with_statement
    30 from __future__ import with_statement
    32 
    31 
    33 __docformat__ = "restructuredtext en"
    32 __docformat__ = "restructuredtext en"
    34 
    33 
    35 import sys
    34 import sys
       
    35 import threading
    36 import Queue
    36 import Queue
    37 from os.path import join
    37 from os.path import join
    38 from datetime import datetime
    38 from datetime import datetime
    39 from time import time, localtime, strftime
    39 from time import time, localtime, strftime
    40 
    40 
   313         self._available_pools.put_nowait(pool)
   313         self._available_pools.put_nowait(pool)
   314 
   314 
   315     def pinfo(self):
   315     def pinfo(self):
   316         # XXX: session.pool is accessed from a local storage, would be interesting
   316         # XXX: session.pool is accessed from a local storage, would be interesting
   317         #      to see if there is a pool set in any thread specific data)
   317         #      to see if there is a pool set in any thread specific data)
   318         import threading
       
   319         return '%s: %s (%s)' % (self._available_pools.qsize(),
   318         return '%s: %s (%s)' % (self._available_pools.qsize(),
   320                                 ','.join(session.user.login for session in self._sessions.values()
   319                                 ','.join(session.user.login for session in self._sessions.values()
   321                                          if session.pool),
   320                                          if session.pool),
   322                                 threading.currentThread())
   321                                 threading.currentThread())
   323     def shutdown(self):
   322     def shutdown(self):
   360             self.info('sql cache usage: %s/%s (%s%%)', hits+ misses, nocache,
   359             self.info('sql cache usage: %s/%s (%s%%)', hits+ misses, nocache,
   361                       ((hits + misses) * 100) / (hits + misses + nocache))
   360                       ((hits + misses) * 100) / (hits + misses + nocache))
   362         except ZeroDivisionError:
   361         except ZeroDivisionError:
   363             pass
   362             pass
   364 
   363 
       
   364     def _login_from_email(self, login):
       
   365         session = self.internal_session()
       
   366         try:
       
   367             rset = session.execute('Any L WHERE U login L, U primary_email M, '
       
   368                                    'M address %(login)s', {'login': login},
       
   369                                    build_descr=False)
       
   370             if rset.rowcount == 1:
       
   371                 login = rset[0][0]
       
   372         finally:
       
   373             session.close()
       
   374         return login
       
   375 
       
   376     def authenticate_user(self, session, login, **kwargs):
       
   377         """validate login / password, raise AuthenticationError on failure
       
   378         return associated CWUser instance on success
       
   379         """
       
   380         if self.vreg.config['allow-email-login'] and '@' in login:
       
   381             login = self._login_from_email(login)
       
   382         for source in self.sources:
       
   383             if source.support_entity('CWUser'):
       
   384                 try:
       
   385                     eid = source.authenticate(session, login, **kwargs)
       
   386                     break
       
   387                 except AuthenticationError:
       
   388                     continue
       
   389         else:
       
   390             raise AuthenticationError('authentication failed with all sources')
       
   391         cwuser = self._build_user(session, eid)
       
   392         if self.config.consider_user_state and \
       
   393                not cwuser.state in cwuser.AUTHENTICABLE_STATES:
       
   394             raise AuthenticationError('user is not in authenticable state')
       
   395         return cwuser
       
   396 
       
   397     def _build_user(self, session, eid):
       
   398         """return a CWUser entity for user with the given eid"""
       
   399         cls = self.vreg['etypes'].etype_class('CWUser')
       
   400         rql = cls.fetch_rql(session.user, ['X eid %(x)s'])
       
   401         rset = session.execute(rql, {'x': eid})
       
   402         assert len(rset) == 1, rset
       
   403         cwuser = rset.get_entity(0, 0)
       
   404         # pylint: disable-msg=W0104
       
   405         # prefetch / cache cwuser's groups and properties. This is especially
       
   406         # useful for internal sessions to avoid security insertions
       
   407         cwuser.groups
       
   408         cwuser.properties
       
   409         return cwuser
       
   410 
       
   411     # public (dbapi) interface ################################################
       
   412 
   365     def stats(self): # XXX restrict to managers session?
   413     def stats(self): # XXX restrict to managers session?
   366         import threading
       
   367         results = {}
   414         results = {}
   368         querier = self.querier
   415         querier = self.querier
   369         source = self.system_source
   416         source = self.system_source
   370         for size, maxsize, hits, misses, title in (
   417         for size, maxsize, hits, misses, title in (
   371             (len(querier._rql_cache), self.config['rql-cache-size'],
   418             (len(querier._rql_cache), self.config['rql-cache-size'],
   381         results['nb_open_sessions'] = len(self._sessions)
   428         results['nb_open_sessions'] = len(self._sessions)
   382         results['nb_active_threads'] = threading.activeCount()
   429         results['nb_active_threads'] = threading.activeCount()
   383         results['looping_tasks'] = ', '.join(str(t) for t in self._looping_tasks)
   430         results['looping_tasks'] = ', '.join(str(t) for t in self._looping_tasks)
   384         results['available_pools'] = self._available_pools.qsize()
   431         results['available_pools'] = self._available_pools.qsize()
   385         return results
   432         return results
   386 
       
   387     def _login_from_email(self, login):
       
   388         session = self.internal_session()
       
   389         try:
       
   390             rset = session.execute('Any L WHERE U login L, U primary_email M, '
       
   391                                    'M address %(login)s', {'login': login},
       
   392                                    build_descr=False)
       
   393             if rset.rowcount == 1:
       
   394                 login = rset[0][0]
       
   395         finally:
       
   396             session.close()
       
   397         return login
       
   398 
       
   399     def authenticate_user(self, session, login, **kwargs):
       
   400         """validate login / password, raise AuthenticationError on failure
       
   401         return associated CWUser instance on success
       
   402         """
       
   403         if self.vreg.config['allow-email-login'] and '@' in login:
       
   404             login = self._login_from_email(login)
       
   405         for source in self.sources:
       
   406             if source.support_entity('CWUser'):
       
   407                 try:
       
   408                     eid = source.authenticate(session, login, **kwargs)
       
   409                     break
       
   410                 except AuthenticationError:
       
   411                     continue
       
   412         else:
       
   413             raise AuthenticationError('authentication failed with all sources')
       
   414         cwuser = self._build_user(session, eid)
       
   415         if self.config.consider_user_state and \
       
   416                not cwuser.state in cwuser.AUTHENTICABLE_STATES:
       
   417             raise AuthenticationError('user is not in authenticable state')
       
   418         return cwuser
       
   419 
       
   420     def _build_user(self, session, eid):
       
   421         """return a CWUser entity for user with the given eid"""
       
   422         cls = self.vreg['etypes'].etype_class('CWUser')
       
   423         rql = cls.fetch_rql(session.user, ['X eid %(x)s'])
       
   424         rset = session.execute(rql, {'x': eid})
       
   425         assert len(rset) == 1, rset
       
   426         cwuser = rset.get_entity(0, 0)
       
   427         # pylint: disable-msg=W0104
       
   428         # prefetch / cache cwuser's groups and properties. This is especially
       
   429         # useful for internal sessions to avoid security insertions
       
   430         cwuser.groups
       
   431         cwuser.properties
       
   432         return cwuser
       
   433 
       
   434     # public (dbapi) interface ################################################
       
   435 
   433 
   436     def get_schema(self):
   434     def get_schema(self):
   437         """return the instance schema. This is a public method, not
   435         """return the instance schema. This is a public method, not
   438         requiring a session id
   436         requiring a session id
   439         """
   437         """