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