Show More
@@ -89,7 +89,7 b' class TestAuthSettingsView(object):' | |||||
89 | 'timeout': 3600, |
|
89 | 'timeout': 3600, | |
90 | 'tls_kind': 'PLAIN', |
|
90 | 'tls_kind': 'PLAIN', | |
91 | 'tls_reqcert': 'NEVER', |
|
91 | 'tls_reqcert': 'NEVER', | |
92 |
|
92 | 'tls_cert_dir':'/etc/openldap/cacerts', | ||
93 | 'dn_user': 'test_user', |
|
93 | 'dn_user': 'test_user', | |
94 | 'dn_pass': 'test_pass', |
|
94 | 'dn_pass': 'test_pass', | |
95 | 'base_dn': 'test_base_dn', |
|
95 | 'base_dn': 'test_base_dn', |
@@ -38,7 +38,8 b' from rhodecode.authentication.schema imp' | |||||
38 | from rhodecode.lib import rc_cache |
|
38 | from rhodecode.lib import rc_cache | |
39 | from rhodecode.lib.auth import PasswordGenerator, _RhodeCodeCryptoBCrypt |
|
39 | from rhodecode.lib.auth import PasswordGenerator, _RhodeCodeCryptoBCrypt | |
40 | from rhodecode.lib.utils2 import safe_int, safe_str |
|
40 | from rhodecode.lib.utils2 import safe_int, safe_str | |
41 | from rhodecode.lib.exceptions import LdapConnectionError |
|
41 | from rhodecode.lib.exceptions import LdapConnectionError, LdapUsernameError, \ | |
|
42 | LdapPasswordError | |||
42 | from rhodecode.model.db import User |
|
43 | from rhodecode.model.db import User | |
43 | from rhodecode.model.meta import Session |
|
44 | from rhodecode.model.meta import Session | |
44 | from rhodecode.model.settings import SettingsModel |
|
45 | from rhodecode.model.settings import SettingsModel | |
@@ -577,7 +578,8 b' class RhodeCodeExternalAuthPlugin(RhodeC' | |||||
577 | class AuthLdapBase(object): |
|
578 | class AuthLdapBase(object): | |
578 |
|
579 | |||
579 | @classmethod |
|
580 | @classmethod | |
580 | def _build_servers(cls, ldap_server_type, ldap_server, port): |
|
581 | def _build_servers(cls, ldap_server_type, ldap_server, port, use_resolver=True): | |
|
582 | ||||
581 | def host_resolver(host, port, full_resolve=True): |
|
583 | def host_resolver(host, port, full_resolve=True): | |
582 | """ |
|
584 | """ | |
583 | Main work for this function is to prevent ldap connection issues, |
|
585 | Main work for this function is to prevent ldap connection issues, | |
@@ -616,7 +618,7 b' class AuthLdapBase(object):' | |||||
616 | return ', '.join( |
|
618 | return ', '.join( | |
617 | ["{}://{}".format( |
|
619 | ["{}://{}".format( | |
618 | ldap_server_type, |
|
620 | ldap_server_type, | |
619 | host_resolver(host, port, full_resolve=full_resolve)) |
|
621 | host_resolver(host, port, full_resolve=use_resolver and full_resolve)) | |
620 | for host in ldap_server]) |
|
622 | for host in ldap_server]) | |
621 |
|
623 | |||
622 | @classmethod |
|
624 | @classmethod | |
@@ -630,6 +632,19 b' class AuthLdapBase(object):' | |||||
630 | uid = chop_at(username, "@%s" % server_addr) |
|
632 | uid = chop_at(username, "@%s" % server_addr) | |
631 | return uid |
|
633 | return uid | |
632 |
|
634 | |||
|
635 | @classmethod | |||
|
636 | def validate_username(cls, username): | |||
|
637 | if "," in username: | |||
|
638 | raise LdapUsernameError( | |||
|
639 | "invalid character `,` in username: `{}`".format(username)) | |||
|
640 | ||||
|
641 | @classmethod | |||
|
642 | def validate_password(cls, username, password): | |||
|
643 | if not password: | |||
|
644 | msg = "Authenticating user %s with blank password not allowed" | |||
|
645 | log.warning(msg, username) | |||
|
646 | raise LdapPasswordError(msg) | |||
|
647 | ||||
633 |
|
648 | |||
634 | def loadplugin(plugin_id): |
|
649 | def loadplugin(plugin_id): | |
635 | """ |
|
650 | """ |
@@ -22,7 +22,6 b'' | |||||
22 | RhodeCode authentication plugin for LDAP |
|
22 | RhodeCode authentication plugin for LDAP | |
23 | """ |
|
23 | """ | |
24 |
|
24 | |||
25 | import os |
|
|||
26 | import logging |
|
25 | import logging | |
27 | import traceback |
|
26 | import traceback | |
28 |
|
27 | |||
@@ -67,6 +66,171 b' class LdapAuthnResource(AuthnPluginResou' | |||||
67 | pass |
|
66 | pass | |
68 |
|
67 | |||
69 |
|
68 | |||
|
69 | class AuthLdap(AuthLdapBase): | |||
|
70 | default_tls_cert_dir = '/etc/openldap/cacerts' | |||
|
71 | ||||
|
72 | def __init__(self, server, base_dn, port=389, bind_dn='', bind_pass='', | |||
|
73 | tls_kind='PLAIN', tls_reqcert='DEMAND', tls_cert_file=None, | |||
|
74 | tls_cert_dir=None, ldap_version=3, | |||
|
75 | search_scope='SUBTREE', attr_login='uid', | |||
|
76 | ldap_filter='', timeout=None): | |||
|
77 | if ldap == Missing: | |||
|
78 | raise LdapImportError("Missing or incompatible ldap library") | |||
|
79 | ||||
|
80 | self.debug = False | |||
|
81 | self.timeout = timeout or 60 * 5 | |||
|
82 | self.ldap_version = ldap_version | |||
|
83 | self.ldap_server_type = 'ldap' | |||
|
84 | ||||
|
85 | self.TLS_KIND = tls_kind | |||
|
86 | ||||
|
87 | if self.TLS_KIND == 'LDAPS': | |||
|
88 | port = port or 689 | |||
|
89 | self.ldap_server_type += 's' | |||
|
90 | ||||
|
91 | OPT_X_TLS_DEMAND = 2 | |||
|
92 | self.TLS_REQCERT = getattr(ldap, 'OPT_X_TLS_%s' % tls_reqcert, OPT_X_TLS_DEMAND) | |||
|
93 | self.TLS_CERT_FILE = tls_cert_file or '' | |||
|
94 | self.TLS_CERT_DIR = tls_cert_dir or self.default_tls_cert_dir | |||
|
95 | ||||
|
96 | # split server into list | |||
|
97 | self.SERVER_ADDRESSES = self._get_server_list(server) | |||
|
98 | self.LDAP_SERVER_PORT = port | |||
|
99 | ||||
|
100 | # USE FOR READ ONLY BIND TO LDAP SERVER | |||
|
101 | self.attr_login = attr_login | |||
|
102 | ||||
|
103 | self.LDAP_BIND_DN = safe_str(bind_dn) | |||
|
104 | self.LDAP_BIND_PASS = safe_str(bind_pass) | |||
|
105 | ||||
|
106 | self.SEARCH_SCOPE = getattr(ldap, 'SCOPE_%s' % search_scope) | |||
|
107 | self.BASE_DN = safe_str(base_dn) | |||
|
108 | self.LDAP_FILTER = safe_str(ldap_filter) | |||
|
109 | ||||
|
110 | def _get_ldap_conn(self): | |||
|
111 | ||||
|
112 | if self.debug: | |||
|
113 | ldap.set_option(ldap.OPT_DEBUG_LEVEL, 255) | |||
|
114 | ||||
|
115 | if self.TLS_CERT_FILE and hasattr(ldap, 'OPT_X_TLS_CACERTFILE'): | |||
|
116 | ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, self.TLS_CERT_FILE) | |||
|
117 | ||||
|
118 | elif hasattr(ldap, 'OPT_X_TLS_CACERTDIR'): | |||
|
119 | ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, self.TLS_CERT_DIR) | |||
|
120 | ||||
|
121 | if self.TLS_KIND != 'PLAIN': | |||
|
122 | ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, self.TLS_REQCERT) | |||
|
123 | ||||
|
124 | ldap.set_option(ldap.OPT_REFERRALS, ldap.OPT_OFF) | |||
|
125 | ldap.set_option(ldap.OPT_RESTART, ldap.OPT_ON) | |||
|
126 | ||||
|
127 | # init connection now | |||
|
128 | ldap_servers = self._build_servers( | |||
|
129 | self.ldap_server_type, self.SERVER_ADDRESSES, self.LDAP_SERVER_PORT) | |||
|
130 | log.debug('initializing LDAP connection to:%s', ldap_servers) | |||
|
131 | ldap_conn = ldap.initialize(ldap_servers) | |||
|
132 | ldap_conn.set_option(ldap.OPT_NETWORK_TIMEOUT, self.timeout) | |||
|
133 | ldap_conn.set_option(ldap.OPT_TIMEOUT, self.timeout) | |||
|
134 | ldap_conn.timeout = self.timeout | |||
|
135 | ||||
|
136 | if self.ldap_version == 2: | |||
|
137 | ldap_conn.protocol = ldap.VERSION2 | |||
|
138 | else: | |||
|
139 | ldap_conn.protocol = ldap.VERSION3 | |||
|
140 | ||||
|
141 | if self.TLS_KIND == 'START_TLS': | |||
|
142 | ldap_conn.start_tls_s() | |||
|
143 | ||||
|
144 | if self.LDAP_BIND_DN and self.LDAP_BIND_PASS: | |||
|
145 | log.debug('Trying simple_bind with password and given login DN: %s', | |||
|
146 | self.LDAP_BIND_DN) | |||
|
147 | ldap_conn.simple_bind_s(self.LDAP_BIND_DN, self.LDAP_BIND_PASS) | |||
|
148 | ||||
|
149 | return ldap_conn | |||
|
150 | ||||
|
151 | def fetch_attrs_from_simple_bind(self, server, dn, username, password): | |||
|
152 | try: | |||
|
153 | log.debug('Trying simple bind with %s', dn) | |||
|
154 | server.simple_bind_s(dn, safe_str(password)) | |||
|
155 | user = server.search_ext_s( | |||
|
156 | dn, ldap.SCOPE_BASE, '(objectClass=*)', )[0] | |||
|
157 | _, attrs = user | |||
|
158 | return attrs | |||
|
159 | ||||
|
160 | except ldap.INVALID_CREDENTIALS: | |||
|
161 | log.debug( | |||
|
162 | "LDAP rejected password for user '%s': %s, org_exc:", | |||
|
163 | username, dn, exc_info=True) | |||
|
164 | ||||
|
165 | def authenticate_ldap(self, username, password): | |||
|
166 | """ | |||
|
167 | Authenticate a user via LDAP and return his/her LDAP properties. | |||
|
168 | ||||
|
169 | Raises AuthenticationError if the credentials are rejected, or | |||
|
170 | EnvironmentError if the LDAP server can't be reached. | |||
|
171 | ||||
|
172 | :param username: username | |||
|
173 | :param password: password | |||
|
174 | """ | |||
|
175 | ||||
|
176 | uid = self.get_uid(username, self.SERVER_ADDRESSES) | |||
|
177 | user_attrs = {} | |||
|
178 | dn = '' | |||
|
179 | ||||
|
180 | self.validate_password(username, password) | |||
|
181 | self.validate_username(username) | |||
|
182 | ||||
|
183 | ldap_conn = None | |||
|
184 | try: | |||
|
185 | ldap_conn = self._get_ldap_conn() | |||
|
186 | filter_ = '(&%s(%s=%s))' % ( | |||
|
187 | self.LDAP_FILTER, self.attr_login, username) | |||
|
188 | log.debug("Authenticating %r filter %s", self.BASE_DN, filter_) | |||
|
189 | ||||
|
190 | lobjects = ldap_conn.search_ext_s( | |||
|
191 | self.BASE_DN, self.SEARCH_SCOPE, filter_) | |||
|
192 | ||||
|
193 | if not lobjects: | |||
|
194 | log.debug("No matching LDAP objects for authentication " | |||
|
195 | "of UID:'%s' username:(%s)", uid, username) | |||
|
196 | raise ldap.NO_SUCH_OBJECT() | |||
|
197 | ||||
|
198 | log.debug('Found matching ldap object, trying to authenticate') | |||
|
199 | for (dn, _attrs) in lobjects: | |||
|
200 | if dn is None: | |||
|
201 | continue | |||
|
202 | ||||
|
203 | user_attrs = self.fetch_attrs_from_simple_bind( | |||
|
204 | ldap_conn, dn, username, password) | |||
|
205 | if user_attrs: | |||
|
206 | break | |||
|
207 | else: | |||
|
208 | raise LdapPasswordError( | |||
|
209 | 'Failed to authenticate user `{}`' | |||
|
210 | 'with given password'.format(username)) | |||
|
211 | ||||
|
212 | except ldap.NO_SUCH_OBJECT: | |||
|
213 | log.debug("LDAP says no such user '%s' (%s), org_exc:", | |||
|
214 | uid, username, exc_info=True) | |||
|
215 | raise LdapUsernameError('Unable to find user') | |||
|
216 | except ldap.SERVER_DOWN: | |||
|
217 | org_exc = traceback.format_exc() | |||
|
218 | raise LdapConnectionError( | |||
|
219 | "LDAP can't access authentication " | |||
|
220 | "server, org_exc:%s" % org_exc) | |||
|
221 | finally: | |||
|
222 | if ldap_conn: | |||
|
223 | log.debug('ldap: connection release') | |||
|
224 | try: | |||
|
225 | ldap_conn.unbind_s() | |||
|
226 | except Exception: | |||
|
227 | # for any reason this can raise exception we must catch it | |||
|
228 | # to not crush the server | |||
|
229 | pass | |||
|
230 | ||||
|
231 | return dn, user_attrs | |||
|
232 | ||||
|
233 | ||||
70 | class LdapSettingsSchema(AuthnPluginSettingsSchemaBase): |
|
234 | class LdapSettingsSchema(AuthnPluginSettingsSchemaBase): | |
71 | tls_kind_choices = ['PLAIN', 'LDAPS', 'START_TLS'] |
|
235 | tls_kind_choices = ['PLAIN', 'LDAPS', 'START_TLS'] | |
72 | tls_reqcert_choices = ['NEVER', 'ALLOW', 'TRY', 'DEMAND', 'HARD'] |
|
236 | tls_reqcert_choices = ['NEVER', 'ALLOW', 'TRY', 'DEMAND', 'HARD'] | |
@@ -134,6 +298,22 b' class LdapSettingsSchema(AuthnPluginSett' | |||||
134 | title=_('Certificate Checks'), |
|
298 | title=_('Certificate Checks'), | |
135 | validator=colander.OneOf(tls_reqcert_choices), |
|
299 | validator=colander.OneOf(tls_reqcert_choices), | |
136 | widget='select') |
|
300 | widget='select') | |
|
301 | tls_cert_file = colander.SchemaNode( | |||
|
302 | colander.String(), | |||
|
303 | default='', | |||
|
304 | description=_('This specifies the PEM-format file path containing ' | |||
|
305 | 'certificates for use in TLS connection.\n' | |||
|
306 | 'If not specified `TLS Cert dir` will be used'), | |||
|
307 | title=_('TLS Cert file'), | |||
|
308 | missing='', | |||
|
309 | widget='string') | |||
|
310 | tls_cert_dir = colander.SchemaNode( | |||
|
311 | colander.String(), | |||
|
312 | default=AuthLdap.default_tls_cert_dir, | |||
|
313 | description=_('This specifies the path of a directory that contains individual ' | |||
|
314 | 'CA certificates in separate files.'), | |||
|
315 | title=_('TLS Cert dir'), | |||
|
316 | widget='string') | |||
137 | base_dn = colander.SchemaNode( |
|
317 | base_dn = colander.SchemaNode( | |
138 | colander.String(), |
|
318 | colander.String(), | |
139 | default='', |
|
319 | default='', | |
@@ -198,175 +378,6 b' class LdapSettingsSchema(AuthnPluginSett' | |||||
198 | widget='string') |
|
378 | widget='string') | |
199 |
|
379 | |||
200 |
|
380 | |||
201 | class AuthLdap(AuthLdapBase): |
|
|||
202 |
|
||||
203 | def __init__(self, server, base_dn, port=389, bind_dn='', bind_pass='', |
|
|||
204 | tls_kind='PLAIN', tls_reqcert='DEMAND', ldap_version=3, |
|
|||
205 | search_scope='SUBTREE', attr_login='uid', |
|
|||
206 | ldap_filter='', timeout=None): |
|
|||
207 | if ldap == Missing: |
|
|||
208 | raise LdapImportError("Missing or incompatible ldap library") |
|
|||
209 |
|
||||
210 | self.debug = False |
|
|||
211 | self.timeout = timeout or 60 * 5 |
|
|||
212 | self.ldap_version = ldap_version |
|
|||
213 | self.ldap_server_type = 'ldap' |
|
|||
214 |
|
||||
215 | self.TLS_KIND = tls_kind |
|
|||
216 |
|
||||
217 | if self.TLS_KIND == 'LDAPS': |
|
|||
218 | port = port or 689 |
|
|||
219 | self.ldap_server_type += 's' |
|
|||
220 |
|
||||
221 | OPT_X_TLS_DEMAND = 2 |
|
|||
222 | self.TLS_REQCERT = getattr(ldap, 'OPT_X_TLS_%s' % tls_reqcert, |
|
|||
223 | OPT_X_TLS_DEMAND) |
|
|||
224 | self.LDAP_SERVER = server |
|
|||
225 | # split server into list |
|
|||
226 | self.SERVER_ADDRESSES = self._get_server_list(server) |
|
|||
227 | self.LDAP_SERVER_PORT = port |
|
|||
228 |
|
||||
229 | # USE FOR READ ONLY BIND TO LDAP SERVER |
|
|||
230 | self.attr_login = attr_login |
|
|||
231 |
|
||||
232 | self.LDAP_BIND_DN = safe_str(bind_dn) |
|
|||
233 | self.LDAP_BIND_PASS = safe_str(bind_pass) |
|
|||
234 |
|
||||
235 | self.SEARCH_SCOPE = getattr(ldap, 'SCOPE_%s' % search_scope) |
|
|||
236 | self.BASE_DN = safe_str(base_dn) |
|
|||
237 | self.LDAP_FILTER = safe_str(ldap_filter) |
|
|||
238 |
|
||||
239 | def _get_ldap_conn(self): |
|
|||
240 |
|
||||
241 | if self.debug: |
|
|||
242 | ldap.set_option(ldap.OPT_DEBUG_LEVEL, 255) |
|
|||
243 |
|
||||
244 | default_cert_path = os.environ.get('SSL_CERT_FILE') |
|
|||
245 | default_cert_dir = os.environ.get('SSL_CERT_DIR', '/etc/openldap/cacerts') |
|
|||
246 | if default_cert_path and hasattr(ldap, 'OPT_X_TLS_CACERTFILE'): |
|
|||
247 | ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, default_cert_path) |
|
|||
248 |
|
||||
249 | elif hasattr(ldap, 'OPT_X_TLS_CACERTDIR'): |
|
|||
250 | ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, default_cert_dir) |
|
|||
251 |
|
||||
252 | if self.TLS_KIND != 'PLAIN': |
|
|||
253 | ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, self.TLS_REQCERT) |
|
|||
254 |
|
||||
255 | ldap.set_option(ldap.OPT_REFERRALS, ldap.OPT_OFF) |
|
|||
256 | ldap.set_option(ldap.OPT_RESTART, ldap.OPT_ON) |
|
|||
257 |
|
||||
258 | # init connection now |
|
|||
259 | ldap_servers = self._build_servers( |
|
|||
260 | self.ldap_server_type, self.SERVER_ADDRESSES, self.LDAP_SERVER_PORT) |
|
|||
261 | log.debug('initializing LDAP connection to:%s', ldap_servers) |
|
|||
262 | ldap_conn = ldap.initialize(ldap_servers) |
|
|||
263 | ldap_conn.set_option(ldap.OPT_NETWORK_TIMEOUT, self.timeout) |
|
|||
264 | ldap_conn.set_option(ldap.OPT_TIMEOUT, self.timeout) |
|
|||
265 | ldap_conn.timeout = self.timeout |
|
|||
266 |
|
||||
267 | if self.ldap_version == 2: |
|
|||
268 | ldap_conn.protocol = ldap.VERSION2 |
|
|||
269 | else: |
|
|||
270 | ldap_conn.protocol = ldap.VERSION3 |
|
|||
271 |
|
||||
272 | if self.TLS_KIND == 'START_TLS': |
|
|||
273 | ldap_conn.start_tls_s() |
|
|||
274 |
|
||||
275 | if self.LDAP_BIND_DN and self.LDAP_BIND_PASS: |
|
|||
276 | log.debug('Trying simple_bind with password and given login DN: %s', |
|
|||
277 | self.LDAP_BIND_DN) |
|
|||
278 | ldap_conn.simple_bind_s(self.LDAP_BIND_DN, self.LDAP_BIND_PASS) |
|
|||
279 |
|
||||
280 | return ldap_conn |
|
|||
281 |
|
||||
282 | def fetch_attrs_from_simple_bind(self, server, dn, username, password): |
|
|||
283 | try: |
|
|||
284 | log.debug('Trying simple bind with %s', dn) |
|
|||
285 | server.simple_bind_s(dn, safe_str(password)) |
|
|||
286 | user = server.search_ext_s( |
|
|||
287 | dn, ldap.SCOPE_BASE, '(objectClass=*)', )[0] |
|
|||
288 | _, attrs = user |
|
|||
289 | return attrs |
|
|||
290 |
|
||||
291 | except ldap.INVALID_CREDENTIALS: |
|
|||
292 | log.debug( |
|
|||
293 | "LDAP rejected password for user '%s': %s, org_exc:", |
|
|||
294 | username, dn, exc_info=True) |
|
|||
295 |
|
||||
296 | def authenticate_ldap(self, username, password): |
|
|||
297 | """ |
|
|||
298 | Authenticate a user via LDAP and return his/her LDAP properties. |
|
|||
299 |
|
||||
300 | Raises AuthenticationError if the credentials are rejected, or |
|
|||
301 | EnvironmentError if the LDAP server can't be reached. |
|
|||
302 |
|
||||
303 | :param username: username |
|
|||
304 | :param password: password |
|
|||
305 | """ |
|
|||
306 |
|
||||
307 | uid = self.get_uid(username, self.SERVER_ADDRESSES) |
|
|||
308 | user_attrs = {} |
|
|||
309 | dn = '' |
|
|||
310 |
|
||||
311 | if not password: |
|
|||
312 | msg = "Authenticating user %s with blank password not allowed" |
|
|||
313 | log.warning(msg, username) |
|
|||
314 | raise LdapPasswordError(msg) |
|
|||
315 | if "," in username: |
|
|||
316 | raise LdapUsernameError( |
|
|||
317 | "invalid character `,` in username: `{}`".format(username)) |
|
|||
318 | ldap_conn = None |
|
|||
319 | try: |
|
|||
320 | ldap_conn = self._get_ldap_conn() |
|
|||
321 | filter_ = '(&%s(%s=%s))' % ( |
|
|||
322 | self.LDAP_FILTER, self.attr_login, username) |
|
|||
323 | log.debug( |
|
|||
324 | "Authenticating %r filter %s", self.BASE_DN, filter_) |
|
|||
325 | lobjects = ldap_conn.search_ext_s( |
|
|||
326 | self.BASE_DN, self.SEARCH_SCOPE, filter_) |
|
|||
327 |
|
||||
328 | if not lobjects: |
|
|||
329 | log.debug("No matching LDAP objects for authentication " |
|
|||
330 | "of UID:'%s' username:(%s)", uid, username) |
|
|||
331 | raise ldap.NO_SUCH_OBJECT() |
|
|||
332 |
|
||||
333 | log.debug('Found matching ldap object, trying to authenticate') |
|
|||
334 | for (dn, _attrs) in lobjects: |
|
|||
335 | if dn is None: |
|
|||
336 | continue |
|
|||
337 |
|
||||
338 | user_attrs = self.fetch_attrs_from_simple_bind( |
|
|||
339 | ldap_conn, dn, username, password) |
|
|||
340 | if user_attrs: |
|
|||
341 | break |
|
|||
342 |
|
||||
343 | else: |
|
|||
344 | raise LdapPasswordError( |
|
|||
345 | 'Failed to authenticate user `{}`' |
|
|||
346 | 'with given password'.format(username)) |
|
|||
347 |
|
||||
348 | except ldap.NO_SUCH_OBJECT: |
|
|||
349 | log.debug("LDAP says no such user '%s' (%s), org_exc:", |
|
|||
350 | uid, username, exc_info=True) |
|
|||
351 | raise LdapUsernameError('Unable to find user') |
|
|||
352 | except ldap.SERVER_DOWN: |
|
|||
353 | org_exc = traceback.format_exc() |
|
|||
354 | raise LdapConnectionError( |
|
|||
355 | "LDAP can't access authentication " |
|
|||
356 | "server, org_exc:%s" % org_exc) |
|
|||
357 | finally: |
|
|||
358 | if ldap_conn: |
|
|||
359 | log.debug('ldap: connection release') |
|
|||
360 | try: |
|
|||
361 | ldap_conn.unbind_s() |
|
|||
362 | except Exception: |
|
|||
363 | # for any reason this can raise exception we must catch it |
|
|||
364 | # to not crush the server |
|
|||
365 | pass |
|
|||
366 |
|
||||
367 | return dn, user_attrs |
|
|||
368 |
|
||||
369 |
|
||||
370 | class RhodeCodeAuthPlugin(RhodeCodeExternalAuthPlugin): |
|
381 | class RhodeCodeAuthPlugin(RhodeCodeExternalAuthPlugin): | |
371 | # used to define dynamic binding in the |
|
382 | # used to define dynamic binding in the | |
372 | DYNAMIC_BIND_VAR = '$login' |
|
383 | DYNAMIC_BIND_VAR = '$login' | |
@@ -459,6 +470,8 b' class RhodeCodeAuthPlugin(RhodeCodeExter' | |||||
459 | 'bind_pass': settings.get('dn_pass'), |
|
470 | 'bind_pass': settings.get('dn_pass'), | |
460 | 'tls_kind': settings.get('tls_kind'), |
|
471 | 'tls_kind': settings.get('tls_kind'), | |
461 | 'tls_reqcert': settings.get('tls_reqcert'), |
|
472 | 'tls_reqcert': settings.get('tls_reqcert'), | |
|
473 | 'tls_cert_file': settings.get('tls_cert_file'), | |||
|
474 | 'tls_cert_dir': settings.get('tls_cert_dir'), | |||
462 | 'search_scope': settings.get('search_scope'), |
|
475 | 'search_scope': settings.get('search_scope'), | |
463 | 'attr_login': settings.get('attr_login'), |
|
476 | 'attr_login': settings.get('attr_login'), | |
464 | 'ldap_version': 3, |
|
477 | 'ldap_version': 3, | |
@@ -490,10 +503,8 b' class RhodeCodeAuthPlugin(RhodeCodeExter' | |||||
490 | groups = [] |
|
503 | groups = [] | |
491 | user_attrs = { |
|
504 | user_attrs = { | |
492 | 'username': username, |
|
505 | 'username': username, | |
493 | 'firstname': safe_unicode( |
|
506 | 'firstname': safe_unicode(get_ldap_attr('attr_firstname') or firstname), | |
494 |
|
|
507 | 'lastname': safe_unicode(get_ldap_attr('attr_lastname') or lastname), | |
495 | 'lastname': safe_unicode( |
|
|||
496 | get_ldap_attr('attr_lastname') or lastname), |
|
|||
497 | 'groups': groups, |
|
508 | 'groups': groups, | |
498 | 'user_group_sync': False, |
|
509 | 'user_group_sync': False, | |
499 | 'email': get_ldap_attr('attr_email') or email, |
|
510 | 'email': get_ldap_attr('attr_email') or email, | |
@@ -503,6 +514,7 b' class RhodeCodeAuthPlugin(RhodeCodeExter' | |||||
503 | 'extern_name': user_dn, |
|
514 | 'extern_name': user_dn, | |
504 | 'extern_type': extern_type, |
|
515 | 'extern_type': extern_type, | |
505 | } |
|
516 | } | |
|
517 | ||||
506 | log.debug('ldap user: %s', user_attrs) |
|
518 | log.debug('ldap user: %s', user_attrs) | |
507 | log.info('user `%s` authenticated correctly', user_attrs['username']) |
|
519 | log.info('user `%s` authenticated correctly', user_attrs['username']) | |
508 |
|
520 | |||
@@ -514,4 +526,3 b' class RhodeCodeAuthPlugin(RhodeCodeExter' | |||||
514 | except (Exception,): |
|
526 | except (Exception,): | |
515 | log.exception("Other exception") |
|
527 | log.exception("Other exception") | |
516 | return None |
|
528 | return None | |
517 |
|
General Comments 0
You need to be logged in to leave comments.
Login now