Merge 3.26
authorPhilippe Pepiot <philippe.pepiot@logilab.fr>
Fri, 24 May 2019 16:29:14 +0200
changeset 12626 32ee89340e59
parent 12624 24b9073a6617 (current diff)
parent 12625 ba5231e1aa45 (diff)
child 12627 3648a2c293f6
Merge 3.26
cubicweb/__pkginfo__.py
cubicweb/crypto.py
cubicweb/dataimport/importer.py
cubicweb/server/test/unittest_ldapsource.py
cubicweb/sobjects/ldapparser.py
flake8-ok-files.txt
requirements/test-misc.txt
--- a/.hgtags	Wed May 22 11:34:08 2019 +0200
+++ b/.hgtags	Fri May 24 16:29:14 2019 +0200
@@ -633,3 +633,4 @@
 ee4ad63c91e5406e29f079f1f2d3774361798ac8 3.26.7
 91f75319a726b523a09103540d3bc6872aaf2ae4 3.26.8
 4d6909de765ac036ddef00b5853213fcae56d525 3.26.9
+74cc5de1ee6c578db401c89716fdc43b27624a04 3.26.10
--- a/cubicweb/crypto.py	Wed May 22 11:34:08 2019 +0200
+++ b/cubicweb/crypto.py	Fri May 24 16:29:14 2019 +0200
@@ -25,6 +25,8 @@
 
 
 _CYPHERERS = {}
+
+
 def _cypherer(seed):
     if isinstance(seed, str):
         seed = seed.encode('utf-8')
@@ -37,12 +39,13 @@
 
 def encrypt(data, seed):
     string = pickle.dumps(data)
-    string = string + '*' * (8 - len(string) % 8)
+    string = string + b'*' * (8 - len(string) % 8)
     string = b64encode(_cypherer(seed).encrypt(string))
-    return str(string)
+    return string.decode('utf-8')
 
 
 def decrypt(string, seed):
+    string = string.encode('utf-8')
     # pickle ignores trailing characters so we do not need to strip them off
     string = _cypherer(seed).decrypt(b64decode(string))
     return pickle.loads(string)
--- a/cubicweb/dataimport/importer.py	Wed May 22 11:34:08 2019 +0200
+++ b/cubicweb/dataimport/importer.py	Fri May 24 16:29:14 2019 +0200
@@ -71,7 +71,10 @@
     def use_extid_as_cwuri_filter(extentities):
         for extentity in extentities:
             if extentity.extid not in extid2eid:
-                extentity.values.setdefault('cwuri', set([extentity.extid.decode('utf-8')]))
+                cwuri = extentity.extid
+                if isinstance(cwuri, bytes):
+                    cwuri = cwuri.decode('utf-8')
+                extentity.values.setdefault('cwuri', set([cwuri]))
             yield extentity
     return use_extid_as_cwuri_filter
 
--- a/cubicweb/dataimport/test/unittest_importer.py	Wed May 22 11:34:08 2019 +0200
+++ b/cubicweb/dataimport/test/unittest_importer.py	Fri May 24 16:29:14 2019 +0200
@@ -196,6 +196,12 @@
         personne.values.pop('cwuri')
         list(set_cwuri((personne,)))
         self.assertNotIn('cwuri', personne.values)
+        personne = ExtEntity('Personne', u'ééé', {})
+        mapping = {}
+        set_cwuri = use_extid_as_cwuri(mapping)
+        list(set_cwuri((personne,)))
+        self.assertIn('cwuri', personne.values)
+        self.assertEqual(personne.values['cwuri'], set([u'ééé']))
 
 
 class DropExtraValuesTC(CubicWebTC):
--- a/cubicweb/server/test/unittest_ldapsource.py	Wed May 22 11:34:08 2019 +0200
+++ b/cubicweb/server/test/unittest_ldapsource.py	Fri May 24 16:29:14 2019 +0200
@@ -251,6 +251,33 @@
                               source.authenticate, cnx, 'syt', 'toto')
             self.assertTrue(source.authenticate(cnx, 'syt', 'syt'))
 
