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 |
["{}://{} |
|
|
196 |
self.ldap_server_type, host |
|
|
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