##// END OF EJS Templates
auth-ldap: added connection pinning and timeout option to ldap plugin
marcink -
r2654:c156e0f4 default
parent child Browse files
Show More
@@ -86,6 +86,7 b' class TestAuthSettingsView(object):'
86 86
87 87 'host': 'dc.example.com',
88 88 'port': '999',
89 'timeout': 3600,
89 90 'tls_kind': 'PLAIN',
90 91 'tls_reqcert': 'NEVER',
91 92
@@ -22,6 +22,7 b''
22 22 RhodeCode authentication plugin for LDAP
23 23 """
24 24
25 import socket
25 26 import re
26 27 import colander
27 28 import logging
@@ -90,6 +91,16 b' class LdapSettingsSchema(AuthnPluginSett'
90 91 title=_('Port'),
91 92 validator=colander.Range(min=0, max=65536),
92 93 widget='int')
94
95 timeout = colander.SchemaNode(
96 colander.Int(),
97 default=60 * 5,
98 description=_('Timeout for LDAP connection'),
99 preparer=strip_whitespace,
100 title=_('Connection timeout'),
101 validator=colander.Range(min=1),
102 widget='int')
103
93 104 dn_user = colander.SchemaNode(
94 105 colander.String(),
95 106 default='',
@@ -191,19 +202,47 b' class LdapSettingsSchema(AuthnPluginSett'
191 202 class AuthLdap(object):
192 203
193 204 def _build_servers(self):
205 def host_resolver(host, port):
206 """
207 Main work for this function is to prevent ldap connection issues,
208 and detect them early using a "greenified" sockets
209 """
210 host = host.strip()
211
212 log.info('Resolving LDAP host %s', host)
213 try:
214 ip = socket.gethostbyname(host)
215 log.info('Got LDAP server %s ip %s', host, ip)
216 except Exception:
217 raise LdapConnectionError(
218 'Failed to resolve host: `{}`'.format(host))
219
220 log.info('Checking LDAP IP access %s', ip)
221 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
222 try:
223 s.connect((ip, int(port)))
224 s.shutdown(socket.SHUT_RD)
225 except Exception:
226 raise LdapConnectionError(
227 'Failed to connect to host: `{}:{}`'.format(host, port))
228
229 return '{}:{}'.format(host, port)
230
231 port = self.LDAP_SERVER_PORT
194 232 return ', '.join(
195 ["{}://{}:{}".format(
196 self.ldap_server_type, host.strip(), self.LDAP_SERVER_PORT)
233 ["{}://{}".format(
234 self.ldap_server_type, host_resolver(host, port))
197 235 for host in self.SERVER_ADDRESSES])
198 236
199 237 def __init__(self, server, base_dn, port=389, bind_dn='', bind_pass='',
200 238 tls_kind='PLAIN', tls_reqcert='DEMAND', ldap_version=3,
201 239 search_scope='SUBTREE', attr_login='uid',
202 ldap_filter=''):
240 ldap_filter='', timeout=None):
203 241 if ldap == Missing:
204 242 raise LdapImportError("Missing or incompatible ldap library")
205 243
206 244 self.debug = False
245 self.timeout = timeout or 60 * 5
207 246 self.ldap_version = ldap_version
208 247 self.ldap_server_type = 'ldap'
209 248
@@ -231,22 +270,25 b' class AuthLdap(object):'
231 270 self.LDAP_FILTER = safe_str(ldap_filter)
232 271
233 272 def _get_ldap_conn(self):
273 log.debug('initializing LDAP connection to:%s', self.LDAP_SERVER)
274
234 275 if self.debug:
235 276 ldap.set_option(ldap.OPT_DEBUG_LEVEL, 255)
236 277
237 278 if hasattr(ldap, 'OPT_X_TLS_CACERTDIR'):
238 ldap.set_option(ldap.OPT_X_TLS_CACERTDIR,
239 '/etc/openldap/cacerts')
240 ldap.set_option(ldap.OPT_REFERRALS, ldap.OPT_OFF)
241 ldap.set_option(ldap.OPT_RESTART, ldap.OPT_ON)
242 ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 60 * 10)
243 ldap.set_option(ldap.OPT_TIMEOUT, 60 * 10)
244
279 ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, '/etc/openldap/cacerts')
245 280 if self.TLS_KIND != 'PLAIN':
246 281 ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, self.TLS_REQCERT)
247 282
248 log.debug('initializing LDAP connection to:%s', self.LDAP_SERVER)
283 ldap.set_option(ldap.OPT_REFERRALS, ldap.OPT_OFF)
284 ldap.set_option(ldap.OPT_RESTART, ldap.OPT_ON)
285
286 # init connection now
249 287 ldap_conn = ldap.initialize(self.LDAP_SERVER)
288 ldap_conn.set_option(ldap.OPT_NETWORK_TIMEOUT, self.timeout)
289 ldap_conn.set_option(ldap.OPT_TIMEOUT, self.timeout)
290 ldap_conn.timeout = self.timeout
291
250 292 if self.ldap_version == 2:
251 293 ldap_conn.protocol = ldap.VERSION2
252 294 else:
@@ -446,6 +488,7 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
446 488 'attr_login': settings.get('attr_login'),
447 489 'ldap_version': 3,
448 490 'ldap_filter': settings.get('filter'),
491 'timeout': settings.get('timeout')
449 492 }
450 493
451 494 ldap_attrs = self.try_dynamic_binding(username, password, ldap_args)
@@ -496,3 +539,4 b' class RhodeCodeAuthPlugin(RhodeCodeExter'
496 539 except (Exception,):
497 540 log.exception("Other exception")
498 541 return None
542
General Comments 0
You need to be logged in to leave comments. Login now