+    def test_ldapfeed_insert_collision(self):
+        """
+        when a user computed login from ldapfeed collides with a CWUser
+        login the user MUST not be inserted, and message MUST be present
+        at error level regarding the collision for troubleshooting purpose.
+        We also check that in case the CWUser is skipped, the entity EmailAddress
+        is not modified.
+        If EmailAddress are not modified, CWGroup are not.
+        """
+        with self.admin_access.cnx() as cnx:
+            user = cnx.find('CWUser', login=u'syt').one()
+            user.cw_set(cw_source=cnx.find('CWSource', name=u'system').one())
+            with cnx.security_enabled(write=False):
+                user.cw_set(cwuri=u'http://testing.fr/cubicweb/{}'.format(user.eid))
+                for mail in user.use_email:
+                    mail.cw_set(address=mail.address[:-3] + u".net")
+            cnx.commit()
+            with self.assertLogs('cubicweb.appobject', level='ERROR') as cm:
+                self.pull(cnx)
+                self.assertEqual(
+                    cm.output,
+                    ['ERROR:cubicweb.appobject:not synchronizing user syt.'
+                     ' User already exist in source system']
+                )
+            for mail in user.use_email:
+                self.assertTrue(mail.address.endswith(".net"))
+
     def test_base(self):
         with self.admin_access.repo_cnx() as cnx:
             # check a known one
--- a/cubicweb/sobjects/ldapparser.py	Wed May 22 11:34:08 2019 +0200
+++ b/cubicweb/sobjects/ldapparser.py	Fri May 24 16:29:14 2019 +0200
@@ -154,9 +154,26 @@
 
     def extentities_generator(self):
         self.debug('processing ldapfeed source %s %s', self.source, self.searchgroupfilterstr)
+        # get existing users *not* managed by this source
+        non_managed_users = dict(self._cw.execute(
+            'Any L, SN WHERE'
+            ' U is CWUser, U login L,'
+            ' U cw_source S, S name SN,'
+            ' NOT S eid %(eid)s',
+            {'eid': self.source.eid}, build_descr=False))
         # generate users and email addresses
         for userdict in self.user_source_entities_by_extid.values():
             attrs = self.ldap2cwattrs(userdict, 'CWUser')
+            login = attrs['login'][0]
+            try:
+                source = non_managed_users[login]
+            except KeyError:
+                pass
+            else:
+                self.error(
+                    'not synchronizing user %s. User already exist in source %s',
+                    login, source)
+                continue
             pwd = attrs.get('upassword')
             if not pwd:
                 # generate a dumb password if not fetched from ldap (see
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/test/unittest_crypto.py	Fri May 24 16:29:14 2019 +0200
@@ -0,0 +1,18 @@
+from unittest import TestCase
+
+from cubicweb import crypto
+
+
+class CryptoTC(TestCase):
+
+    def test_encrypt_decrypt_roundtrip(self):
+        data = {'a': u'ah', 'b': [1, 2]}
+        seed = 'ssss'
+        crypted = crypto.encrypt(data, seed)
+        decrypted = crypto.decrypt(crypted, seed)
+        self.assertEqual(decrypted, data)
+
+
+if __name__ == '__main__':
+    import unittest
+    unittest.main()
--- a/flake8-ok-files.txt	Wed May 22 11:34:08 2019 +0200
+++ b/flake8-ok-files.txt	Fri May 24 16:29:14 2019 +0200
@@ -3,6 +3,7 @@
 cubicweb/_exceptions.py
 cubicweb/cwctl.py
 cubicweb/cwvreg.py
+cubicweb/crypto.py
 cubicweb/dataimport/csv.py
 cubicweb/dataimport/importer.py
 cubicweb/dataimport/massive_store.py