##// END OF EJS Templates
fixes #173, many thanks for slestak for contributing into this one.
marcink -
r1425:3dedf399 beta
parent child Browse files
Show More
@@ -1,9 +1,10 b''
1 1 List of contributors to RhodeCode project:
2 2 Marcin Kuźmiński <marcin@python-works.com>
3 3 Lukasz Balcerzak <lukaszbalcerzak@gmail.com>
4 4 Jason Harris <jason@jasonfharris.com>
5 5 Thayne Harbaugh <thayne@fusionio.com>
6 6 cejones
7 7 Lorenzo M. Catucci <lorenzo@sancho.ccd.uniroma2.it>
8 8 Dmitri Kuznetsov
9 Jared Bunting <jared.bunting@peachjean.com> No newline at end of file
9 Jared Bunting <jared.bunting@peachjean.com>
10 Steve Romanow <slestak989@gmail.com> No newline at end of file
@@ -1,613 +1,613 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.auth
4 4 ~~~~~~~~~~~~~~~~~~
5 5
6 6 authentication and permission libraries
7 7
8 8 :created_on: Apr 4, 2010
9 9 :copyright: (c) 2010 by marcink.
10 10 :license: LICENSE_NAME, see LICENSE_FILE for more details.
11 11 """
12 12 # This program is free software: you can redistribute it and/or modify
13 13 # it under the terms of the GNU General Public License as published by
14 14 # the Free Software Foundation, either version 3 of the License, or
15 15 # (at your option) any later version.
16 16 #
17 17 # This program is distributed in the hope that it will be useful,
18 18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 20 # GNU General Public License for more details.
21 21 #
22 22 # You should have received a copy of the GNU General Public License
23 23 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 24
25 25 import random
26 26 import logging
27 27 import traceback
28 28 import hashlib
29 29
30 30 from tempfile import _RandomNameSequence
31 31 from decorator import decorator
32 32
33 33 from pylons import config, session, url, request
34 34 from pylons.controllers.util import abort, redirect
35 35 from pylons.i18n.translation import _
36 36
37 37 from rhodecode import __platform__, PLATFORM_WIN, PLATFORM_OTHERS
38 38
39 39 if __platform__ in PLATFORM_WIN:
40 40 from hashlib import sha256
41 41 if __platform__ in PLATFORM_OTHERS:
42 42 import bcrypt
43 43
44 from rhodecode.lib import str2bool
44 from rhodecode.lib import str2bool, safe_unicode
45 45 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
46 46 from rhodecode.lib.utils import get_repo_slug
47 47 from rhodecode.lib.auth_ldap import AuthLdap
48 48
49 49 from rhodecode.model import meta
50 50 from rhodecode.model.user import UserModel
51 51 from rhodecode.model.db import Permission, RhodeCodeSettings
52 52
53 53 log = logging.getLogger(__name__)
54 54
55 55
56 56 class PasswordGenerator(object):
57 57 """This is a simple class for generating password from
58 58 different sets of characters
59 59 usage:
60 60 passwd_gen = PasswordGenerator()
61 61 #print 8-letter password containing only big and small letters
62 62 of alphabet
63 63 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
64 64 """
65 65 ALPHABETS_NUM = r'''1234567890'''
66 66 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
67 67 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
68 68 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
69 69 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
70 70 + ALPHABETS_NUM + ALPHABETS_SPECIAL
71 71 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
72 72 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
73 73 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
74 74 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
75 75
76 76 def __init__(self, passwd=''):
77 77 self.passwd = passwd
78 78
79 79 def gen_password(self, len, type):
80 80 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
81 81 return self.passwd
82 82
83 83
84 84 class RhodeCodeCrypto(object):
85 85
86 86 @classmethod
87 87 def hash_string(cls, str_):
88 88 """
89 89 Cryptographic function used for password hashing based on pybcrypt
90 90 or pycrypto in windows
91 91
92 92 :param password: password to hash
93 93 """
94 94 if __platform__ in PLATFORM_WIN:
95 95 return sha256(str_).hexdigest()
96 96 elif __platform__ in PLATFORM_OTHERS:
97 97 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
98 98 else:
99 99 raise Exception('Unknown or unsupported platform %s' \
100 100 % __platform__)
101 101
102 102 @classmethod
103 103 def hash_check(cls, password, hashed):
104 104 """
105 105 Checks matching password with it's hashed value, runs different
106 106 implementation based on platform it runs on
107 107
108 108 :param password: password
109 109 :param hashed: password in hashed form
110 110 """
111 111
112 112 if __platform__ in PLATFORM_WIN:
113 113 return sha256(password).hexdigest() == hashed
114 114 elif __platform__ in PLATFORM_OTHERS:
115 115 return bcrypt.hashpw(password, hashed) == hashed
116 116 else:
117 117 raise Exception('Unknown or unsupported platform %s' \
118 118 % __platform__)
119 119
120 120
121 121 def get_crypt_password(password):
122 122 return RhodeCodeCrypto.hash_string(password)
123 123
124 124
125 125 def check_password(password, hashed):
126 126 return RhodeCodeCrypto.hash_check(password, hashed)
127 127
128 128
129 129 def generate_api_key(username, salt=None):
130 130 if salt is None:
131 131 salt = _RandomNameSequence().next()
132 132
133 133 return hashlib.sha1(username + salt).hexdigest()
134 134
135 135
136 136 def authfunc(environ, username, password):
137 137 """Dummy authentication function used in Mercurial/Git/ and access control,
138 138
139 139 :param environ: needed only for using in Basic auth
140 140 """
141 141 return authenticate(username, password)
142 142
143 143
144 144 def authenticate(username, password):
145 145 """Authentication function used for access control,
146 146 firstly checks for db authentication then if ldap is enabled for ldap
147 147 authentication, also creates ldap user if not in database
148 148
149 149 :param username: username
150 150 :param password: password
151 151 """
152 152
153 153 user_model = UserModel()
154 154 user = user_model.get_by_username(username, cache=False)
155 155
156 156 log.debug('Authenticating user using RhodeCode account')
157 157 if user is not None and not user.ldap_dn:
158 158 if user.active:
159 159 if user.username == 'default' and user.active:
160 160 log.info('user %s authenticated correctly as anonymous user',
161 161 username)
162 162 return True
163 163
164 164 elif user.username == username and check_password(password,
165 165 user.password):
166 166 log.info('user %s authenticated correctly', username)
167 167 return True
168 168 else:
169 169 log.warning('user %s is disabled', username)
170 170
171 171 else:
172 172 log.debug('Regular authentication failed')
173 173 user_obj = user_model.get_by_username(username, cache=False,
174 174 case_insensitive=True)
175 175
176 176 if user_obj is not None and not user_obj.ldap_dn:
177 177 log.debug('this user already exists as non ldap')
178 178 return False
179 179
180 180 ldap_settings = RhodeCodeSettings.get_ldap_settings()
181 181 #======================================================================
182 182 # FALLBACK TO LDAP AUTH IF ENABLE
183 183 #======================================================================
184 184 if str2bool(ldap_settings.get('ldap_active')):
185 185 log.debug("Authenticating user using ldap")
186 186 kwargs = {
187 187 'server': ldap_settings.get('ldap_host', ''),
188 188 'base_dn': ldap_settings.get('ldap_base_dn', ''),
189 189 'port': ldap_settings.get('ldap_port'),
190 190 'bind_dn': ldap_settings.get('ldap_dn_user'),
191 191 'bind_pass': ldap_settings.get('ldap_dn_pass'),
192 192 'tls_kind': ldap_settings.get('ldap_tls_kind'),
193 193 'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'),
194 194 'ldap_filter': ldap_settings.get('ldap_filter'),
195 195 'search_scope': ldap_settings.get('ldap_search_scope'),
196 196 'attr_login': ldap_settings.get('ldap_attr_login'),
197 197 'ldap_version': 3,
198 198 }
199 199 log.debug('Checking for ldap authentication')
200 200 try:
201 201 aldap = AuthLdap(**kwargs)
202 202 (user_dn, ldap_attrs) = aldap.authenticate_ldap(username,
203 203 password)
204 204 log.debug('Got ldap DN response %s', user_dn)
205 205
206 206 get_ldap_attr = lambda k: ldap_attrs.get(ldap_settings\
207 207 .get(k), [''])[0]
208 208
209 209 user_attrs = {
210 'name': get_ldap_attr('ldap_attr_firstname'),
211 'lastname': get_ldap_attr('ldap_attr_lastname'),
212 'email': get_ldap_attr('ldap_attr_email'),
213 }
210 'name': safe_unicode(get_ldap_attr('ldap_attr_firstname')),
211 'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')),
212 'email': get_ldap_attr('ldap_attr_email'),
213 }
214 214
215 215 if user_model.create_ldap(username, password, user_dn,
216 216 user_attrs):
217 217 log.info('created new ldap user %s', username)
218 218
219 219 return True
220 220 except (LdapUsernameError, LdapPasswordError,):
221 221 pass
222 222 except (Exception,):
223 223 log.error(traceback.format_exc())
224 224 pass
225 225 return False
226 226
227 227
228 228 class AuthUser(object):
229 229 """
230 230 A simple object that handles all attributes of user in RhodeCode
231 231
232 232 It does lookup based on API key,given user, or user present in session
233 233 Then it fills all required information for such user. It also checks if
234 234 anonymous access is enabled and if so, it returns default user as logged
235 235 in
236 236 """
237 237
238 238 def __init__(self, user_id=None, api_key=None):
239 239
240 240 self.user_id = user_id
241 241 self.api_key = None
242 242
243 243 self.username = 'None'
244 244 self.name = ''
245 245 self.lastname = ''
246 246 self.email = ''
247 247 self.is_authenticated = False
248 248 self.admin = False
249 249 self.permissions = {}
250 250 self._api_key = api_key
251 251 self.propagate_data()
252 252
253 253 def propagate_data(self):
254 254 user_model = UserModel()
255 255 self.anonymous_user = user_model.get_by_username('default', cache=True)
256 256 if self._api_key and self._api_key != self.anonymous_user.api_key:
257 257 #try go get user by api key
258 258 log.debug('Auth User lookup by API KEY %s', self._api_key)
259 259 user_model.fill_data(self, api_key=self._api_key)
260 260 else:
261 261 log.debug('Auth User lookup by USER ID %s', self.user_id)
262 262 if self.user_id is not None \
263 263 and self.user_id != self.anonymous_user.user_id:
264 264 user_model.fill_data(self, user_id=self.user_id)
265 265 else:
266 266 if self.anonymous_user.active is True:
267 267 user_model.fill_data(self,
268 268 user_id=self.anonymous_user.user_id)
269 269 #then we set this user is logged in
270 270 self.is_authenticated = True
271 271 else:
272 272 self.is_authenticated = False
273 273
274 274 log.debug('Auth User is now %s', self)
275 275 user_model.fill_perms(self)
276 276
277 277 @property
278 278 def is_admin(self):
279 279 return self.admin
280 280
281 281 @property
282 282 def full_contact(self):
283 283 return '%s %s <%s>' % (self.name, self.lastname, self.email)
284 284
285 285 def __repr__(self):
286 286 return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
287 287 self.is_authenticated)
288 288
289 289 def set_authenticated(self, authenticated=True):
290 290
291 291 if self.user_id != self.anonymous_user.user_id:
292 292 self.is_authenticated = authenticated
293 293
294 294
295 295 def set_available_permissions(config):
296 296 """This function will propagate pylons globals with all available defined
297 297 permission given in db. We don't want to check each time from db for new
298 298 permissions since adding a new permission also requires application restart
299 299 ie. to decorate new views with the newly created permission
300 300
301 301 :param config: current pylons config instance
302 302
303 303 """
304 304 log.info('getting information about all available permissions')
305 305 try:
306 306 sa = meta.Session()
307 307 all_perms = sa.query(Permission).all()
308 308 except:
309 309 pass
310 310 finally:
311 311 meta.Session.remove()
312 312
313 313 config['available_permissions'] = [x.permission_name for x in all_perms]
314 314
315 315
316 316 #==============================================================================
317 317 # CHECK DECORATORS
318 318 #==============================================================================
319 319 class LoginRequired(object):
320 320 """
321 321 Must be logged in to execute this function else
322 322 redirect to login page
323 323
324 324 :param api_access: if enabled this checks only for valid auth token
325 325 and grants access based on valid token
326 326 """
327 327
328 328 def __init__(self, api_access=False):
329 329 self.api_access = api_access
330 330
331 331 def __call__(self, func):
332 332 return decorator(self.__wrapper, func)
333 333
334 334 def __wrapper(self, func, *fargs, **fkwargs):
335 335 cls = fargs[0]
336 336 user = cls.rhodecode_user
337 337
338 338 api_access_ok = False
339 339 if self.api_access:
340 340 log.debug('Checking API KEY access for %s', cls)
341 341 if user.api_key == request.GET.get('api_key'):
342 342 api_access_ok = True
343 343 else:
344 344 log.debug("API KEY token not valid")
345 345
346 346 log.debug('Checking if %s is authenticated @ %s', user.username, cls)
347 347 if user.is_authenticated or api_access_ok:
348 348 log.debug('user %s is authenticated', user.username)
349 349 return func(*fargs, **fkwargs)
350 350 else:
351 351 log.warn('user %s NOT authenticated', user.username)
352 352 p = url.current()
353 353
354 354 log.debug('redirecting to login page with %s', p)
355 355 return redirect(url('login_home', came_from=p))
356 356
357 357
358 358 class NotAnonymous(object):
359 359 """Must be logged in to execute this function else
360 360 redirect to login page"""
361 361
362 362 def __call__(self, func):
363 363 return decorator(self.__wrapper, func)
364 364
365 365 def __wrapper(self, func, *fargs, **fkwargs):
366 366 cls = fargs[0]
367 367 self.user = cls.rhodecode_user
368 368
369 369 log.debug('Checking if user is not anonymous @%s', cls)
370 370
371 371 anonymous = self.user.username == 'default'
372 372
373 373 if anonymous:
374 374 p = url.current()
375 375
376 376 import rhodecode.lib.helpers as h
377 377 h.flash(_('You need to be a registered user to '
378 378 'perform this action'),
379 379 category='warning')
380 380 return redirect(url('login_home', came_from=p))
381 381 else:
382 382 return func(*fargs, **fkwargs)
383 383
384 384
385 385 class PermsDecorator(object):
386 386 """Base class for controller decorators"""
387 387
388 388 def __init__(self, *required_perms):
389 389 available_perms = config['available_permissions']
390 390 for perm in required_perms:
391 391 if perm not in available_perms:
392 392 raise Exception("'%s' permission is not defined" % perm)
393 393 self.required_perms = set(required_perms)
394 394 self.user_perms = None
395 395
396 396 def __call__(self, func):
397 397 return decorator(self.__wrapper, func)
398 398
399 399 def __wrapper(self, func, *fargs, **fkwargs):
400 400 cls = fargs[0]
401 401 self.user = cls.rhodecode_user
402 402 self.user_perms = self.user.permissions
403 403 log.debug('checking %s permissions %s for %s %s',
404 404 self.__class__.__name__, self.required_perms, cls,
405 405 self.user)
406 406
407 407 if self.check_permissions():
408 408 log.debug('Permission granted for %s %s', cls, self.user)
409 409 return func(*fargs, **fkwargs)
410 410
411 411 else:
412 412 log.warning('Permission denied for %s %s', cls, self.user)
413 413
414 414
415 415 anonymous = self.user.username == 'default'
416 416
417 417 if anonymous:
418 418 p = url.current()
419 419
420 420 import rhodecode.lib.helpers as h
421 421 h.flash(_('You need to be a signed in to '
422 422 'view this page'),
423 423 category='warning')
424 424 return redirect(url('login_home', came_from=p))
425 425
426 426 else:
427 427 #redirect with forbidden ret code
428 428 return abort(403)
429 429
430 430 def check_permissions(self):
431 431 """Dummy function for overriding"""
432 432 raise Exception('You have to write this function in child class')
433 433
434 434
435 435 class HasPermissionAllDecorator(PermsDecorator):
436 436 """Checks for access permission for all given predicates. All of them
437 437 have to be meet in order to fulfill the request
438 438 """
439 439
440 440 def check_permissions(self):
441 441 if self.required_perms.issubset(self.user_perms.get('global')):
442 442 return True
443 443 return False
444 444
445 445
446 446 class HasPermissionAnyDecorator(PermsDecorator):
447 447 """Checks for access permission for any of given predicates. In order to
448 448 fulfill the request any of predicates must be meet
449 449 """
450 450
451 451 def check_permissions(self):
452 452 if self.required_perms.intersection(self.user_perms.get('global')):
453 453 return True
454 454 return False
455 455
456 456
457 457 class HasRepoPermissionAllDecorator(PermsDecorator):
458 458 """Checks for access permission for all given predicates for specific
459 459 repository. All of them have to be meet in order to fulfill the request
460 460 """
461 461
462 462 def check_permissions(self):
463 463 repo_name = get_repo_slug(request)
464 464 try:
465 465 user_perms = set([self.user_perms['repositories'][repo_name]])
466 466 except KeyError:
467 467 return False
468 468 if self.required_perms.issubset(user_perms):
469 469 return True
470 470 return False
471 471
472 472
473 473 class HasRepoPermissionAnyDecorator(PermsDecorator):
474 474 """Checks for access permission for any of given predicates for specific
475 475 repository. In order to fulfill the request any of predicates must be meet
476 476 """
477 477
478 478 def check_permissions(self):
479 479 repo_name = get_repo_slug(request)
480 480
481 481 try:
482 482 user_perms = set([self.user_perms['repositories'][repo_name]])
483 483 except KeyError:
484 484 return False
485 485 if self.required_perms.intersection(user_perms):
486 486 return True
487 487 return False
488 488
489 489
490 490 #==============================================================================
491 491 # CHECK FUNCTIONS
492 492 #==============================================================================
493 493 class PermsFunction(object):
494 494 """Base function for other check functions"""
495 495
496 496 def __init__(self, *perms):
497 497 available_perms = config['available_permissions']
498 498
499 499 for perm in perms:
500 500 if perm not in available_perms:
501 501 raise Exception("'%s' permission in not defined" % perm)
502 502 self.required_perms = set(perms)
503 503 self.user_perms = None
504 504 self.granted_for = ''
505 505 self.repo_name = None
506 506
507 507 def __call__(self, check_Location=''):
508 508 user = session.get('rhodecode_user', False)
509 509 if not user:
510 510 return False
511 511 self.user_perms = user.permissions
512 512 self.granted_for = user
513 513 log.debug('checking %s %s %s', self.__class__.__name__,
514 514 self.required_perms, user)
515 515
516 516 if self.check_permissions():
517 517 log.debug('Permission granted %s @ %s', self.granted_for,
518 518 check_Location or 'unspecified location')
519 519 return True
520 520
521 521 else:
522 522 log.warning('Permission denied for %s @ %s', self.granted_for,
523 523 check_Location or 'unspecified location')
524 524 return False
525 525
526 526 def check_permissions(self):
527 527 """Dummy function for overriding"""
528 528 raise Exception('You have to write this function in child class')
529 529
530 530
531 531 class HasPermissionAll(PermsFunction):
532 532 def check_permissions(self):
533 533 if self.required_perms.issubset(self.user_perms.get('global')):
534 534 return True
535 535 return False
536 536
537 537
538 538 class HasPermissionAny(PermsFunction):
539 539 def check_permissions(self):
540 540 if self.required_perms.intersection(self.user_perms.get('global')):
541 541 return True
542 542 return False
543 543
544 544
545 545 class HasRepoPermissionAll(PermsFunction):
546 546
547 547 def __call__(self, repo_name=None, check_Location=''):
548 548 self.repo_name = repo_name
549 549 return super(HasRepoPermissionAll, self).__call__(check_Location)
550 550
551 551 def check_permissions(self):
552 552 if not self.repo_name:
553 553 self.repo_name = get_repo_slug(request)
554 554
555 555 try:
556 556 self.user_perms = set([self.user_perms['reposit'
557 557 'ories'][self.repo_name]])
558 558 except KeyError:
559 559 return False
560 560 self.granted_for = self.repo_name
561 561 if self.required_perms.issubset(self.user_perms):
562 562 return True
563 563 return False
564 564
565 565
566 566 class HasRepoPermissionAny(PermsFunction):
567 567
568 568 def __call__(self, repo_name=None, check_Location=''):
569 569 self.repo_name = repo_name
570 570 return super(HasRepoPermissionAny, self).__call__(check_Location)
571 571
572 572 def check_permissions(self):
573 573 if not self.repo_name:
574 574 self.repo_name = get_repo_slug(request)
575 575
576 576 try:
577 577 self.user_perms = set([self.user_perms['reposi'
578 578 'tories'][self.repo_name]])
579 579 except KeyError:
580 580 return False
581 581 self.granted_for = self.repo_name
582 582 if self.required_perms.intersection(self.user_perms):
583 583 return True
584 584 return False
585 585
586 586
587 587 #==============================================================================
588 588 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
589 589 #==============================================================================
590 590 class HasPermissionAnyMiddleware(object):
591 591 def __init__(self, *perms):
592 592 self.required_perms = set(perms)
593 593
594 594 def __call__(self, user, repo_name):
595 595 usr = AuthUser(user.user_id)
596 596 try:
597 597 self.user_perms = set([usr.permissions['repositories'][repo_name]])
598 598 except:
599 599 self.user_perms = set()
600 600 self.granted_for = ''
601 601 self.username = user.username
602 602 self.repo_name = repo_name
603 603 return self.check_permissions()
604 604
605 605 def check_permissions(self):
606 606 log.debug('checking mercurial protocol '
607 607 'permissions %s for user:%s repository:%s', self.user_perms,
608 608 self.username, self.repo_name)
609 609 if self.required_perms.intersection(self.user_perms):
610 610 log.debug('permission granted')
611 611 return True
612 612 log.debug('permission denied')
613 613 return False
@@ -1,21 +1,75 b''
1 1 from rhodecode.tests import *
2 from rhodecode.model.db import RhodeCodeSettings
3
4 try:
5 import ldap
6 except ImportError:
7 # means that python-ldap is not installed
8 pass
2 9
3 10 class TestLdapSettingsController(TestController):
4 11
5 12 def test_index(self):
6 13 self.log_user()
7 14 response = self.app.get(url(controller='admin/ldap_settings',
8 15 action='index'))
9 # Test response...
16 self.assertTrue('LDAP administration' in response.body)
10 17
11 18 def test_ldap_save_settings(self):
12 pass
19 self.log_user()
20 test_url = url(controller='admin/ldap_settings',
21 action='ldap_settings')
22
23 response = self.app.post(url=test_url,
24 params={'ldap_host' : u'dc.example.com',
25 'ldap_port' : '999',
26 'ldap_tls_kind' : 'PLAIN',
27 'ldap_tls_reqcert' : 'NEVER',
28 'ldap_dn_user':'test_user',
29 'ldap_dn_pass':'test_pass',
30 'ldap_base_dn':'test_base_dn',
31 'ldap_filter':'test_filter',
32 'ldap_search_scope':'BASE',
33 'ldap_attr_login':'test_attr_login',
34 'ldap_attr_firstname':'ima',
35 'ldap_attr_lastname':'tester',
36 'ldap_attr_email':'test@example.com' })
37
38 new_settings = RhodeCodeSettings.get_ldap_settings()
39 self.assertEqual(new_settings['ldap_host'], u'dc.example.com',
40 'fail db write compare')
41
42 self.checkSessionFlash(response,
43 'Ldap settings updated successfully')
13 44
14 45 def test_ldap_error_form(self):
15 pass
46 self.log_user()
47 test_url = url(controller='admin/ldap_settings',
48 action='ldap_settings')
49
50 response = self.app.post(url=test_url,
51 params={'ldap_host' : '',
52 'ldap_port' : 'i-should-be-number',
53 'ldap_tls_kind' : 'PLAIN',
54 'ldap_tls_reqcert' : 'NEVER',
55 'ldap_dn_user':'',
56 'ldap_dn_pass':'',
57 'ldap_base_dn':'',
58 'ldap_filter':'',
59 'ldap_search_scope':'BASE',
60 'ldap_attr_login':'', # <----- missing required input
61 'ldap_attr_firstname':'',
62 'ldap_attr_lastname':'',
63 'ldap_attr_email':'' })
64
65 self.assertTrue("""<span class="error-message">The LDAP Login"""
66 """ attribute of the CN must be specified""" in
67 response.body)
68 self.assertTrue("""<span class="error-message">Please """
69 """enter a number</span>""" in response.body)
16 70
17 71 def test_ldap_login(self):
18 72 pass
19 73
20 74 def test_ldap_login_incorrect(self):
21 75 pass
General Comments 0
You need to be logged in to leave comments. Login now