##// END OF EJS Templates
Little more verbose logging for auth
marcink -
r2458:ba495411 beta
parent child Browse files
Show More
@@ -1,821 +1,822 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 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import random
27 27 import logging
28 28 import traceback
29 29 import hashlib
30 30
31 31 from tempfile import _RandomNameSequence
32 32 from decorator import decorator
33 33
34 34 from pylons import config, url, request
35 35 from pylons.controllers.util import abort, redirect
36 36 from pylons.i18n.translation import _
37 37
38 38 from rhodecode import __platform__, PLATFORM_WIN, PLATFORM_OTHERS
39 39 from rhodecode.model.meta import Session
40 40
41 41 if __platform__ in PLATFORM_WIN:
42 42 from hashlib import sha256
43 43 if __platform__ in PLATFORM_OTHERS:
44 44 import bcrypt
45 45
46 46 from rhodecode.lib.utils2 import str2bool, safe_unicode
47 47 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
48 48 from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug
49 49 from rhodecode.lib.auth_ldap import AuthLdap
50 50
51 51 from rhodecode.model import meta
52 52 from rhodecode.model.user import UserModel
53 53 from rhodecode.model.db import Permission, RhodeCodeSetting, User
54 54
55 55 log = logging.getLogger(__name__)
56 56
57 57
58 58 class PasswordGenerator(object):
59 59 """
60 60 This is a simple class for generating password from different sets of
61 61 characters
62 62 usage::
63 63
64 64 passwd_gen = PasswordGenerator()
65 65 #print 8-letter password containing only big and small letters
66 66 of alphabet
67 67 passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
68 68 """
69 69 ALPHABETS_NUM = r'''1234567890'''
70 70 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
71 71 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
72 72 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
73 73 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
74 74 + ALPHABETS_NUM + ALPHABETS_SPECIAL
75 75 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
76 76 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
77 77 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
78 78 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
79 79
80 80 def __init__(self, passwd=''):
81 81 self.passwd = passwd
82 82
83 83 def gen_password(self, length, type_=None):
84 84 if type_ is None:
85 85 type_ = self.ALPHABETS_FULL
86 86 self.passwd = ''.join([random.choice(type_) for _ in xrange(length)])
87 87 return self.passwd
88 88
89 89
90 90 class RhodeCodeCrypto(object):
91 91
92 92 @classmethod
93 93 def hash_string(cls, str_):
94 94 """
95 95 Cryptographic function used for password hashing based on pybcrypt
96 96 or pycrypto in windows
97 97
98 98 :param password: password to hash
99 99 """
100 100 if __platform__ in PLATFORM_WIN:
101 101 return sha256(str_).hexdigest()
102 102 elif __platform__ in PLATFORM_OTHERS:
103 103 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
104 104 else:
105 105 raise Exception('Unknown or unsupported platform %s' \
106 106 % __platform__)
107 107
108 108 @classmethod
109 109 def hash_check(cls, password, hashed):
110 110 """
111 111 Checks matching password with it's hashed value, runs different
112 112 implementation based on platform it runs on
113 113
114 114 :param password: password
115 115 :param hashed: password in hashed form
116 116 """
117 117
118 118 if __platform__ in PLATFORM_WIN:
119 119 return sha256(password).hexdigest() == hashed
120 120 elif __platform__ in PLATFORM_OTHERS:
121 121 return bcrypt.hashpw(password, hashed) == hashed
122 122 else:
123 123 raise Exception('Unknown or unsupported platform %s' \
124 124 % __platform__)
125 125
126 126
127 127 def get_crypt_password(password):
128 128 return RhodeCodeCrypto.hash_string(password)
129 129
130 130
131 131 def check_password(password, hashed):
132 132 return RhodeCodeCrypto.hash_check(password, hashed)
133 133
134 134
135 135 def generate_api_key(str_, salt=None):
136 136 """
137 137 Generates API KEY from given string
138 138
139 139 :param str_:
140 140 :param salt:
141 141 """
142 142
143 143 if salt is None:
144 144 salt = _RandomNameSequence().next()
145 145
146 146 return hashlib.sha1(str_ + salt).hexdigest()
147 147
148 148
149 149 def authfunc(environ, username, password):
150 150 """
151 151 Dummy authentication wrapper function used in Mercurial and Git for
152 152 access control.
153 153
154 154 :param environ: needed only for using in Basic auth
155 155 """
156 156 return authenticate(username, password)
157 157
158 158
159 159 def authenticate(username, password):
160 160 """
161 161 Authentication function used for access control,
162 162 firstly checks for db authentication then if ldap is enabled for ldap
163 163 authentication, also creates ldap user if not in database
164 164
165 165 :param username: username
166 166 :param password: password
167 167 """
168 168
169 169 user_model = UserModel()
170 170 user = User.get_by_username(username)
171 171
172 172 log.debug('Authenticating user using RhodeCode account')
173 173 if user is not None and not user.ldap_dn:
174 174 if user.active:
175 175 if user.username == 'default' and user.active:
176 176 log.info('user %s authenticated correctly as anonymous user' %
177 177 username)
178 178 return True
179 179
180 180 elif user.username == username and check_password(password,
181 181 user.password):
182 182 log.info('user %s authenticated correctly' % username)
183 183 return True
184 184 else:
185 185 log.warning('user %s tried auth but is disabled' % username)
186 186
187 187 else:
188 188 log.debug('Regular authentication failed')
189 189 user_obj = User.get_by_username(username, case_insensitive=True)
190 190
191 191 if user_obj is not None and not user_obj.ldap_dn:
192 192 log.debug('this user already exists as non ldap')
193 193 return False
194 194
195 195 ldap_settings = RhodeCodeSetting.get_ldap_settings()
196 196 #======================================================================
197 197 # FALLBACK TO LDAP AUTH IF ENABLE
198 198 #======================================================================
199 199 if str2bool(ldap_settings.get('ldap_active')):
200 200 log.debug("Authenticating user using ldap")
201 201 kwargs = {
202 202 'server': ldap_settings.get('ldap_host', ''),
203 203 'base_dn': ldap_settings.get('ldap_base_dn', ''),
204 204 'port': ldap_settings.get('ldap_port'),
205 205 'bind_dn': ldap_settings.get('ldap_dn_user'),
206 206 'bind_pass': ldap_settings.get('ldap_dn_pass'),
207 207 'tls_kind': ldap_settings.get('ldap_tls_kind'),
208 208 'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'),
209 209 'ldap_filter': ldap_settings.get('ldap_filter'),
210 210 'search_scope': ldap_settings.get('ldap_search_scope'),
211 211 'attr_login': ldap_settings.get('ldap_attr_login'),
212 212 'ldap_version': 3,
213 213 }
214 214 log.debug('Checking for ldap authentication')
215 215 try:
216 216 aldap = AuthLdap(**kwargs)
217 217 (user_dn, ldap_attrs) = aldap.authenticate_ldap(username,
218 218 password)
219 219 log.debug('Got ldap DN response %s' % user_dn)
220 220
221 221 get_ldap_attr = lambda k: ldap_attrs.get(ldap_settings\
222 222 .get(k), [''])[0]
223 223
224 224 user_attrs = {
225 225 'name': safe_unicode(get_ldap_attr('ldap_attr_firstname')),
226 226 'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')),
227 227 'email': get_ldap_attr('ldap_attr_email'),
228 228 }
229 229
230 230 # don't store LDAP password since we don't need it. Override
231 231 # with some random generated password
232 232 _password = PasswordGenerator().gen_password(length=8)
233 233 # create this user on the fly if it doesn't exist in rhodecode
234 234 # database
235 235 if user_model.create_ldap(username, _password, user_dn,
236 236 user_attrs):
237 237 log.info('created new ldap user %s' % username)
238 238
239 239 Session.commit()
240 240 return True
241 241 except (LdapUsernameError, LdapPasswordError,):
242 242 pass
243 243 except (Exception,):
244 244 log.error(traceback.format_exc())
245 245 pass
246 246 return False
247 247
248 248
249 249 def login_container_auth(username):
250 250 user = User.get_by_username(username)
251 251 if user is None:
252 252 user_attrs = {
253 253 'name': username,
254 254 'lastname': None,
255 255 'email': None,
256 256 }
257 257 user = UserModel().create_for_container_auth(username, user_attrs)
258 258 if not user:
259 259 return None
260 260 log.info('User %s was created by container authentication' % username)
261 261
262 262 if not user.active:
263 263 return None
264 264
265 265 user.update_lastlogin()
266 266 Session.commit()
267 267
268 268 log.debug('User %s is now logged in by container authentication',
269 269 user.username)
270 270 return user
271 271
272 272
273 273 def get_container_username(environ, config):
274 274 username = None
275 275
276 276 if str2bool(config.get('container_auth_enabled', False)):
277 277 from paste.httpheaders import REMOTE_USER
278 278 username = REMOTE_USER(environ)
279 279
280 280 if not username and str2bool(config.get('proxypass_auth_enabled', False)):
281 281 username = environ.get('HTTP_X_FORWARDED_USER')
282 282
283 283 if username:
284 284 # Removing realm and domain from username
285 285 username = username.partition('@')[0]
286 286 username = username.rpartition('\\')[2]
287 287 log.debug('Received username %s from container' % username)
288 288
289 289 return username
290 290
291 291
292 292 class CookieStoreWrapper(object):
293 293
294 294 def __init__(self, cookie_store):
295 295 self.cookie_store = cookie_store
296 296
297 297 def __repr__(self):
298 298 return 'CookieStore<%s>' % (self.cookie_store)
299 299
300 300 def get(self, key, other=None):
301 301 if isinstance(self.cookie_store, dict):
302 302 return self.cookie_store.get(key, other)
303 303 elif isinstance(self.cookie_store, AuthUser):
304 304 return self.cookie_store.__dict__.get(key, other)
305 305
306 306
307 307 class AuthUser(object):
308 308 """
309 309 A simple object that handles all attributes of user in RhodeCode
310 310
311 311 It does lookup based on API key,given user, or user present in session
312 312 Then it fills all required information for such user. It also checks if
313 313 anonymous access is enabled and if so, it returns default user as logged
314 314 in
315 315 """
316 316
317 317 def __init__(self, user_id=None, api_key=None, username=None):
318 318
319 319 self.user_id = user_id
320 320 self.api_key = None
321 321 self.username = username
322 322
323 323 self.name = ''
324 324 self.lastname = ''
325 325 self.email = ''
326 326 self.is_authenticated = False
327 327 self.admin = False
328 328 self.permissions = {}
329 329 self._api_key = api_key
330 330 self.propagate_data()
331 331 self._instance = None
332 332
333 333 def propagate_data(self):
334 334 user_model = UserModel()
335 335 self.anonymous_user = User.get_by_username('default', cache=True)
336 336 is_user_loaded = False
337 337
338 338 # try go get user by api key
339 339 if self._api_key and self._api_key != self.anonymous_user.api_key:
340 340 log.debug('Auth User lookup by API KEY %s' % self._api_key)
341 341 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
342 342 # lookup by userid
343 343 elif (self.user_id is not None and
344 344 self.user_id != self.anonymous_user.user_id):
345 345 log.debug('Auth User lookup by USER ID %s' % self.user_id)
346 346 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
347 347 # lookup by username
348 348 elif self.username and \
349 349 str2bool(config.get('container_auth_enabled', False)):
350 350
351 351 log.debug('Auth User lookup by USER NAME %s' % self.username)
352 352 dbuser = login_container_auth(self.username)
353 353 if dbuser is not None:
354 354 for k, v in dbuser.get_dict().items():
355 355 setattr(self, k, v)
356 356 self.set_authenticated()
357 357 is_user_loaded = True
358 358 else:
359 359 log.debug('No data in %s that could been used to log in' % self)
360 360
361 361 if not is_user_loaded:
362 362 # if we cannot authenticate user try anonymous
363 363 if self.anonymous_user.active is True:
364 364 user_model.fill_data(self, user_id=self.anonymous_user.user_id)
365 365 # then we set this user is logged in
366 366 self.is_authenticated = True
367 367 else:
368 368 self.user_id = None
369 369 self.username = None
370 370 self.is_authenticated = False
371 371
372 372 if not self.username:
373 373 self.username = 'None'
374 374
375 375 log.debug('Auth User is now %s' % self)
376 376 user_model.fill_perms(self)
377 377
378 378 @property
379 379 def is_admin(self):
380 380 return self.admin
381 381
382 382 def __repr__(self):
383 383 return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
384 384 self.is_authenticated)
385 385
386 386 def set_authenticated(self, authenticated=True):
387 387 if self.user_id != self.anonymous_user.user_id:
388 388 self.is_authenticated = authenticated
389 389
390 390 def get_cookie_store(self):
391 391 return {'username': self.username,
392 392 'user_id': self.user_id,
393 393 'is_authenticated': self.is_authenticated}
394 394
395 395 @classmethod
396 396 def from_cookie_store(cls, cookie_store):
397 397 """
398 398 Creates AuthUser from a cookie store
399 399
400 400 :param cls:
401 401 :param cookie_store:
402 402 """
403 403 user_id = cookie_store.get('user_id')
404 404 username = cookie_store.get('username')
405 405 api_key = cookie_store.get('api_key')
406 406 return AuthUser(user_id, api_key, username)
407 407
408 408
409 409 def set_available_permissions(config):
410 410 """
411 411 This function will propagate pylons globals with all available defined
412 412 permission given in db. We don't want to check each time from db for new
413 413 permissions since adding a new permission also requires application restart
414 414 ie. to decorate new views with the newly created permission
415 415
416 416 :param config: current pylons config instance
417 417
418 418 """
419 419 log.info('getting information about all available permissions')
420 420 try:
421 421 sa = meta.Session
422 422 all_perms = sa.query(Permission).all()
423 423 except Exception:
424 424 pass
425 425 finally:
426 426 meta.Session.remove()
427 427
428 428 config['available_permissions'] = [x.permission_name for x in all_perms]
429 429
430 430
431 431 #==============================================================================
432 432 # CHECK DECORATORS
433 433 #==============================================================================
434 434 class LoginRequired(object):
435 435 """
436 436 Must be logged in to execute this function else
437 437 redirect to login page
438 438
439 439 :param api_access: if enabled this checks only for valid auth token
440 440 and grants access based on valid token
441 441 """
442 442
443 443 def __init__(self, api_access=False):
444 444 self.api_access = api_access
445 445
446 446 def __call__(self, func):
447 447 return decorator(self.__wrapper, func)
448 448
449 449 def __wrapper(self, func, *fargs, **fkwargs):
450 450 cls = fargs[0]
451 451 user = cls.rhodecode_user
452 452
453 453 api_access_ok = False
454 454 if self.api_access:
455 455 log.debug('Checking API KEY access for %s' % cls)
456 456 if user.api_key == request.GET.get('api_key'):
457 457 api_access_ok = True
458 458 else:
459 459 log.debug("API KEY token not valid")
460 460 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
461 461 log.debug('Checking if %s is authenticated @ %s' % (user.username, loc))
462 462 if user.is_authenticated or api_access_ok:
463 log.info('user %s is authenticated and granted access to %s' % (
464 user.username, loc)
463 reason = 'RegularAuth' if user.is_authenticated else 'APIAuth'
464 log.info('user %s is authenticated and granted access to %s '
465 'using %s' % (user.username, loc, reason)
465 466 )
466 467 return func(*fargs, **fkwargs)
467 468 else:
468 469 log.warn('user %s NOT authenticated on func: %s' % (
469 470 user, loc)
470 471 )
471 472 p = url.current()
472 473
473 474 log.debug('redirecting to login page with %s' % p)
474 475 return redirect(url('login_home', came_from=p))
475 476
476 477
477 478 class NotAnonymous(object):
478 479 """
479 480 Must be logged in to execute this function else
480 481 redirect to login page"""
481 482
482 483 def __call__(self, func):
483 484 return decorator(self.__wrapper, func)
484 485
485 486 def __wrapper(self, func, *fargs, **fkwargs):
486 487 cls = fargs[0]
487 488 self.user = cls.rhodecode_user
488 489
489 490 log.debug('Checking if user is not anonymous @%s' % cls)
490 491
491 492 anonymous = self.user.username == 'default'
492 493
493 494 if anonymous:
494 495 p = url.current()
495 496
496 497 import rhodecode.lib.helpers as h
497 498 h.flash(_('You need to be a registered user to '
498 499 'perform this action'),
499 500 category='warning')
500 501 return redirect(url('login_home', came_from=p))
501 502 else:
502 503 return func(*fargs, **fkwargs)
503 504
504 505
505 506 class PermsDecorator(object):
506 507 """Base class for controller decorators"""
507 508
508 509 def __init__(self, *required_perms):
509 510 available_perms = config['available_permissions']
510 511 for perm in required_perms:
511 512 if perm not in available_perms:
512 513 raise Exception("'%s' permission is not defined" % perm)
513 514 self.required_perms = set(required_perms)
514 515 self.user_perms = None
515 516
516 517 def __call__(self, func):
517 518 return decorator(self.__wrapper, func)
518 519
519 520 def __wrapper(self, func, *fargs, **fkwargs):
520 521 cls = fargs[0]
521 522 self.user = cls.rhodecode_user
522 523 self.user_perms = self.user.permissions
523 524 log.debug('checking %s permissions %s for %s %s',
524 525 self.__class__.__name__, self.required_perms, cls, self.user)
525 526
526 527 if self.check_permissions():
527 528 log.debug('Permission granted for %s %s' % (cls, self.user))
528 529 return func(*fargs, **fkwargs)
529 530
530 531 else:
531 532 log.debug('Permission denied for %s %s' % (cls, self.user))
532 533 anonymous = self.user.username == 'default'
533 534
534 535 if anonymous:
535 536 p = url.current()
536 537
537 538 import rhodecode.lib.helpers as h
538 539 h.flash(_('You need to be a signed in to '
539 540 'view this page'),
540 541 category='warning')
541 542 return redirect(url('login_home', came_from=p))
542 543
543 544 else:
544 545 # redirect with forbidden ret code
545 546 return abort(403)
546 547
547 548 def check_permissions(self):
548 549 """Dummy function for overriding"""
549 550 raise Exception('You have to write this function in child class')
550 551
551 552
552 553 class HasPermissionAllDecorator(PermsDecorator):
553 554 """
554 555 Checks for access permission for all given predicates. All of them
555 556 have to be meet in order to fulfill the request
556 557 """
557 558
558 559 def check_permissions(self):
559 560 if self.required_perms.issubset(self.user_perms.get('global')):
560 561 return True
561 562 return False
562 563
563 564
564 565 class HasPermissionAnyDecorator(PermsDecorator):
565 566 """
566 567 Checks for access permission for any of given predicates. In order to
567 568 fulfill the request any of predicates must be meet
568 569 """
569 570
570 571 def check_permissions(self):
571 572 if self.required_perms.intersection(self.user_perms.get('global')):
572 573 return True
573 574 return False
574 575
575 576
576 577 class HasRepoPermissionAllDecorator(PermsDecorator):
577 578 """
578 579 Checks for access permission for all given predicates for specific
579 580 repository. All of them have to be meet in order to fulfill the request
580 581 """
581 582
582 583 def check_permissions(self):
583 584 repo_name = get_repo_slug(request)
584 585 try:
585 586 user_perms = set([self.user_perms['repositories'][repo_name]])
586 587 except KeyError:
587 588 return False
588 589 if self.required_perms.issubset(user_perms):
589 590 return True
590 591 return False
591 592
592 593
593 594 class HasRepoPermissionAnyDecorator(PermsDecorator):
594 595 """
595 596 Checks for access permission for any of given predicates for specific
596 597 repository. In order to fulfill the request any of predicates must be meet
597 598 """
598 599
599 600 def check_permissions(self):
600 601 repo_name = get_repo_slug(request)
601 602
602 603 try:
603 604 user_perms = set([self.user_perms['repositories'][repo_name]])
604 605 except KeyError:
605 606 return False
606 607
607 608 if self.required_perms.intersection(user_perms):
608 609 return True
609 610 return False
610 611
611 612
612 613 class HasReposGroupPermissionAllDecorator(PermsDecorator):
613 614 """
614 615 Checks for access permission for all given predicates for specific
615 616 repository. All of them have to be meet in order to fulfill the request
616 617 """
617 618
618 619 def check_permissions(self):
619 620 group_name = get_repos_group_slug(request)
620 621 try:
621 622 user_perms = set([self.user_perms['repositories_groups'][group_name]])
622 623 except KeyError:
623 624 return False
624 625 if self.required_perms.issubset(user_perms):
625 626 return True
626 627 return False
627 628
628 629
629 630 class HasReposGroupPermissionAnyDecorator(PermsDecorator):
630 631 """
631 632 Checks for access permission for any of given predicates for specific
632 633 repository. In order to fulfill the request any of predicates must be meet
633 634 """
634 635
635 636 def check_permissions(self):
636 637 group_name = get_repos_group_slug(request)
637 638
638 639 try:
639 640 user_perms = set([self.user_perms['repositories_groups'][group_name]])
640 641 except KeyError:
641 642 return False
642 643 if self.required_perms.intersection(user_perms):
643 644 return True
644 645 return False
645 646
646 647
647 648 #==============================================================================
648 649 # CHECK FUNCTIONS
649 650 #==============================================================================
650 651 class PermsFunction(object):
651 652 """Base function for other check functions"""
652 653
653 654 def __init__(self, *perms):
654 655 available_perms = config['available_permissions']
655 656
656 657 for perm in perms:
657 658 if perm not in available_perms:
658 659 raise Exception("'%s' permission is not defined" % perm)
659 660 self.required_perms = set(perms)
660 661 self.user_perms = None
661 662 self.repo_name = None
662 663 self.group_name = None
663 664
664 665 def __call__(self, check_Location=''):
665 666 user = request.user
666 667 cls_name = self.__class__.__name__
667 668 check_scope = {
668 669 'HasPermissionAll': '',
669 670 'HasPermissionAny': '',
670 671 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
671 672 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
672 673 'HasReposGroupPermissionAll': 'group:%s' % self.group_name,
673 674 'HasReposGroupPermissionAny': 'group:%s' % self.group_name,
674 675 }.get(cls_name, '?')
675 676 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
676 677 self.required_perms, user, check_scope,
677 678 check_Location or 'unspecified location')
678 679 if not user:
679 680 log.debug('Empty request user')
680 681 return False
681 682 self.user_perms = user.permissions
682 683 if self.check_permissions():
683 684 log.debug('Permission granted for user: %s @ %s', user,
684 685 check_Location or 'unspecified location')
685 686 return True
686 687
687 688 else:
688 689 log.debug('Permission denied for user: %s @ %s', user,
689 690 check_Location or 'unspecified location')
690 691 return False
691 692
692 693 def check_permissions(self):
693 694 """Dummy function for overriding"""
694 695 raise Exception('You have to write this function in child class')
695 696
696 697
697 698 class HasPermissionAll(PermsFunction):
698 699 def check_permissions(self):
699 700 if self.required_perms.issubset(self.user_perms.get('global')):
700 701 return True
701 702 return False
702 703
703 704
704 705 class HasPermissionAny(PermsFunction):
705 706 def check_permissions(self):
706 707 if self.required_perms.intersection(self.user_perms.get('global')):
707 708 return True
708 709 return False
709 710
710 711
711 712 class HasRepoPermissionAll(PermsFunction):
712 713 def __call__(self, repo_name=None, check_Location=''):
713 714 self.repo_name = repo_name
714 715 return super(HasRepoPermissionAll, self).__call__(check_Location)
715 716
716 717 def check_permissions(self):
717 718 if not self.repo_name:
718 719 self.repo_name = get_repo_slug(request)
719 720
720 721 try:
721 722 self._user_perms = set(
722 723 [self.user_perms['repositories'][self.repo_name]]
723 724 )
724 725 except KeyError:
725 726 return False
726 727 if self.required_perms.issubset(self._user_perms):
727 728 return True
728 729 return False
729 730
730 731
731 732 class HasRepoPermissionAny(PermsFunction):
732 733 def __call__(self, repo_name=None, check_Location=''):
733 734 self.repo_name = repo_name
734 735 return super(HasRepoPermissionAny, self).__call__(check_Location)
735 736
736 737 def check_permissions(self):
737 738 if not self.repo_name:
738 739 self.repo_name = get_repo_slug(request)
739 740
740 741 try:
741 742 self._user_perms = set(
742 743 [self.user_perms['repositories'][self.repo_name]]
743 744 )
744 745 except KeyError:
745 746 return False
746 747 if self.required_perms.intersection(self._user_perms):
747 748 return True
748 749 return False
749 750
750 751
751 752 class HasReposGroupPermissionAny(PermsFunction):
752 753 def __call__(self, group_name=None, check_Location=''):
753 754 self.group_name = group_name
754 755 return super(HasReposGroupPermissionAny, self).__call__(check_Location)
755 756
756 757 def check_permissions(self):
757 758 try:
758 759 self._user_perms = set(
759 760 [self.user_perms['repositories_groups'][self.group_name]]
760 761 )
761 762 except KeyError:
762 763 return False
763 764 if self.required_perms.intersection(self._user_perms):
764 765 return True
765 766 return False
766 767
767 768
768 769 class HasReposGroupPermissionAll(PermsFunction):
769 770 def __call__(self, group_name=None, check_Location=''):
770 771 self.group_name = group_name
771 772 return super(HasReposGroupPermissionAny, self).__call__(check_Location)
772 773
773 774 def check_permissions(self):
774 775 try:
775 776 self._user_perms = set(
776 777 [self.user_perms['repositories_groups'][self.group_name]]
777 778 )
778 779 except KeyError:
779 780 return False
780 781 if self.required_perms.issubset(self._user_perms):
781 782 return True
782 783 return False
783 784
784 785
785 786 #==============================================================================
786 787 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
787 788 #==============================================================================
788 789 class HasPermissionAnyMiddleware(object):
789 790 def __init__(self, *perms):
790 791 self.required_perms = set(perms)
791 792
792 793 def __call__(self, user, repo_name):
793 794 # repo_name MUST be unicode, since we handle keys in permission
794 795 # dict by unicode
795 796 repo_name = safe_unicode(repo_name)
796 797 usr = AuthUser(user.user_id)
797 798 try:
798 799 self.user_perms = set([usr.permissions['repositories'][repo_name]])
799 800 except Exception:
800 801 log.error('Exception while accessing permissions %s' %
801 802 traceback.format_exc())
802 803 self.user_perms = set()
803 804 self.username = user.username
804 805 self.repo_name = repo_name
805 806 return self.check_permissions()
806 807
807 808 def check_permissions(self):
808 809 log.debug('checking mercurial protocol '
809 810 'permissions %s for user:%s repository:%s', self.user_perms,
810 811 self.username, self.repo_name)
811 812 if self.required_perms.intersection(self.user_perms):
812 813 log.debug('permission granted for user:%s on repo:%s' % (
813 814 self.username, self.repo_name
814 815 )
815 816 )
816 817 return True
817 818 log.debug('permission denied for user:%s on repo:%s' % (
818 819 self.username, self.repo_name
819 820 )
820 821 )
821 822 return False
General Comments 0
You need to be logged in to leave comments. Login now