diff -r 000000000000 -r b97547f5f1fa web/views/authentication.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/views/authentication.py Wed Nov 05 15:52:50 2008 +0100 @@ -0,0 +1,103 @@ +"""user authentication component + +:organization: Logilab +:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +""" +__docformat__ = "restructuredtext en" + +from logilab.common.decorators import clear_cache + +from cubicweb import AuthenticationError, BadConnectionId +from cubicweb.dbapi import repo_connect, ConnectionProperties +from cubicweb.web import ExplicitLogin, InvalidSession +from cubicweb.web.application import AbstractAuthenticationManager + + +class RepositoryAuthenticationManager(AbstractAuthenticationManager): + """authenticate user associated to a request and check session validity""" + + def __init__(self): + self.repo = self.config.repository(self.vreg) + self.log_queries = self.config['query-log-file'] + + def validate_session(self, req, session): + """check session validity, and return eventually hijacked session + + :raise InvalidSession: + if session is corrupted for a reason or another and should be closed + """ + # with this authentication manager, session is actually a dbapi + # connection + cnx = session + login = req.get_authorization()[0] + try: + # calling cnx.user() check connection validity, raise + # BadConnectionId on failure + user = cnx.user(req) + if login and user.login != login: + cnx.close() + raise InvalidSession('login mismatch') + except BadConnectionId: + # check if a connection should be automatically restablished + if (login is None or login == cnx.login): + login, password = cnx.login, cnx.password + cnx = self.authenticate(req, login, password) + user = cnx.user(req) + # backport session's data + cnx.data = session.data + else: + raise InvalidSession('bad connection id') + # associate the connection to the current request + req.set_connection(cnx, user) + return cnx + + def authenticate(self, req, _login=None, _password=None): + """authenticate user and return corresponding user object + + :raise ExplicitLogin: if authentication is required (no authentication + info found or wrong user/password) + + Note: this method is violating AuthenticationManager interface by + returning a session instance instead of the user. This is expected by + the InMemoryRepositorySessionManager. + """ + if _login is not None: + login, password = _login, _password + else: + login, password = req.get_authorization() + if not login: + # No session and no login -> try anonymous + login, password = self.vreg.config.anonymous_user() + if not login: # anonymous not authorized + raise ExplicitLogin() + # remove possibly cached cursor coming from closed connection + clear_cache(req, 'cursor') + cnxprops = ConnectionProperties(self.vreg.config.repo_method, + close=False, log=self.log_queries) + try: + cnx = repo_connect(self.repo, login, password, cnxprops=cnxprops) + except AuthenticationError: + req.set_message(req._('authentication failure')) + # restore an anonymous connection if possible + anonlogin, anonpassword = self.vreg.config.anonymous_user() + if anonlogin and anonlogin != login: + cnx = repo_connect(self.repo, anonlogin, anonpassword, + cnxprops=cnxprops) + self._init_cnx(cnx, anonlogin, anonpassword) + else: + raise ExplicitLogin() + else: + self._init_cnx(cnx, login, password) + # associate the connection to the current request + req.set_connection(cnx) + return cnx + + def _init_cnx(self, cnx, login, password): + # decorate connection + if login == self.vreg.config.anonymous_user()[0]: + cnx.anonymous_connection = True + cnx.vreg = self.vreg + cnx.login = login + cnx.password = password +