--- a/cubicweb/server/sources/ldapfeed.py Tue Feb 25 22:45:42 2020 +0100
+++ b/cubicweb/server/sources/ldapfeed.py Tue Feb 25 23:22:58 2020 +0100
@@ -34,10 +34,11 @@
from cubicweb import _
# search scopes
-LDAP_SCOPES = {'BASE': ldap3.SEARCH_SCOPE_BASE_OBJECT,
- 'ONELEVEL': ldap3.SEARCH_SCOPE_SINGLE_LEVEL,
- 'SUBTREE': ldap3.SEARCH_SCOPE_WHOLE_SUBTREE}
-
+LDAP_SCOPES = {
+ 'BASE': ldap3.BASE,
+ 'ONELEVEL': ldap3.LEVEL,
+ 'SUBTREE': ldap3.SUBTREE,
+}
# map ldap protocol to their standard port
PROTO_PORT = {'ldap': 389,
@@ -254,7 +255,7 @@
# check password by establishing a (unused) connection
try:
self._connect(user, password)
- except ldap3.LDAPException as ex:
+ except ldap3.core.exceptions.LDAPException as ex:
# Something went wrong, most likely bad credentials
self.info('while trying to authenticate %s: %s', user, ex)
raise AuthenticationError()
@@ -270,15 +271,27 @@
def _connect(self, user=None, userpwd=None):
protocol, host, port = self.connection_info()
+ kwargs = {}
+ if user:
+ kwargs['user'] = user['dn']
+ elif self.cnx_dn:
+ kwargs['user'] = self.cnx_dn
+ if self.cnx_pwd:
+ kwargs['password'] = self.cnx_pwd
self.info('connecting %s://%s:%s as %s', protocol, host, port,
- user and user['dn'] or 'anonymous')
+ kwargs.get('user', 'anonymous'))
server = ldap3.Server(host, port=int(port))
- conn = ldap3.Connection(server, user=user and user['dn'], client_strategy=ldap3.STRATEGY_SYNC_RESTARTABLE, auto_referrals=False)
+ conn = ldap3.Connection(
+ server, client_strategy=ldap3.RESTARTABLE, auto_referrals=False,
+ raise_exceptions=True,
+ **kwargs)
+
# Now bind with the credentials given. Let exceptions propagate out.
if user is None:
- # XXX always use simple bind for data connection
+ # anonymous bind
if not self.cnx_dn:
- conn.bind()
+ if not conn.bind():
+ raise AuthenticationError(conn.result["message"])
else:
self._authenticate(conn, {'dn': self.cnx_dn}, self.cnx_pwd)
else:
@@ -289,7 +302,6 @@
return conn
def _auth_simple(self, conn, user, userpwd):
- conn.authentication = ldap3.AUTH_SIMPLE
conn.user = user['dn']
conn.password = userpwd
return conn.bind()
@@ -314,7 +326,7 @@
if self._conn is None:
self._conn = self._connect()
ldapcnx = self._conn
- if not ldapcnx.search(base, searchstr, search_scope=scope, attributes=attrs):
+ if not ldapcnx.search(base, searchstr, search_scope=scope, attributes=set(attrs) - {'dn'}):
return []
result = []
for rec in ldapcnx.response:
@@ -330,14 +342,14 @@
"""Turn an ldap received item into a proper dict."""
itemdict = {'dn': dn}
for key, value in iterator:
- if self.user_attrs.get(key) == 'upassword': # XXx better password detection
- value = value[0].encode('utf-8')
+ if self.user_attrs.get(key) == 'upassword': # XXx better password detection
+ value = value[0]
# we only support ldap_salted_sha1 for ldap sources, see: server/utils.py
if not value.startswith(b'{SSHA}'):
value = utils.crypt_password(value)
itemdict[key] = Binary(value)
elif self.user_attrs.get(key) == 'modification_date':
- itemdict[key] = datetime.strptime(value[0], '%Y%m%d%H%M%SZ')
+ itemdict[key] = value
else:
if PY2 and value and isinstance(value[0], str):
value = [unicode(val, 'utf-8', 'replace') for val in value]