[repository auth] cleanup email login by turning it into a proper repo-side authentication plugin
--- a/server/repository.py Wed Jan 19 12:47:06 2011 +0100
+++ b/server/repository.py Wed Jan 19 12:47:08 2011 +0100
@@ -430,33 +430,24 @@
except ZeroDivisionError:
pass
- def _login_from_email(self, login):
- session = self.internal_session()
- try:
- rset = session.execute('Any L WHERE U login L, U primary_email M, '
- 'M address %(login)s', {'login': login},
- build_descr=False)
- if rset.rowcount == 1:
- login = rset[0][0]
- finally:
- session.close()
- return login
-
- def authenticate_user(self, session, login, **kwargs):
- """validate login / password, raise AuthenticationError on failure
- return associated CWUser instance on success
+ def check_auth_info(self, session, login, authinfo):
+ """validate authentication, raise AuthenticationError on failure, return
+ associated CWUser's eid on success.
"""
- if self.vreg.config['allow-email-login'] and '@' in login:
- login = self._login_from_email(login)
for source in self.sources:
if source.support_entity('CWUser'):
try:
- eid = source.authenticate(session, login, **kwargs)
- break
+ return source.authenticate(session, login, **authinfo)
except AuthenticationError:
continue
else:
raise AuthenticationError('authentication failed with all sources')
+
+ def authenticate_user(self, session, login, **authinfo):
+ """validate login / password, raise AuthenticationError on failure
+ return associated CWUser instance on success
+ """
+ eid = self.check_auth_info(session, login, authinfo)
cwuser = self._build_user(session, eid)
if self.config.consider_user_state and \
not cwuser.cw_adapt_to('IWorkflowable').state in cwuser.AUTHENTICABLE_STATES:
--- a/server/sources/native.py Wed Jan 19 12:47:06 2011 +0100
+++ b/server/sources/native.py Wed Jan 19 12:47:08 2011 +0100
@@ -266,6 +266,8 @@
def __init__(self, repo, source_config, *args, **kwargs):
SQLAdapterMixIn.__init__(self, source_config)
self.authentifiers = [LoginPasswordAuthentifier(self)]
+ if repo.config['allow-email-login']:
+ self.authentifiers.insert(0, EmailPasswordAuthentifier(self))
AbstractSource.__init__(self, repo, source_config, *args, **kwargs)
# sql generator
self._rql_sqlgen = self.sqlgen_class(self.schema, self.dbhelper,
@@ -1495,3 +1497,19 @@
return rset[0][0]
except IndexError:
raise AuthenticationError('bad password')
+
+
+class EmailPasswordAuthentifier(BaseAuthentifier):
+ def authenticate(self, session, login, **authinfo):
+ # email_auth flag prevent from infinite recursion (call to
+ # repo.check_auth_info at the end of this method may lead us here again)
+ if not '@' in login or authinfo.pop('email_auth', None):
+ raise AuthenticationError('not an email')
+ rset = session.execute('Any L WHERE U login L, U primary_email M, '
+ 'M address %(login)s', {'login': login},
+ build_descr=False)
+ if rset.rowcount != 1:
+ raise AuthenticationError('unexisting email')
+ login = rset.rows[0][0]
+ authinfo['email_auth'] = True
+ return self.source.repo.check_auth_info(session, login, authinfo)
--- a/web/test/unittest_application.py Wed Jan 19 12:47:06 2011 +0100
+++ b/web/test/unittest_application.py Wed Jan 19 12:47:08 2011 +0100
@@ -22,7 +22,7 @@
from urllib import unquote
from logilab.common.testlib import TestCase, unittest_main
-from logilab.common.decorators import clear_cache
+from logilab.common.decorators import clear_cache, classproperty
from cubicweb import AuthenticationError, Unauthorized
from cubicweb.devtools.testlib import CubicWebTC
@@ -157,6 +157,15 @@
raise
self.app.error_handler = raise_hdlr
+ @classproperty
+ def config(cls):
+ try:
+ return cls.__dict__['_config']
+ except KeyError:
+ config = super(ApplicationTC, cls).config
+ config.global_set_option('allow-email-login', True)
+ return config
+
def test_cnx_user_groups_sync(self):
user = self.user()
self.assertEqual(user.groups, set(('managers',)))
@@ -347,7 +356,7 @@
self.execute('INSERT EmailAddress X: X address %(address)s, U primary_email X '
'WHERE U login %(login)s', {'address': address, 'login': login})
self.commit()
- # option allow-email-login not set
+ # # option allow-email-login not set
req, origsession = self.init_authentication('cookie')
# req.form['__login'] = address
# req.form['__password'] = self.admpassword