45 # map ldap protocol to their standard port |
45 # map ldap protocol to their standard port |
46 PROTO_PORT = {'ldap': 389, |
46 PROTO_PORT = {'ldap': 389, |
47 'ldaps': 636, |
47 'ldaps': 636, |
48 'ldapi': None, |
48 'ldapi': None, |
49 } |
49 } |
50 |
|
51 |
|
52 class ConnectionWrapper(object): |
|
53 def __init__(self, cnx=None): |
|
54 self.cnx = cnx |
|
55 def commit(self): |
|
56 pass |
|
57 def rollback(self): |
|
58 pass |
|
59 def cursor(self): |
|
60 return None # no actual cursor support |
|
61 def close(self): |
|
62 if hasattr(self.cnx, 'close'): |
|
63 self.cnx.close() |
|
64 |
50 |
65 |
51 |
66 class LDAPFeedSource(datafeed.DataFeedSource): |
52 class LDAPFeedSource(datafeed.DataFeedSource): |
67 """LDAP feed source: unlike ldapuser source, this source is copy based and |
53 """LDAP feed source: unlike ldapuser source, this source is copy based and |
68 will import ldap content (beside passwords for authentication) into the |
54 will import ldap content (beside passwords for authentication) into the |
231 protocol, hostport = self.urls[0].split('://') |
217 protocol, hostport = self.urls[0].split('://') |
232 if protocol != 'ldapi' and not ':' in hostport: |
218 if protocol != 'ldapi' and not ':' in hostport: |
233 hostport = '%s:%s' % (hostport, PROTO_PORT[protocol]) |
219 hostport = '%s:%s' % (hostport, PROTO_PORT[protocol]) |
234 return protocol, hostport |
220 return protocol, hostport |
235 |
221 |
236 def get_connection(self): |
|
237 """open and return a connection to the source""" |
|
238 if self._conn is None: |
|
239 try: |
|
240 self._connect() |
|
241 except Exception: |
|
242 self.exception('unable to connect to ldap') |
|
243 return ConnectionWrapper(self._conn) |
|
244 |
|
245 def authenticate(self, session, login, password=None, **kwargs): |
222 def authenticate(self, session, login, password=None, **kwargs): |
246 """return CWUser eid for the given login/password if this account is |
223 """return CWUser eid for the given login/password if this account is |
247 defined in this source, else raise `AuthenticationError` |
224 defined in this source, else raise `AuthenticationError` |
248 |
225 |
249 two queries are needed since passwords are stored crypted, so we have |
226 two queries are needed since passwords are stored crypted, so we have |
303 pass |
280 pass |
304 #conn.set_option(ldap.OPT_NETWORK_TIMEOUT, conn_timeout) |
281 #conn.set_option(ldap.OPT_NETWORK_TIMEOUT, conn_timeout) |
305 #conn.timeout = op_timeout |
282 #conn.timeout = op_timeout |
306 # Now bind with the credentials given. Let exceptions propagate out. |
283 # Now bind with the credentials given. Let exceptions propagate out. |
307 if user is None: |
284 if user is None: |
308 # no user specified, we want to initialize the 'data' connection, |
|
309 assert self._conn is None |
|
310 self._conn = conn |
|
311 # XXX always use simple bind for data connection |
285 # XXX always use simple bind for data connection |
312 if not self.cnx_dn: |
286 if not self.cnx_dn: |
313 conn.simple_bind_s(self.cnx_dn, self.cnx_pwd) |
287 conn.simple_bind_s(self.cnx_dn, self.cnx_pwd) |
314 else: |
288 else: |
315 self._authenticate(conn, {'dn': self.cnx_dn}, self.cnx_pwd) |
289 self._authenticate(conn, {'dn': self.cnx_dn}, self.cnx_pwd) |
343 def _search(self, session, base, scope, |
317 def _search(self, session, base, scope, |
344 searchstr='(objectClass=*)', attrs=()): |
318 searchstr='(objectClass=*)', attrs=()): |
345 """make an ldap query""" |
319 """make an ldap query""" |
346 self.debug('ldap search %s %s %s %s %s', self.uri, base, scope, |
320 self.debug('ldap search %s %s %s %s %s', self.uri, base, scope, |
347 searchstr, list(attrs)) |
321 searchstr, list(attrs)) |
348 # XXX for now, we do not have connections set support for LDAP, so |
322 if self._conn is None: |
349 # this is always self._conn |
323 self._conn = self._connect() |
350 cnx = self.get_connection().cnx #session.cnxset.connection(self.uri).cnx |
324 cnx = self._conn |
351 if cnx is None: |
|
352 # cant connect to server |
|
353 msg = session._("can't connect to source %s, some data may be missing") |
|
354 session.set_shared_data('sources_error', msg % self.uri, txdata=True) |
|
355 return [] |
|
356 try: |
325 try: |
357 res = cnx.search_s(base, scope, searchstr, attrs) |
326 res = cnx.search_s(base, scope, searchstr, attrs) |
358 except ldap.PARTIAL_RESULTS: |
327 except ldap.PARTIAL_RESULTS: |
359 res = cnx.result(all=0)[1] |
328 res = cnx.result(all=0)[1] |
360 except ldap.NO_SUCH_OBJECT: |
329 except ldap.NO_SUCH_OBJECT: |