web/views/authentication.py
changeset 0 b97547f5f1fa
child 1488 6da89a703c5a
equal deleted inserted replaced
-1:000000000000 0:b97547f5f1fa
       
     1 """user authentication component
       
     2 
       
     3 :organization: Logilab
       
     4 :copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     5 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     6 """
       
     7 __docformat__ = "restructuredtext en"
       
     8 
       
     9 from logilab.common.decorators import clear_cache
       
    10 
       
    11 from cubicweb import AuthenticationError, BadConnectionId
       
    12 from cubicweb.dbapi import repo_connect, ConnectionProperties
       
    13 from cubicweb.web import ExplicitLogin, InvalidSession
       
    14 from cubicweb.web.application import AbstractAuthenticationManager
       
    15     
       
    16 
       
    17 class RepositoryAuthenticationManager(AbstractAuthenticationManager):
       
    18     """authenticate user associated to a request and check session validity"""
       
    19     
       
    20     def __init__(self):
       
    21         self.repo = self.config.repository(self.vreg)
       
    22         self.log_queries = self.config['query-log-file']
       
    23 
       
    24     def validate_session(self, req, session):
       
    25         """check session validity, and return eventually hijacked session
       
    26 
       
    27         :raise InvalidSession:
       
    28           if session is corrupted for a reason or another and should be closed
       
    29         """
       
    30         # with this authentication manager, session is actually a dbapi
       
    31         # connection
       
    32         cnx = session
       
    33         login = req.get_authorization()[0]
       
    34         try:
       
    35             # calling cnx.user() check connection validity, raise
       
    36             # BadConnectionId on failure
       
    37             user = cnx.user(req)
       
    38             if login and user.login != login:
       
    39                 cnx.close()
       
    40                 raise InvalidSession('login mismatch')
       
    41         except BadConnectionId:
       
    42             # check if a connection should be automatically restablished
       
    43             if (login is None or login == cnx.login):
       
    44                 login, password = cnx.login, cnx.password
       
    45                 cnx = self.authenticate(req, login, password)
       
    46                 user = cnx.user(req)
       
    47                 # backport session's data
       
    48                 cnx.data = session.data
       
    49             else:
       
    50                 raise InvalidSession('bad connection id')
       
    51         # associate the connection to the current request
       
    52         req.set_connection(cnx, user)
       
    53         return cnx
       
    54         
       
    55     def authenticate(self, req, _login=None, _password=None):
       
    56         """authenticate user and return corresponding user object
       
    57         
       
    58         :raise ExplicitLogin: if authentication is required (no authentication
       
    59         info found or wrong user/password)
       
    60 
       
    61         Note: this method is violating AuthenticationManager interface by
       
    62         returning a session instance instead of the user. This is expected by
       
    63         the InMemoryRepositorySessionManager.
       
    64         """
       
    65         if _login is not None:
       
    66             login, password = _login, _password
       
    67         else:
       
    68             login, password = req.get_authorization()
       
    69         if not login:
       
    70             # No session and no login -> try anonymous
       
    71             login, password = self.vreg.config.anonymous_user()
       
    72             if not login: # anonymous not authorized
       
    73                 raise ExplicitLogin()
       
    74         # remove possibly cached cursor coming from closed connection
       
    75         clear_cache(req, 'cursor')
       
    76         cnxprops = ConnectionProperties(self.vreg.config.repo_method,
       
    77                                         close=False, log=self.log_queries)
       
    78         try:
       
    79             cnx = repo_connect(self.repo, login, password, cnxprops=cnxprops)
       
    80         except AuthenticationError:
       
    81             req.set_message(req._('authentication failure'))
       
    82             # restore an anonymous connection if possible
       
    83             anonlogin, anonpassword = self.vreg.config.anonymous_user()
       
    84             if anonlogin and anonlogin != login:
       
    85                 cnx = repo_connect(self.repo, anonlogin, anonpassword,
       
    86                                    cnxprops=cnxprops)
       
    87                 self._init_cnx(cnx, anonlogin, anonpassword)
       
    88             else:
       
    89                 raise ExplicitLogin()
       
    90         else:
       
    91             self._init_cnx(cnx, login, password)
       
    92         # associate the connection to the current request
       
    93         req.set_connection(cnx)
       
    94         return cnx
       
    95 
       
    96     def _init_cnx(self, cnx, login, password):
       
    97         # decorate connection
       
    98         if login == self.vreg.config.anonymous_user()[0]:
       
    99             cnx.anonymous_connection = True
       
   100         cnx.vreg = self.vreg
       
   101         cnx.login = login
       
   102         cnx.password = password
       
   103