##// END OF EJS Templates
ldap-auth: fixed wrong Missing check
marcink -
r126:d027fa2e default
parent child Browse files
Show More
@@ -1,460 +1,461 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 RhodeCode authentication plugin for LDAP
23 23 """
24 24
25 25
26 26 import colander
27 27 import logging
28 28 import traceback
29 29
30 30 from pylons.i18n.translation import lazy_ugettext as _
31 31 from sqlalchemy.ext.hybrid import hybrid_property
32 32
33 33 from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin
34 34 from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase
35 35 from rhodecode.authentication.routes import AuthnPluginResourceBase
36 36 from rhodecode.lib.colander_utils import strip_whitespace
37 37 from rhodecode.lib.exceptions import (
38 38 LdapConnectionError, LdapUsernameError, LdapPasswordError, LdapImportError
39 39 )
40 40 from rhodecode.lib.utils2 import safe_unicode, safe_str
41 41 from rhodecode.model.db import User
42 42 from rhodecode.model.validators import Missing
43 43
44 44 log = logging.getLogger(__name__)
45 45
46 46 try:
47 47 import ldap
48 48 except ImportError:
49 # means that python-ldap is not installed
50 ldap = Missing()
49 # means that python-ldap is not installed, we use Missing object to mark
50 # ldap lib is Missing
51 ldap = Missing
51 52
52 53
53 54 def plugin_factory(plugin_id, *args, **kwds):
54 55 """
55 56 Factory function that is called during plugin discovery.
56 57 It returns the plugin instance.
57 58 """
58 59 plugin = RhodeCodeAuthPlugin(plugin_id)
59 60 return plugin
60 61
61 62
62 63 class LdapAuthnResource(AuthnPluginResourceBase):
63 64 pass
64 65
65 66
66 67 class LdapSettingsSchema(AuthnPluginSettingsSchemaBase):
67 68 tls_kind_choices = ['PLAIN', 'LDAPS', 'START_TLS']
68 69 tls_reqcert_choices = ['NEVER', 'ALLOW', 'TRY', 'DEMAND', 'HARD']
69 70 search_scope_choices = ['BASE', 'ONELEVEL', 'SUBTREE']
70 71
71 72 host = colander.SchemaNode(
72 73 colander.String(),
73 74 default='',
74 75 description=_('Host of the LDAP Server'),
75 76 preparer=strip_whitespace,
76 77 title=_('LDAP Host'),
77 78 widget='string')
78 79 port = colander.SchemaNode(
79 80 colander.Int(),
80 81 default=389,
81 82 description=_('Port that the LDAP server is listening on'),
82 83 preparer=strip_whitespace,
83 84 title=_('Port'),
84 85 validator=colander.Range(min=0, max=65536),
85 86 widget='int')
86 87 dn_user = colander.SchemaNode(
87 88 colander.String(),
88 89 default='',
89 90 description=_('User to connect to LDAP'),
90 91 missing='',
91 92 preparer=strip_whitespace,
92 93 title=_('Account'),
93 94 widget='string')
94 95 dn_pass = colander.SchemaNode(
95 96 colander.String(),
96 97 default='',
97 98 description=_('Password to connect to LDAP'),
98 99 missing='',
99 100 preparer=strip_whitespace,
100 101 title=_('Password'),
101 102 widget='password')
102 103 tls_kind = colander.SchemaNode(
103 104 colander.String(),
104 105 default=tls_kind_choices[0],
105 106 description=_('TLS Type'),
106 107 title=_('Connection Security'),
107 108 validator=colander.OneOf(tls_kind_choices),
108 109 widget='select')
109 110 tls_reqcert = colander.SchemaNode(
110 111 colander.String(),
111 112 default=tls_reqcert_choices[0],
112 113 description=_('Require Cert over TLS?'),
113 114 title=_('Certificate Checks'),
114 115 validator=colander.OneOf(tls_reqcert_choices),
115 116 widget='select')
116 117 base_dn = colander.SchemaNode(
117 118 colander.String(),
118 119 default='',
119 120 description=_('Base DN to search (e.g., dc=mydomain,dc=com)'),
120 121 missing='',
121 122 preparer=strip_whitespace,
122 123 title=_('Base DN'),
123 124 widget='string')
124 125 filter = colander.SchemaNode(
125 126 colander.String(),
126 127 default='',
127 128 description=_('Filter to narrow results (e.g., ou=Users, etc)'),
128 129 missing='',
129 130 preparer=strip_whitespace,
130 131 title=_('LDAP Search Filter'),
131 132 widget='string')
132 133 search_scope = colander.SchemaNode(
133 134 colander.String(),
134 135 default=search_scope_choices[0],
135 136 description=_('How deep to search LDAP'),
136 137 title=_('LDAP Search Scope'),
137 138 validator=colander.OneOf(search_scope_choices),
138 139 widget='select')
139 140 attr_login = colander.SchemaNode(
140 141 colander.String(),
141 142 default='',
142 143 description=_('LDAP Attribute to map to user name'),
143 144 missing_msg=_('The LDAP Login attribute of the CN must be specified'),
144 145 preparer=strip_whitespace,
145 146 title=_('Login Attribute'),
146 147 widget='string')
147 148 attr_firstname = colander.SchemaNode(
148 149 colander.String(),
149 150 default='',
150 151 description=_('LDAP Attribute to map to first name'),
151 152 missing='',
152 153 preparer=strip_whitespace,
153 154 title=_('First Name Attribute'),
154 155 widget='string')
155 156 attr_lastname = colander.SchemaNode(
156 157 colander.String(),
157 158 default='',
158 159 description=_('LDAP Attribute to map to last name'),
159 160 missing='',
160 161 preparer=strip_whitespace,
161 162 title=_('Last Name Attribute'),
162 163 widget='string')
163 164 attr_email = colander.SchemaNode(
164 165 colander.String(),
165 166 default='',
166 167 description=_('LDAP Attribute to map to email address'),
167 168 missing='',
168 169 preparer=strip_whitespace,
169 170 title=_('Email Attribute'),
170 171 widget='string')
171 172
172 173
173 174 class AuthLdap(object):
174 175
175 176 def _build_servers(self):
176 177 return ', '.join(
177 178 ["{}://{}:{}".format(
178 179 self.ldap_server_type, host.strip(), self.LDAP_SERVER_PORT)
179 180 for host in self.SERVER_ADDRESSES])
180 181
181 182 def __init__(self, server, base_dn, port=389, bind_dn='', bind_pass='',
182 183 tls_kind='PLAIN', tls_reqcert='DEMAND', ldap_version=3,
183 184 search_scope='SUBTREE', attr_login='uid',
184 185 ldap_filter='(&(objectClass=user)(!(objectClass=computer)))'):
185 if isinstance(ldap, Missing):
186 if ldap == Missing:
186 187 raise LdapImportError("Missing or incompatible ldap library")
187 188
188 189 self.ldap_version = ldap_version
189 190 self.ldap_server_type = 'ldap'
190 191
191 192 self.TLS_KIND = tls_kind
192 193
193 194 if self.TLS_KIND == 'LDAPS':
194 195 port = port or 689
195 196 self.ldap_server_type += 's'
196 197
197 198 OPT_X_TLS_DEMAND = 2
198 199 self.TLS_REQCERT = getattr(ldap, 'OPT_X_TLS_%s' % tls_reqcert,
199 200 OPT_X_TLS_DEMAND)
200 201 # split server into list
201 202 self.SERVER_ADDRESSES = server.split(',')
202 203 self.LDAP_SERVER_PORT = port
203 204
204 205 # USE FOR READ ONLY BIND TO LDAP SERVER
205 206 self.attr_login = attr_login
206 207
207 208 self.LDAP_BIND_DN = safe_str(bind_dn)
208 209 self.LDAP_BIND_PASS = safe_str(bind_pass)
209 210 self.LDAP_SERVER = self._build_servers()
210 211 self.SEARCH_SCOPE = getattr(ldap, 'SCOPE_%s' % search_scope)
211 212 self.BASE_DN = safe_str(base_dn)
212 213 self.LDAP_FILTER = safe_str(ldap_filter)
213 214
214 215 def _get_ldap_server(self):
215 216 if hasattr(ldap, 'OPT_X_TLS_CACERTDIR'):
216 217 ldap.set_option(ldap.OPT_X_TLS_CACERTDIR,
217 218 '/etc/openldap/cacerts')
218 219 ldap.set_option(ldap.OPT_REFERRALS, ldap.OPT_OFF)
219 220 ldap.set_option(ldap.OPT_RESTART, ldap.OPT_ON)
220 221 ldap.set_option(ldap.OPT_TIMEOUT, 20)
221 222 ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 10)
222 223 ldap.set_option(ldap.OPT_TIMELIMIT, 15)
223 224 if self.TLS_KIND != 'PLAIN':
224 225 ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, self.TLS_REQCERT)
225 226 server = ldap.initialize(self.LDAP_SERVER)
226 227 if self.ldap_version == 2:
227 228 server.protocol = ldap.VERSION2
228 229 else:
229 230 server.protocol = ldap.VERSION3
230 231
231 232 if self.TLS_KIND == 'START_TLS':
232 233 server.start_tls_s()
233 234
234 235 if self.LDAP_BIND_DN and self.LDAP_BIND_PASS:
235 236 log.debug('Trying simple_bind with password and given DN: %s',
236 237 self.LDAP_BIND_DN)
237 238 server.simple_bind_s(self.LDAP_BIND_DN, self.LDAP_BIND_PASS)
238 239
239 240 return server
240 241
241 242 def get_uid(self, username):
242 243 from rhodecode.lib.helpers import chop_at
243 244 uid = username
244 245 for server_addr in self.SERVER_ADDRESSES:
245 246 uid = chop_at(username, "@%s" % server_addr)
246 247 return uid
247 248
248 249 def fetch_attrs_from_simple_bind(self, server, dn, username, password):
249 250 try:
250 251 log.debug('Trying simple bind with %s', dn)
251 252 server.simple_bind_s(dn, safe_str(password))
252 253 user = server.search_ext_s(
253 254 dn, ldap.SCOPE_BASE, '(objectClass=*)', )[0]
254 255 _, attrs = user
255 256 return attrs
256 257
257 258 except ldap.INVALID_CREDENTIALS:
258 259 log.debug(
259 260 "LDAP rejected password for user '%s': %s, org_exc:",
260 261 username, dn, exc_info=True)
261 262
262 263 def authenticate_ldap(self, username, password):
263 264 """
264 265 Authenticate a user via LDAP and return his/her LDAP properties.
265 266
266 267 Raises AuthenticationError if the credentials are rejected, or
267 268 EnvironmentError if the LDAP server can't be reached.
268 269
269 270 :param username: username
270 271 :param password: password
271 272 """
272 273
273 274 uid = self.get_uid(username)
274 275
275 276 if not password:
276 277 msg = "Authenticating user %s with blank password not allowed"
277 278 log.warning(msg, username)
278 279 raise LdapPasswordError(msg)
279 280 if "," in username:
280 281 raise LdapUsernameError("invalid character in username: ,")
281 282 try:
282 283 server = self._get_ldap_server()
283 284 filter_ = '(&%s(%s=%s))' % (
284 285 self.LDAP_FILTER, self.attr_login, username)
285 286 log.debug("Authenticating %r filter %s at %s", self.BASE_DN,
286 287 filter_, self.LDAP_SERVER)
287 288 lobjects = server.search_ext_s(
288 289 self.BASE_DN, self.SEARCH_SCOPE, filter_)
289 290
290 291 if not lobjects:
291 292 raise ldap.NO_SUCH_OBJECT()
292 293
293 294 for (dn, _attrs) in lobjects:
294 295 if dn is None:
295 296 continue
296 297
297 298 user_attrs = self.fetch_attrs_from_simple_bind(
298 299 server, dn, username, password)
299 300 if user_attrs:
300 301 break
301 302
302 303 else:
303 304 log.debug("No matching LDAP objects for authentication "
304 305 "of '%s' (%s)", uid, username)
305 306 raise LdapPasswordError('Failed to authenticate user '
306 307 'with given password')
307 308
308 309 except ldap.NO_SUCH_OBJECT:
309 310 log.debug("LDAP says no such user '%s' (%s), org_exc:",
310 311 uid, username, exc_info=True)
311 312 raise LdapUsernameError()
312 313 except ldap.SERVER_DOWN:
313 314 org_exc = traceback.format_exc()
314 315 raise LdapConnectionError(
315 316 "LDAP can't access authentication "
316 317 "server, org_exc:%s" % org_exc)
317 318
318 319 return dn, user_attrs
319 320
320 321
321 322 class RhodeCodeAuthPlugin(RhodeCodeExternalAuthPlugin):
322 323 # used to define dynamic binding in the
323 324 DYNAMIC_BIND_VAR = '$login'
324 325
325 326 def includeme(self, config):
326 327 config.add_authn_plugin(self)
327 328 config.add_authn_resource(self.get_id(), LdapAuthnResource(self))
328 329 config.add_view(
329 330 'rhodecode.authentication.views.AuthnPluginViewBase',
330 331 attr='settings_get',
331 332 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
332 333 request_method='GET',
333 334 route_name='auth_home',
334 335 context=LdapAuthnResource)
335 336 config.add_view(
336 337 'rhodecode.authentication.views.AuthnPluginViewBase',
337 338 attr='settings_post',
338 339 renderer='rhodecode:templates/admin/auth/plugin_settings.html',
339 340 request_method='POST',
340 341 route_name='auth_home',
341 342 context=LdapAuthnResource)
342 343
343 344 def get_settings_schema(self):
344 345 return LdapSettingsSchema()
345 346
346 347 def get_display_name(self):
347 348 return _('LDAP')
348 349
349 350 @hybrid_property
350 351 def name(self):
351 352 return "ldap"
352 353
353 354 def use_fake_password(self):
354 355 return True
355 356
356 357 def user_activation_state(self):
357 358 def_user_perms = User.get_default_user().AuthUser.permissions['global']
358 359 return 'hg.extern_activate.auto' in def_user_perms
359 360
360 361 def try_dynamic_binding(self, username, password, current_args):
361 362 """
362 363 Detects marker inside our original bind, and uses dynamic auth if
363 364 present
364 365 """
365 366
366 367 org_bind = current_args['bind_dn']
367 368 passwd = current_args['bind_pass']
368 369
369 370 def has_bind_marker(username):
370 371 if self.DYNAMIC_BIND_VAR in username:
371 372 return True
372 373
373 374 # we only passed in user with "special" variable
374 375 if org_bind and has_bind_marker(org_bind) and not passwd:
375 376 log.debug('Using dynamic user/password binding for ldap '
376 377 'authentication. Replacing `%s` with username',
377 378 self.DYNAMIC_BIND_VAR)
378 379 current_args['bind_dn'] = org_bind.replace(
379 380 self.DYNAMIC_BIND_VAR, username)
380 381 current_args['bind_pass'] = password
381 382
382 383 return current_args
383 384
384 385 def auth(self, userobj, username, password, settings, **kwargs):
385 386 """
386 387 Given a user object (which may be null), username, a plaintext password,
387 388 and a settings object (containing all the keys needed as listed in
388 389 settings()), authenticate this user's login attempt.
389 390
390 391 Return None on failure. On success, return a dictionary of the form:
391 392
392 393 see: RhodeCodeAuthPluginBase.auth_func_attrs
393 394 This is later validated for correctness
394 395 """
395 396
396 397 if not username or not password:
397 398 log.debug('Empty username or password skipping...')
398 399 return None
399 400
400 401 ldap_args = {
401 402 'server': settings.get('host', ''),
402 403 'base_dn': settings.get('base_dn', ''),
403 404 'port': settings.get('port'),
404 405 'bind_dn': settings.get('dn_user'),
405 406 'bind_pass': settings.get('dn_pass'),
406 407 'tls_kind': settings.get('tls_kind'),
407 408 'tls_reqcert': settings.get('tls_reqcert'),
408 409 'search_scope': settings.get('search_scope'),
409 410 'attr_login': settings.get('attr_login'),
410 411 'ldap_version': 3,
411 412 'ldap_filter': settings.get('filter'),
412 413 }
413 414
414 415 ldap_attrs = self.try_dynamic_binding(username, password, ldap_args)
415 416
416 417 log.debug('Checking for ldap authentication.')
417 418
418 419 try:
419 420 aldap = AuthLdap(**ldap_args)
420 421 (user_dn, ldap_attrs) = aldap.authenticate_ldap(username, password)
421 422 log.debug('Got ldap DN response %s', user_dn)
422 423
423 424 def get_ldap_attr(k):
424 425 return ldap_attrs.get(settings.get(k), [''])[0]
425 426
426 427 # old attrs fetched from RhodeCode database
427 428 admin = getattr(userobj, 'admin', False)
428 429 active = getattr(userobj, 'active', True)
429 430 email = getattr(userobj, 'email', '')
430 431 username = getattr(userobj, 'username', username)
431 432 firstname = getattr(userobj, 'firstname', '')
432 433 lastname = getattr(userobj, 'lastname', '')
433 434 extern_type = getattr(userobj, 'extern_type', '')
434 435
435 436 groups = []
436 437 user_attrs = {
437 438 'username': username,
438 439 'firstname': safe_unicode(
439 440 get_ldap_attr('attr_firstname') or firstname),
440 441 'lastname': safe_unicode(
441 442 get_ldap_attr('attr_lastname') or lastname),
442 443 'groups': groups,
443 444 'email': get_ldap_attr('attr_email' or email),
444 445 'admin': admin,
445 446 'active': active,
446 447 "active_from_extern": None,
447 448 'extern_name': user_dn,
448 449 'extern_type': extern_type,
449 450 }
450 451 log.debug('ldap user: %s', user_attrs)
451 452 log.info('user %s authenticated correctly', user_attrs['username'])
452 453
453 454 return user_attrs
454 455
455 456 except (LdapUsernameError, LdapPasswordError, LdapImportError):
456 457 log.exception("LDAP related exception")
457 458 return None
458 459 except (Exception,):
459 460 log.exception("Other exception")
460 461 return None
@@ -1,157 +1,183 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import mock
22 22 import pytest
23 23
24 24 from rhodecode.lib.auth import _RhodeCodeCryptoBCrypt
25 25 from rhodecode.authentication.base import RhodeCodeAuthPluginBase
26 26 from rhodecode.authentication.plugins.auth_ldap import RhodeCodeAuthPlugin
27 27 from rhodecode.model import db
28 28
29 29
30 30 def test_authenticate_returns_from_auth(stub_auth_data):
31 31 plugin = RhodeCodeAuthPluginBase('stub_id')
32 32 with mock.patch.object(plugin, 'auth') as auth_mock:
33 33 auth_mock.return_value = stub_auth_data
34 34 result = plugin._authenticate(mock.Mock(), 'test', 'password', {})
35 35 assert stub_auth_data == result
36 36
37 37
38 38 def test_authenticate_returns_empty_auth_data():
39 39 auth_data = {}
40 40 plugin = RhodeCodeAuthPluginBase('stub_id')
41 41 with mock.patch.object(plugin, 'auth') as auth_mock:
42 42 auth_mock.return_value = auth_data
43 43 result = plugin._authenticate(mock.Mock(), 'test', 'password', {})
44 44 assert auth_data == result
45 45
46 46
47 47 def test_authenticate_skips_hash_migration_if_mismatch(stub_auth_data):
48 48 stub_auth_data['_hash_migrate'] = 'new-hash'
49 49 plugin = RhodeCodeAuthPluginBase('stub_id')
50 50 with mock.patch.object(plugin, 'auth') as auth_mock:
51 51 auth_mock.return_value = stub_auth_data
52 52 result = plugin._authenticate(mock.Mock(), 'test', 'password', {})
53 53
54 54 user = db.User.get_by_username(stub_auth_data['username'])
55 55 assert user.password != 'new-hash'
56 56 assert result == stub_auth_data
57 57
58 58
59 59 def test_authenticate_migrates_to_new_hash(stub_auth_data):
60 60 new_password = b'new-password'
61 61 new_hash = _RhodeCodeCryptoBCrypt().hash_create(new_password)
62 62 stub_auth_data['_hash_migrate'] = new_hash
63 63 plugin = RhodeCodeAuthPluginBase('stub_id')
64 64 with mock.patch.object(plugin, 'auth') as auth_mock:
65 65 auth_mock.return_value = stub_auth_data
66 66 result = plugin._authenticate(
67 67 mock.Mock(), stub_auth_data['username'], new_password, {})
68 68
69 69 user = db.User.get_by_username(stub_auth_data['username'])
70 70 assert user.password == new_hash
71 71 assert result == stub_auth_data
72 72
73 73
74 74 @pytest.fixture
75 75 def stub_auth_data(user_util):
76 76 user = user_util.create_user()
77 77 data = {
78 78 'username': user.username,
79 79 'password': 'password',
80 80 'email': 'test@example.org',
81 81 'firstname': 'John',
82 82 'lastname': 'Smith',
83 83 'groups': [],
84 84 'active': True,
85 85 'admin': False,
86 86 'extern_name': 'test',
87 87 'extern_type': 'ldap',
88 88 'active_from_extern': True
89 89 }
90 90 return data
91 91
92 92
93 93 class TestRhodeCodeAuthPlugin(object):
94 94 def setup_method(self, method):
95 95 self.finalizers = []
96 96 self.user = mock.Mock()
97 97 self.user.username = 'test'
98 98 self.user.password = 'old-password'
99 99 self.fake_auth = {
100 100 'username': 'test',
101 101 'password': 'test',
102 102 'email': 'test@example.org',
103 103 'firstname': 'John',
104 104 'lastname': 'Smith',
105 105 'groups': [],
106 106 'active': True,
107 107 'admin': False,
108 108 'extern_name': 'test',
109 109 'extern_type': 'ldap',
110 110 'active_from_extern': True
111 111 }
112 112
113 113 def teardown_method(self, method):
114 114 if self.finalizers:
115 115 for finalizer in self.finalizers:
116 116 finalizer()
117 117 self.finalizers = []
118 118
119 119 def test_fake_password_is_created_for_the_new_user(self):
120 120 self._patch()
121 121 auth_plugin = RhodeCodeAuthPlugin('stub_id')
122 122 auth_plugin._authenticate(self.user, 'test', 'test', [])
123 123 self.password_generator_mock.assert_called_once_with(length=16)
124 124 create_user_kwargs = self.create_user_mock.call_args[1]
125 125 assert create_user_kwargs['password'] == 'new-password'
126 126
127 127 def test_fake_password_is_not_created_for_the_existing_user(self):
128 128 self._patch()
129 129 self.get_user_mock.return_value = self.user
130 130 auth_plugin = RhodeCodeAuthPlugin('stub_id')
131 131 auth_plugin._authenticate(self.user, 'test', 'test', [])
132 132 assert self.password_generator_mock.called is False
133 133 create_user_kwargs = self.create_user_mock.call_args[1]
134 134 assert create_user_kwargs['password'] == self.user.password
135 135
136 136 def _patch(self):
137 137 get_user_patch = mock.patch('rhodecode.model.db.User.get_by_username')
138 138 self.get_user_mock = get_user_patch.start()
139 139 self.get_user_mock.return_value = None
140 140 self.finalizers.append(get_user_patch.stop)
141 141
142 142 create_user_patch = mock.patch(
143 143 'rhodecode.model.user.UserModel.create_or_update')
144 144 self.create_user_mock = create_user_patch.start()
145 145 self.create_user_mock.return_value = None
146 146 self.finalizers.append(create_user_patch.stop)
147 147
148 148 auth_patch = mock.patch.object(RhodeCodeAuthPlugin, 'auth')
149 149 self.auth_mock = auth_patch.start()
150 150 self.auth_mock.return_value = self.fake_auth
151 151 self.finalizers.append(auth_patch.stop)
152 152
153 153 password_generator_patch = mock.patch(
154 154 'rhodecode.lib.auth.PasswordGenerator.gen_password')
155 155 self.password_generator_mock = password_generator_patch.start()
156 156 self.password_generator_mock.return_value = 'new-password'
157 157 self.finalizers.append(password_generator_patch.stop)
158
159
160 def test_missing_ldap():
161 from rhodecode.model.validators import Missing
162
163 try:
164 import ldap_not_existing
165 except ImportError:
166 # means that python-ldap is not installed
167 ldap_not_existing = Missing
168
169 # missing is singleton
170 assert ldap_not_existing == Missing
171
172
173 def test_import_ldap():
174 from rhodecode.model.validators import Missing
175
176 try:
177 import ldap
178 except ImportError:
179 # means that python-ldap is not installed
180 ldap = Missing
181
182 # missing is singleton
183 assert False is (ldap == Missing)
General Comments 0
You need to be logged in to leave comments. Login now