@@ -228,6 +228,14 @@ def _server_port_default(self):
228
228
This can be useful in an heterogeneous environment, when supplying a UNIX username to authenticate against AD.
229
229
""" ,
230
230
)
231
+ secondary_uri = Unicode (
232
+ config = True ,
233
+ default = "" ,
234
+ help = """
235
+ Comma separated address:port of the LDAP server which can be tried to contact when
236
+ primary LDAP server is unavailable.
237
+ """ ,
238
+ )
231
239
232
240
def resolve_username (self , username_supplied_by_user ):
233
241
search_dn = self .lookup_dn_search_user
@@ -305,8 +313,31 @@ def resolve_username(self, username_supplied_by_user):
305
313
return (user_dn , response [0 ]["dn" ])
306
314
307
315
def get_connection (self , userdn , password ):
316
+ try :
317
+ return self ._get_real_connection (
318
+ userdn , password , self .server_address , self .server_port
319
+ )
320
+ except (
321
+ ldap3 .core .exceptions .LDAPSocketOpenError ,
322
+ ldap3 .core .exceptions .LDAPBindError ,
323
+ ldap3 .core .exceptions .LDAPSocketReceiveError ,
324
+ ):
325
+ for server , port in self ._get_secondary_servers ():
326
+ try :
327
+ return self ._get_real_connection (userdn , password , server , port )
328
+ except (
329
+ ldap3 .core .exceptions .LDAPSocketOpenError ,
330
+ ldap3 .core .exceptions .LDAPBindError ,
331
+ ldap3 .core .exceptions .LDAPSocketReceiveError ,
332
+ ):
333
+ continue
334
+ else :
335
+ # re-raise the last caught error
336
+ raise
337
+
338
+ def _get_real_connection (self , userdn , password , server_address , server_port ):
308
339
server = ldap3 .Server (
309
- self . server_address , port = self . server_port , use_ssl = self .use_ssl
340
+ server_address , port = server_port , use_ssl = self .use_ssl
310
341
)
311
342
auto_bind = (
312
343
ldap3 .AUTO_BIND_NO_TLS if self .use_ssl else ldap3 .AUTO_BIND_TLS_BEFORE_BIND
@@ -316,6 +347,24 @@ def get_connection(self, userdn, password):
316
347
)
317
348
return conn
318
349
350
+ def _get_secondary_servers (self ):
351
+ uri_list = self .secondary_uri .split ("," )
352
+ for uri in uri_list :
353
+ server_port = uri .strip ().split (":" )
354
+ assert len (server_port ) <= 2
355
+ if len (server_port ) == 2 :
356
+ try :
357
+ port = int (server_port [1 ])
358
+ except ValueError :
359
+ self .log .warning (
360
+ "Invalid port in secondary uri %s, use default" % uri
361
+ )
362
+ port = self ._server_port_default ()
363
+ else :
364
+ port = self ._server_port_default ()
365
+
366
+ yield (server_port [0 ], port )
367
+
319
368
def get_user_attributes (self , conn , userdn ):
320
369
attrs = {}
321
370
if self .auth_state_attributes :
0 commit comments