--- a/web/views/authentication.py Tue Oct 13 15:59:47 2009 +0200
+++ b/web/views/authentication.py Tue Oct 13 16:00:09 2009 +0200
@@ -10,10 +10,50 @@
from logilab.common.decorators import clear_cache
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.application import AbstractAuthenticationManager
+class NoAuthInfo(Exception): pass
+
+
+class WebAuthInfoRetreiver(Component):
+ __registry__ = 'webauth'
+ order = None
+
+ def authentication_information(self, req):
+ """retreive authentication information from the given request, raise
+ NoAuthInfo if expected information is not found.
+ """
+ raise NotImplementedError()
+
+ def authenticated(self, req, cnx, retreiver):
+ """callback when return authentication information have opened a
+ repository connection successfully
+ """
+ pass
+
+
+class LoginPasswordRetreiver(WebAuthInfoRetreiver):
+ __regid__ = 'loginpwdauth'
+ order = 10
+
+ def __init__(self, vreg):
+ self.anoninfo = vreg.config.anonymous_user()
+
+ def authentication_information(self, req):
+ """retreive authentication information from the given request, raise
+ NoAuthInfo if expected information is not found.
+ """
+ login, password = req.get_authorization()
+ if not login:
+ # No session and no login -> try anonymous
+ login, password = self.anoninfo
+ if not login: # anonymous not authorized
+ raise NoAuthInfo()
+ return login, {'password': password}
+
class RepositoryAuthenticationManager(AbstractAuthenticationManager):
"""authenticate user associated to a request and check session validity"""
@@ -22,6 +62,9 @@
super(RepositoryAuthenticationManager, self).__init__(vreg)
self.repo = vreg.config.repository(vreg)
self.log_queries = vreg.config['query-log-file']
+ self.authinforetreivers = sorted(vreg['webauth'].possible_objects(vreg),
+ key=lambda x: x.order)
+ assert self.authinforetreivers
def validate_session(self, req, session):
"""check session validity, and return eventually hijacked session
@@ -46,8 +89,7 @@
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)
+ cnx = self._authenticate(req, cnx.login, cnx.authinfo)
user = cnx.user(req)
# backport session's data
cnx.data = session.data
@@ -57,7 +99,7 @@
req.set_connection(cnx, user)
return cnx
- def authenticate(self, req, _login=None, _password=None):
+ def authenticate(self, req):
"""authenticate user and return corresponding user object
:raise ExplicitLogin: if authentication is required (no authentication
@@ -67,22 +109,26 @@
returning a session instance instead of the user. This is expected by
the InMemoryRepositorySessionManager.
"""
- if _login is not None:
- login, password = _login, _password
+ for retreiver in self.authinforetreivers:
+ try:
+ login, authinfo = retreiver.authentication_information(req)
+ except NoAuthInfo:
+ continue
+ cnx = self._authenticate(req, login, authinfo)
+ break
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()
+ raise ExplicitLogin()
+ for retreiver_ in self.authinforetreivers:
+ retreiver_.authenticated(req, cnx, retreiver)
+ return cnx
+
+ def _authenticate(self, req, login, authinfo):
# 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=password,
- cnxprops=cnxprops)
+ cnx = repo_connect(self.repo, login, cnxprops=cnxprops, **authinfo)
except AuthenticationError:
req.set_message(req._('authentication failure'))
# restore an anonymous connection if possible
@@ -90,20 +136,20 @@
if anonlogin and anonlogin != login:
cnx = repo_connect(self.repo, anonlogin, password=anonpassword,
cnxprops=cnxprops)
- self._init_cnx(cnx, anonlogin, anonpassword)
+ self._init_cnx(cnx, anonlogin, {'password': anonpassword})
else:
raise ExplicitLogin()
else:
- self._init_cnx(cnx, login, password)
+ self._init_cnx(cnx, login, authinfo)
# associate the connection to the current request
req.set_connection(cnx)
return cnx
- def _init_cnx(self, cnx, login, password):
+ def _init_cnx(self, cnx, login, authinfo):
# decorate connection
if login == self.vreg.config.anonymous_user()[0]:
cnx.anonymous_connection = True
cnx.vreg = self.vreg
cnx.login = login
- cnx.password = password
+ cnx.authinfo = authinfo