[ldap] we may actually get back password from ldap
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Thu, 03 May 2012 15:52:01 +0200
changeset 8387 b59af20a868d
parent 8386 249b21722e5e
child 8388 c6c624cea870
[ldap] we may actually get back password from ldap
hooks/metadata.py
server/ldaputils.py
server/test/unittest_ldapuser.py
server/utils.py
sobjects/ldapparser.py
--- a/hooks/metadata.py	Thu May 03 15:50:23 2012 +0200
+++ b/hooks/metadata.py	Thu May 03 15:52:01 2012 +0200
@@ -199,17 +199,12 @@
             entity = self._cw.entity_from_eid(self.eidfrom)
             # copy entity if necessary
             if not oldsource.repo_source.copy_based_source:
-                entity.complete(skip_bytes=False)
+                entity.complete(skip_bytes=False, skip_pwd=False)
                 if not entity.creation_date:
                     entity.cw_attr_cache['creation_date'] = datetime.now()
                 if not entity.modification_date:
                     entity.cw_attr_cache['modification_date'] = datetime.now()
                 entity.cw_attr_cache['cwuri'] = u'%s%s' % (self._cw.base_url(), entity.eid)
-                for rschema, attrschema in entity.e_schema.attribute_definitions():
-                    if attrschema == 'Password' and \
-                       rschema.rdef(entity.e_schema, attrschema).cardinality[0] == '1':
-                        from logilab.common.shellutils import generate_password
-                        entity.cw_attr_cache[rschema.type] = generate_password()
                 entity.cw_edited = EditedEntity(entity, **entity.cw_attr_cache)
                 syssource.add_entity(self._cw, entity)
             # we don't want the moved entity to be reimported later.  To
--- a/server/ldaputils.py	Thu May 03 15:50:23 2012 +0200
+++ b/server/ldaputils.py	Thu May 03 15:52:01 2012 +0200
@@ -37,7 +37,7 @@
 from ldap.filter import filter_format
 from ldapurl import LDAPUrl
 
-from cubicweb import ValidationError, AuthenticationError
+from cubicweb import ValidationError, AuthenticationError, Binary
 from cubicweb.server.sources import ConnectionWrapper
 
 _ = unicode
@@ -125,7 +125,7 @@
           }),
         ('user-attrs-map',
          {'type' : 'named',
-          'default': {'uid': 'login', 'gecos': 'email'},
+          'default': {'uid': 'login', 'gecos': 'email', 'userPassword': 'upassword'},
           'help': 'map from ldap user attributes to cubicweb attributes (with Active Directory, you want to use sAMAccountName:login,mail:email,givenName:firstname,sn:surname)',
           'group': 'ldap-source', 'level': 1,
           }),
@@ -344,14 +344,13 @@
         """Turn an ldap received item into a proper dict."""
         itemdict = {'dn': dn}
         for key, value in iterator:
-            if not isinstance(value, str):
-                try:
-                    for i in range(len(value)):
-                        value[i] = unicode(value[i], 'utf8')
-                except Exception:
-                    pass
-            if isinstance(value, list) and len(value) == 1:
-                itemdict[key] = value = value[0]
+            if self.user_attrs.get(key) == 'upassword': # XXx better password detection
+                itemdict[key] = Binary(value[0].encode('utf-8'))
+            else:
+                for i, val in enumerate(value):
+                    value[i] = unicode(val, 'utf-8', 'replace')
+                if isinstance(value, list) and len(value) == 1:
+                    itemdict[key] = value = value[0]
         return itemdict
 
     def _process_no_such_object(self, session, dn):
--- a/server/test/unittest_ldapuser.py	Thu May 03 15:50:23 2012 +0200
+++ b/server/test/unittest_ldapuser.py	Thu May 03 15:52:01 2012 +0200
@@ -156,10 +156,15 @@
         self.assertEqual(e.cw_source[0].name, 'system')
         self.assertTrue(e.creation_date)
         self.assertTrue(e.modification_date)
-        # XXX test some password has been set
         source.pull_data(self.session)
         rset = self.sexecute('CWUser X WHERE X login %(login)s', {'login': 'syt'})
         self.assertEqual(len(rset), 1)
+        # test some password has been set
+        cu = self.session.system_sql('SELECT cw_upassword FROM cw_CWUser WHERE cw_eid=%s' % rset[0][0])
+        value = str(cu.fetchall()[0][0])
+        self.assertEqual(value, '{SSHA}v/8xJQP3uoaTBZz1T7Y0B3qOxRN1cj7D')
+        self.assertTrue(self.repo.system_source.authenticate(
+                self.session, 'syt', password='syt'))
 
 
 class LDAPUserSourceTC(LDAPFeedSourceTC):
--- a/server/utils.py	Thu May 03 15:50:23 2012 +0200
+++ b/server/utils.py	Thu May 03 15:52:01 2012 +0200
@@ -57,7 +57,7 @@
     def calc_checksum(self, secret):
         return md5crypt(secret, self.salt.encode('ascii'))
 
-myctx = CryptContext(['sha512_crypt', CustomMD5Crypt, 'des_crypt'])
+myctx = CryptContext(['sha512_crypt', CustomMD5Crypt, 'des_crypt', 'ldap_salted_sha1'])
 
 def crypt_password(passwd, salt=None):
     """return the encrypted password using the given salt or a generated one
--- a/sobjects/ldapparser.py	Thu May 03 15:50:23 2012 +0200
+++ b/sobjects/ldapparser.py	Thu May 03 15:52:01 2012 +0200
@@ -23,9 +23,13 @@
 from base64 import b64decode
 
 from logilab.common.decorators import cached
+from logilab.common.shellutils import generate_password
 
+from cubicweb import Binary
+from cubicweb.server.utils import crypt_password
 from cubicweb.server.sources import datafeed
 
+
 class DataFeedlDAPParser(datafeed.DataFeedParser):
     __regid__ = 'ldapfeed'
     # attributes that may appears in source user_attrs dict which are not
@@ -62,6 +66,12 @@
             entity.cw_edited['address'] = sourceparams['address']
         else:
             self.ldap2cwattrs(sourceparams, entity.cw_edited)
+            pwd = entity.cw_edited.get('upassword')
+            if not pwd:
+                # generate a dumb password if not fetched from ldap (see
+                # userPassword)
+                pwd = crypt_password(generate_password())
+                entity.cw_edited = Binary(pwd)
         return entity
 
     def after_entity_copy(self, entity, sourceparams):