[server] use a connection instead of a session for user authentication
authorJulien Cristau <julien.cristau@logilab.fr>
Wed, 29 Jan 2014 13:43:42 +0100
changeset 9512 88dc96fc9fc1
parent 9511 241b1232ed7f
child 9513 a7e0746f010c
[server] use a connection instead of a session for user authentication
server/repository.py
server/sources/__init__.py
server/sources/ldapfeed.py
server/sources/native.py
--- a/server/repository.py	Tue Feb 11 17:29:58 2014 +0100
+++ b/server/repository.py	Wed Jan 29 13:43:42 2014 +0100
@@ -448,7 +448,7 @@
         except ZeroDivisionError:
             pass
 
-    def check_auth_info(self, session, login, authinfo):
+    def check_auth_info(self, cnx, login, authinfo):
         """validate authentication, raise AuthenticationError on failure, return
         associated CWUser's eid on success.
         """
@@ -457,30 +457,31 @@
         for source in self.sources_by_uri.itervalues():
             if self.config.source_enabled(source) and source.support_entity('CWUser'):
                 try:
-                    return source.authenticate(session, login, **authinfo)
+                    with cnx.ensure_cnx_set:
+                        return source.authenticate(cnx, login, **authinfo)
                 except AuthenticationError:
                     continue
         else:
             raise AuthenticationError('authentication failed with all sources')
 
-    def authenticate_user(self, session, login, **authinfo):
+    def authenticate_user(self, cnx, 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)
+        eid = self.check_auth_info(cnx, login, authinfo)
+        cwuser = self._build_user(cnx, eid)
         if self.config.consider_user_state and \
                not cwuser.cw_adapt_to('IWorkflowable').state in cwuser.AUTHENTICABLE_STATES:
             raise AuthenticationError('user is not in authenticable state')
         return cwuser
 
-    def _build_user(self, session, eid):
+    def _build_user(self, cnx, eid):
         """return a CWUser entity for user with the given eid"""
-        with session.ensure_cnx_set:
+        with cnx.ensure_cnx_set:
             cls = self.vreg['etypes'].etype_class('CWUser')
-            st = cls.fetch_rqlst(session.user, ordermethod=None)
+            st = cls.fetch_rqlst(cnx.user, ordermethod=None)
             st.add_eid_restriction(st.get_variable('X'), 'x', 'Substitute')
-            rset = session.execute(st.as_string(), {'x': eid})
+            rset = cnx.execute(st.as_string(), {'x': eid})
             assert len(rset) == 1, rset
             cwuser = rset.get_entity(0, 0)
             # pylint: disable=W0104
@@ -681,9 +682,9 @@
         """
         cnxprops = kwargs.pop('cnxprops', None)
         # use an internal connection
-        with self.internal_session() as session:
+        with self.internal_cnx() as cnx:
             # try to get a user object
-            user = self.authenticate_user(session, login, **kwargs)
+            user = self.authenticate_user(cnx, login, **kwargs)
         session = Session(user, self, cnxprops)
         if threading.currentThread() in self._pyro_sessions:
             # assume no pyro client does one get_repository followed by
--- a/server/sources/__init__.py	Tue Feb 11 17:29:58 2014 +0100
+++ b/server/sources/__init__.py	Wed Jan 29 13:43:42 2014 +0100
@@ -346,7 +346,7 @@
 
     # user authentication api ##################################################
 
-    def authenticate(self, session, login, **kwargs):
+    def authenticate(self, cnx, login, **kwargs):
         """if the source support CWUser entity type, it should implement
         this method which should return CWUser eid for the given login/password
         if this account is defined in this source and valid login / password is
@@ -356,7 +356,7 @@
 
     # RQL query api ############################################################
 
