--- a/web/views/authentication.py Mon Apr 12 14:41:01 2010 +0200
+++ b/web/views/authentication.py Tue Apr 13 12:19:24 2010 +0200
@@ -12,7 +12,7 @@
from cubicweb import AuthenticationError, BadConnectionId
from cubicweb.view import Component
from cubicweb.dbapi import repo_connect, ConnectionProperties
-from cubicweb.web import ExplicitLogin, InvalidSession
+from cubicweb.web import InvalidSession
from cubicweb.web.application import AbstractAuthenticationManager
class NoAuthInfo(Exception): pass
@@ -28,9 +28,10 @@
"""
raise NotImplementedError()
- def authenticated(self, req, cnx, retreiver):
+ def authenticated(self, retreiver, req, cnx, login, authinfo):
"""callback when return authentication information have opened a
- repository connection successfully
+ repository connection successfully. Take care req has no session
+ attached yet, hence req.execute isn't available.
"""
pass
@@ -59,50 +60,51 @@
self.authinforetreivers = sorted(vreg['webauth'].possible_objects(vreg),
key=lambda x: x.order)
assert self.authinforetreivers
+ # 2-uple login / password, login is None when no anonymous access
+ # configured
self.anoninfo = vreg.config.anonymous_user()
+ if self.anoninfo[0]:
+ self.anoninfo = (self.anoninfo[0], {'password': self.anoninfo[1]})
def validate_session(self, req, session):
- """check session validity, and return eventually hijacked session
+ """check session validity, reconnecting it to the repository if the
+ associated connection expired in the repository side (hence the
+ necessity for this method). Return the connected user on success.
- :raise InvalidSession:
- if session is corrupted for a reason or another and should be closed
+ raise :exc:`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
+ cnx = session.cnx
login = req.get_authorization()[0]
+ # check cnx.login and not user.login, since in case of login by
+ # email, login and cnx.login are the email while user.login is the
+ # actual user login
+ if login and session.login != login:
+ raise InvalidSession('login mismatch')
try:
# calling cnx.user() check connection validity, raise
# BadConnectionId on failure
user = cnx.user(req)
- # check cnx.login and not user.login, since in case of login by
- # email, login and cnx.login are the email while user.login is the
- # actual user login
- if login and cnx.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):
- cnx = self._authenticate(req, cnx.login, cnx.authinfo)
+ if (login is None or login == session.login):
+ cnx = self._authenticate(session.login, session.authinfo)
user = cnx.user(req)
- # backport session's data
- cnx.data = session.data
+ session.cnx = cnx
else:
raise InvalidSession('bad connection id')
- # associate the connection to the current request
- req.set_connection(cnx, user)
- return cnx
+ return user
def authenticate(self, req):
- """authenticate user and return corresponding user object
+ """authenticate user using connection information found in the request,
+ and return corresponding a :class:`~cubicweb.dbapi.Connection` instance,
+ as well as login and authentication information dictionary used to open
+ the connection.
- :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.
+ raise :exc:`cubicweb.AuthenticationError` if authentication failed
+ (no authentication info found or wrong user/password)
"""
for retreiver in self.authinforetreivers:
try:
@@ -110,44 +112,28 @@
except NoAuthInfo:
continue
try:
- cnx = self._authenticate(req, login, authinfo)
- except ExplicitLogin:
+ cnx = self._authenticate(login, authinfo)
+ except AuthenticationError:
continue # the next one may succeed
for retreiver_ in self.authinforetreivers:
- retreiver_.authenticated(req, cnx, retreiver)
- break
- else:
- # false if no authentication info found, eg this is not an
- # authentication failure
- if 'login' in locals():
- req.set_message(req._('authentication failure'))
- cnx = self._open_anonymous_connection(req)
- return cnx
+ retreiver_.authenticated(retreiver, req, cnx, login, authinfo)
+ return cnx, login, authinfo
+ # false if no authentication info found, eg this is not an
+ # authentication failure
+ if 'login' in locals():
+ req.set_message(req._('authentication failure'))
+ login, authinfo = self.anoninfo
+ if login:
+ cnx = self._authenticate(login, authinfo)
+ cnx.anonymous_connection = True
+ return cnx, login, authinfo
+ raise AuthenticationError()
- def _authenticate(self, req, login, authinfo):
+ def _authenticate(self, login, authinfo):
cnxprops = ConnectionProperties(self.vreg.config.repo_method,
close=False, log=self.log_queries)
- try:
- cnx = repo_connect(self.repo, login, cnxprops=cnxprops, **authinfo)
- except AuthenticationError:
- raise ExplicitLogin()
- self._init_cnx(cnx, login, authinfo)
- # associate the connection to the current request
- req.set_connection(cnx)
+ cnx = repo_connect(self.repo, login, cnxprops=cnxprops, **authinfo)
+ # decorate connection
+ cnx.vreg = self.vreg
return cnx
- def _open_anonymous_connection(self, req):
- # restore an anonymous connection if possible
- login, password = self.anoninfo
- if login:
- cnx = self._authenticate(req, login, {'password': password})
- cnx.anonymous_connection = True
- return cnx
- raise ExplicitLogin()
-
- def _init_cnx(self, cnx, login, authinfo):
- # decorate connection
- cnx.vreg = self.vreg
- cnx.login = login
- cnx.authinfo = authinfo
-