-    def syntax_tree_search(self, session, union,
+    def syntax_tree_search(self, cnx, union,
                            args=None, cachekey=None, varmap=None, debug=0):
         """return result from this source for a rql query (actually from a rql
         syntax tree and a solution dictionary mapping each used variable to a
--- a/server/sources/ldapfeed.py	Tue Feb 11 17:29:58 2014 +0100
+++ b/server/sources/ldapfeed.py	Wed Jan 29 13:43:42 2014 +0100
@@ -219,7 +219,7 @@
             hostport = '%s:%s' % (hostport, PROTO_PORT[protocol])
         return protocol, hostport
 
-    def authenticate(self, session, login, password=None, **kwargs):
+    def authenticate(self, cnx, login, password=None, **kwargs):
         """return CWUser eid for the given login/password if this account is
         defined in this source, else raise `AuthenticationError`
 
@@ -237,7 +237,7 @@
         searchstr = '(&%s)' % ''.join(searchfilter)
         # first search the user
         try:
-            user = self._search(session, self.user_base_dn,
+            user = self._search(cnx, self.user_base_dn,
                                 self.user_base_scope, searchstr)[0]
         except (IndexError, ldap.SERVER_DOWN):
             # no such user
@@ -252,7 +252,7 @@
         except Exception:
             self.error('while trying to authenticate %s', user, exc_info=True)
             raise AuthenticationError()
-        eid = self.repo.extid2eid(self, user['dn'], 'CWUser', session, {})
+        eid = self.repo.extid2eid(self, user['dn'], 'CWUser', session=cnx, insert=False)
         if eid < 0:
             # user has been moved away from this source
             raise AuthenticationError()
@@ -314,28 +314,28 @@
         #from ldap import sasl
         #conn.sasl_interactive_bind_s('', sasl.gssapi())
 
-    def _search(self, session, base, scope,
+    def _search(self, cnx, base, scope,
                 searchstr='(objectClass=*)', attrs=()):
         """make an ldap query"""
         self.debug('ldap search %s %s %s %s %s', self.uri, base, scope,
                    searchstr, list(attrs))
         if self._conn is None:
             self._conn = self._connect()
-        cnx = self._conn
+        ldapcnx = self._conn
         try:
-            res = cnx.search_s(base, scope, searchstr, attrs)
+            res = ldapcnx.search_s(base, scope, searchstr, attrs)
         except ldap.PARTIAL_RESULTS:
-            res = cnx.result(all=0)[1]
+            res = ldapcnx.result(all=0)[1]
         except ldap.NO_SUCH_OBJECT:
             self.info('ldap NO SUCH OBJECT %s %s %s', base, scope, searchstr)
-            self._process_no_such_object(session, base)
+            self._process_no_such_object(cnx, base)
             return []
         # except ldap.REFERRAL as e:
-        #     cnx = self.handle_referral(e)
+        #     ldapcnx = self.handle_referral(e)
         #     try:
-        #         res = cnx.search_s(base, scope, searchstr, attrs)
+        #         res = ldapcnx.search_s(base, scope, searchstr, attrs)
         #     except ldap.PARTIAL_RESULTS:
-        #         res_type, res = cnx.result(all=0)
+        #         res_type, res = ldapcnx.result(all=0)
         result = []
         for rec_dn, rec_dict in res:
             # When used against Active Directory, "rec_dict" may not be
@@ -380,7 +380,7 @@
             itemdict[member] = [itemdict[member]]
         return itemdict
 
-    def _process_no_such_object(self, session, dn):
+    def _process_no_such_object(self, cnx, dn):
         """Some search return NO_SUCH_OBJECT error, handle this (usually because
         an object whose dn is no more existent in ldap as been encountered).
 
--- a/server/sources/native.py	Tue Feb 11 17:29:58 2014 +0100
+++ b/server/sources/native.py	Wed Jan 29 13:43:42 2014 +0100
@@ -439,13 +439,13 @@
         # can't claim not supporting a relation
         return True #not rtype == 'content_for'
 
-    def authenticate(self, session, login, **kwargs):
+    def authenticate(self, cnx, login, **kwargs):
         """return CWUser eid for the given login and other authentication
         information found in kwargs, else raise `AuthenticationError`
         """
         for authentifier in self.authentifiers:
             try:
-                return authentifier.authenticate(session, login, **kwargs)
+                return authentifier.authenticate(cnx, login, **kwargs)
             except AuthenticationError:
                 continue
         raise AuthenticationError()
@@ -1450,7 +1450,7 @@
             self._passwd_rqlst = self.source.compile_rql(self.passwd_rql, self._sols)
             self._auth_rqlst = self.source.compile_rql(self.auth_rql, self._sols)
 
-    def authenticate(self, session, login, password=None, **kwargs):
+    def authenticate(self, cnx, login, password=None, **kwargs):
         """return CWUser eid for the given login/password if this account is
         defined in this source, else raise `AuthenticationError`
 
@@ -1459,7 +1459,7 @@
         """
         args = {'login': login, 'pwd' : None}
         if password is not None:
-            rset = self.source.syntax_tree_search(session, self._passwd_rqlst, args)
+            rset = self.source.syntax_tree_search(cnx, self._passwd_rqlst, args)
             try:
                 pwd = rset[0][0]
             except IndexError:
@@ -1470,7 +1470,7 @@
             # passwords are stored using the Bytes type, so we get a StringIO
             args['pwd'] = Binary(crypt_password(password, pwd.getvalue()))
         # get eid from login and (crypted) password
-        rset = self.source.syntax_tree_search(session, self._auth_rqlst, args)
+        rset = self.source.syntax_tree_search(cnx, self._auth_rqlst, args)
         try:
             user = rset[0][0]
             # If the stored hash uses a deprecated scheme (e.g. DES or MD5 used
@@ -1480,32 +1480,32 @@
                 if not verify: # should not happen, but...
                     raise AuthenticationError('bad password')
                 if newhash:
-                    session.system_sql("UPDATE %s SET %s=%%(newhash)s WHERE %s=%%(login)s" % (
+                    cnx.system_sql("UPDATE %s SET %s=%%(newhash)s WHERE %s=%%(login)s" % (
                                         SQL_PREFIX + 'CWUser',
                                         SQL_PREFIX + 'upassword',
                                         SQL_PREFIX + 'login'),
                                        {'newhash': self.source._binary(newhash),
                                         'login': login})
-                    session.commit(free_cnxset=False)
+                    cnx.commit(free_cnxset=False)
             return user
         except IndexError:
             raise AuthenticationError('bad password')
 
 
 class EmailPasswordAuthentifier(BaseAuthentifier):
-    def authenticate(self, session, login, **authinfo):
+    def authenticate(self, cnx, 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, '
+        rset = cnx.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)
+        return self.source.repo.check_auth_info(cnx, login, authinfo)
 
 
 class DatabaseIndependentBackupRestore(object):