##// END OF EJS Templates
permissions: show overridden permissions in permission summary page
dan -
r100:5b55789f default
parent child Browse files
Show More
@@ -1,1828 +1,1898 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 authentication and permission libraries
22 authentication and permission libraries
23 """
23 """
24
24
25 import inspect
25 import inspect
26 import collections
26 import collections
27 import fnmatch
27 import fnmatch
28 import hashlib
28 import hashlib
29 import itertools
29 import itertools
30 import logging
30 import logging
31 import os
31 import os
32 import random
32 import random
33 import time
33 import time
34 import traceback
34 import traceback
35 from functools import wraps
35 from functools import wraps
36
36
37 import ipaddress
37 import ipaddress
38 from pylons import url, request
38 from pylons import url, request
39 from pylons.controllers.util import abort, redirect
39 from pylons.controllers.util import abort, redirect
40 from pylons.i18n.translation import _
40 from pylons.i18n.translation import _
41 from sqlalchemy import or_
41 from sqlalchemy import or_
42 from sqlalchemy.orm.exc import ObjectDeletedError
42 from sqlalchemy.orm.exc import ObjectDeletedError
43 from sqlalchemy.orm import joinedload
43 from sqlalchemy.orm import joinedload
44 from zope.cachedescriptors.property import Lazy as LazyProperty
44 from zope.cachedescriptors.property import Lazy as LazyProperty
45
45
46 import rhodecode
46 import rhodecode
47 from rhodecode.model import meta
47 from rhodecode.model import meta
48 from rhodecode.model.meta import Session
48 from rhodecode.model.meta import Session
49 from rhodecode.model.user import UserModel
49 from rhodecode.model.user import UserModel
50 from rhodecode.model.db import (
50 from rhodecode.model.db import (
51 User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember,
51 User, Repository, Permission, UserToPerm, UserGroupToPerm, UserGroupMember,
52 UserIpMap, UserApiKeys)
52 UserIpMap, UserApiKeys)
53 from rhodecode.lib import caches
53 from rhodecode.lib import caches
54 from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5
54 from rhodecode.lib.utils2 import safe_unicode, aslist, safe_str, md5
55 from rhodecode.lib.utils import (
55 from rhodecode.lib.utils import (
56 get_repo_slug, get_repo_group_slug, get_user_group_slug)
56 get_repo_slug, get_repo_group_slug, get_user_group_slug)
57 from rhodecode.lib.caching_query import FromCache
57 from rhodecode.lib.caching_query import FromCache
58
58
59
59
60 if rhodecode.is_unix:
60 if rhodecode.is_unix:
61 import bcrypt
61 import bcrypt
62
62
63 log = logging.getLogger(__name__)
63 log = logging.getLogger(__name__)
64
64
65 csrf_token_key = "csrf_token"
65 csrf_token_key = "csrf_token"
66
66
67
67
68 class PasswordGenerator(object):
68 class PasswordGenerator(object):
69 """
69 """
70 This is a simple class for generating password from different sets of
70 This is a simple class for generating password from different sets of
71 characters
71 characters
72 usage::
72 usage::
73
73
74 passwd_gen = PasswordGenerator()
74 passwd_gen = PasswordGenerator()
75 #print 8-letter password containing only big and small letters
75 #print 8-letter password containing only big and small letters
76 of alphabet
76 of alphabet
77 passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
77 passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
78 """
78 """
79 ALPHABETS_NUM = r'''1234567890'''
79 ALPHABETS_NUM = r'''1234567890'''
80 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
80 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
81 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
81 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
82 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
82 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
83 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
83 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
84 + ALPHABETS_NUM + ALPHABETS_SPECIAL
84 + ALPHABETS_NUM + ALPHABETS_SPECIAL
85 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
85 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
86 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
86 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
87 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
87 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
88 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
88 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
89
89
90 def __init__(self, passwd=''):
90 def __init__(self, passwd=''):
91 self.passwd = passwd
91 self.passwd = passwd
92
92
93 def gen_password(self, length, type_=None):
93 def gen_password(self, length, type_=None):
94 if type_ is None:
94 if type_ is None:
95 type_ = self.ALPHABETS_FULL
95 type_ = self.ALPHABETS_FULL
96 self.passwd = ''.join([random.choice(type_) for _ in xrange(length)])
96 self.passwd = ''.join([random.choice(type_) for _ in xrange(length)])
97 return self.passwd
97 return self.passwd
98
98
99
99
100 class _RhodeCodeCryptoBase(object):
100 class _RhodeCodeCryptoBase(object):
101
101
102 def hash_create(self, str_):
102 def hash_create(self, str_):
103 """
103 """
104 hash the string using
104 hash the string using
105
105
106 :param str_: password to hash
106 :param str_: password to hash
107 """
107 """
108 raise NotImplementedError
108 raise NotImplementedError
109
109
110 def hash_check_with_upgrade(self, password, hashed):
110 def hash_check_with_upgrade(self, password, hashed):
111 """
111 """
112 Returns tuple in which first element is boolean that states that
112 Returns tuple in which first element is boolean that states that
113 given password matches it's hashed version, and the second is new hash
113 given password matches it's hashed version, and the second is new hash
114 of the password, in case this password should be migrated to new
114 of the password, in case this password should be migrated to new
115 cipher.
115 cipher.
116 """
116 """
117 checked_hash = self.hash_check(password, hashed)
117 checked_hash = self.hash_check(password, hashed)
118 return checked_hash, None
118 return checked_hash, None
119
119
120 def hash_check(self, password, hashed):
120 def hash_check(self, password, hashed):
121 """
121 """
122 Checks matching password with it's hashed value.
122 Checks matching password with it's hashed value.
123
123
124 :param password: password
124 :param password: password
125 :param hashed: password in hashed form
125 :param hashed: password in hashed form
126 """
126 """
127 raise NotImplementedError
127 raise NotImplementedError
128
128
129 def _assert_bytes(self, value):
129 def _assert_bytes(self, value):
130 """
130 """
131 Passing in an `unicode` object can lead to hard to detect issues
131 Passing in an `unicode` object can lead to hard to detect issues
132 if passwords contain non-ascii characters. Doing a type check
132 if passwords contain non-ascii characters. Doing a type check
133 during runtime, so that such mistakes are detected early on.
133 during runtime, so that such mistakes are detected early on.
134 """
134 """
135 if not isinstance(value, str):
135 if not isinstance(value, str):
136 raise TypeError(
136 raise TypeError(
137 "Bytestring required as input, got %r." % (value, ))
137 "Bytestring required as input, got %r." % (value, ))
138
138
139
139
140 class _RhodeCodeCryptoBCrypt(_RhodeCodeCryptoBase):
140 class _RhodeCodeCryptoBCrypt(_RhodeCodeCryptoBase):
141
141
142 def hash_create(self, str_):
142 def hash_create(self, str_):
143 self._assert_bytes(str_)
143 self._assert_bytes(str_)
144 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
144 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
145
145
146 def hash_check_with_upgrade(self, password, hashed):
146 def hash_check_with_upgrade(self, password, hashed):
147 """
147 """
148 Returns tuple in which first element is boolean that states that
148 Returns tuple in which first element is boolean that states that
149 given password matches it's hashed version, and the second is new hash
149 given password matches it's hashed version, and the second is new hash
150 of the password, in case this password should be migrated to new
150 of the password, in case this password should be migrated to new
151 cipher.
151 cipher.
152
152
153 This implements special upgrade logic which works like that:
153 This implements special upgrade logic which works like that:
154 - check if the given password == bcrypted hash, if yes then we
154 - check if the given password == bcrypted hash, if yes then we
155 properly used password and it was already in bcrypt. Proceed
155 properly used password and it was already in bcrypt. Proceed
156 without any changes
156 without any changes
157 - if bcrypt hash check is not working try with sha256. If hash compare
157 - if bcrypt hash check is not working try with sha256. If hash compare
158 is ok, it means we using correct but old hashed password. indicate
158 is ok, it means we using correct but old hashed password. indicate
159 hash change and proceed
159 hash change and proceed
160 """
160 """
161
161
162 new_hash = None
162 new_hash = None
163
163
164 # regular pw check
164 # regular pw check
165 password_match_bcrypt = self.hash_check(password, hashed)
165 password_match_bcrypt = self.hash_check(password, hashed)
166
166
167 # now we want to know if the password was maybe from sha256
167 # now we want to know if the password was maybe from sha256
168 # basically calling _RhodeCodeCryptoSha256().hash_check()
168 # basically calling _RhodeCodeCryptoSha256().hash_check()
169 if not password_match_bcrypt:
169 if not password_match_bcrypt:
170 if _RhodeCodeCryptoSha256().hash_check(password, hashed):
170 if _RhodeCodeCryptoSha256().hash_check(password, hashed):
171 new_hash = self.hash_create(password) # make new bcrypt hash
171 new_hash = self.hash_create(password) # make new bcrypt hash
172 password_match_bcrypt = True
172 password_match_bcrypt = True
173
173
174 return password_match_bcrypt, new_hash
174 return password_match_bcrypt, new_hash
175
175
176 def hash_check(self, password, hashed):
176 def hash_check(self, password, hashed):
177 """
177 """
178 Checks matching password with it's hashed value.
178 Checks matching password with it's hashed value.
179
179
180 :param password: password
180 :param password: password
181 :param hashed: password in hashed form
181 :param hashed: password in hashed form
182 """
182 """
183 self._assert_bytes(password)
183 self._assert_bytes(password)
184 try:
184 try:
185 return bcrypt.hashpw(password, hashed) == hashed
185 return bcrypt.hashpw(password, hashed) == hashed
186 except ValueError as e:
186 except ValueError as e:
187 # we're having a invalid salt here probably, we should not crash
187 # we're having a invalid salt here probably, we should not crash
188 # just return with False as it would be a wrong password.
188 # just return with False as it would be a wrong password.
189 log.debug('Failed to check password hash using bcrypt %s',
189 log.debug('Failed to check password hash using bcrypt %s',
190 safe_str(e))
190 safe_str(e))
191
191
192 return False
192 return False
193
193
194
194
195 class _RhodeCodeCryptoSha256(_RhodeCodeCryptoBase):
195 class _RhodeCodeCryptoSha256(_RhodeCodeCryptoBase):
196
196
197 def hash_create(self, str_):
197 def hash_create(self, str_):
198 self._assert_bytes(str_)
198 self._assert_bytes(str_)
199 return hashlib.sha256(str_).hexdigest()
199 return hashlib.sha256(str_).hexdigest()
200
200
201 def hash_check(self, password, hashed):
201 def hash_check(self, password, hashed):
202 """
202 """
203 Checks matching password with it's hashed value.
203 Checks matching password with it's hashed value.
204
204
205 :param password: password
205 :param password: password
206 :param hashed: password in hashed form
206 :param hashed: password in hashed form
207 """
207 """
208 self._assert_bytes(password)
208 self._assert_bytes(password)
209 return hashlib.sha256(password).hexdigest() == hashed
209 return hashlib.sha256(password).hexdigest() == hashed
210
210
211
211
212 class _RhodeCodeCryptoMd5(_RhodeCodeCryptoBase):
212 class _RhodeCodeCryptoMd5(_RhodeCodeCryptoBase):
213
213
214 def hash_create(self, str_):
214 def hash_create(self, str_):
215 self._assert_bytes(str_)
215 self._assert_bytes(str_)
216 return hashlib.md5(str_).hexdigest()
216 return hashlib.md5(str_).hexdigest()
217
217
218 def hash_check(self, password, hashed):
218 def hash_check(self, password, hashed):
219 """
219 """
220 Checks matching password with it's hashed value.
220 Checks matching password with it's hashed value.
221
221
222 :param password: password
222 :param password: password
223 :param hashed: password in hashed form
223 :param hashed: password in hashed form
224 """
224 """
225 self._assert_bytes(password)
225 self._assert_bytes(password)
226 return hashlib.md5(password).hexdigest() == hashed
226 return hashlib.md5(password).hexdigest() == hashed
227
227
228
228
229 def crypto_backend():
229 def crypto_backend():
230 """
230 """
231 Return the matching crypto backend.
231 Return the matching crypto backend.
232
232
233 Selection is based on if we run tests or not, we pick md5 backend to run
233 Selection is based on if we run tests or not, we pick md5 backend to run
234 tests faster since BCRYPT is expensive to calculate
234 tests faster since BCRYPT is expensive to calculate
235 """
235 """
236 if rhodecode.is_test:
236 if rhodecode.is_test:
237 RhodeCodeCrypto = _RhodeCodeCryptoMd5()
237 RhodeCodeCrypto = _RhodeCodeCryptoMd5()
238 else:
238 else:
239 RhodeCodeCrypto = _RhodeCodeCryptoBCrypt()
239 RhodeCodeCrypto = _RhodeCodeCryptoBCrypt()
240
240
241 return RhodeCodeCrypto
241 return RhodeCodeCrypto
242
242
243
243
244 def get_crypt_password(password):
244 def get_crypt_password(password):
245 """
245 """
246 Create the hash of `password` with the active crypto backend.
246 Create the hash of `password` with the active crypto backend.
247
247
248 :param password: The cleartext password.
248 :param password: The cleartext password.
249 :type password: unicode
249 :type password: unicode
250 """
250 """
251 password = safe_str(password)
251 password = safe_str(password)
252 return crypto_backend().hash_create(password)
252 return crypto_backend().hash_create(password)
253
253
254
254
255 def check_password(password, hashed):
255 def check_password(password, hashed):
256 """
256 """
257 Check if the value in `password` matches the hash in `hashed`.
257 Check if the value in `password` matches the hash in `hashed`.
258
258
259 :param password: The cleartext password.
259 :param password: The cleartext password.
260 :type password: unicode
260 :type password: unicode
261
261
262 :param hashed: The expected hashed version of the password.
262 :param hashed: The expected hashed version of the password.
263 :type hashed: The hash has to be passed in in text representation.
263 :type hashed: The hash has to be passed in in text representation.
264 """
264 """
265 password = safe_str(password)
265 password = safe_str(password)
266 return crypto_backend().hash_check(password, hashed)
266 return crypto_backend().hash_check(password, hashed)
267
267
268
268
269 def generate_auth_token(data, salt=None):
269 def generate_auth_token(data, salt=None):
270 """
270 """
271 Generates API KEY from given string
271 Generates API KEY from given string
272 """
272 """
273
273
274 if salt is None:
274 if salt is None:
275 salt = os.urandom(16)
275 salt = os.urandom(16)
276 return hashlib.sha1(safe_str(data) + salt).hexdigest()
276 return hashlib.sha1(safe_str(data) + salt).hexdigest()
277
277
278
278
279 class CookieStoreWrapper(object):
279 class CookieStoreWrapper(object):
280
280
281 def __init__(self, cookie_store):
281 def __init__(self, cookie_store):
282 self.cookie_store = cookie_store
282 self.cookie_store = cookie_store
283
283
284 def __repr__(self):
284 def __repr__(self):
285 return 'CookieStore<%s>' % (self.cookie_store)
285 return 'CookieStore<%s>' % (self.cookie_store)
286
286
287 def get(self, key, other=None):
287 def get(self, key, other=None):
288 if isinstance(self.cookie_store, dict):
288 if isinstance(self.cookie_store, dict):
289 return self.cookie_store.get(key, other)
289 return self.cookie_store.get(key, other)
290 elif isinstance(self.cookie_store, AuthUser):
290 elif isinstance(self.cookie_store, AuthUser):
291 return self.cookie_store.__dict__.get(key, other)
291 return self.cookie_store.__dict__.get(key, other)
292
292
293
293
294 def _cached_perms_data(user_id, scope, user_is_admin,
294 def _cached_perms_data(user_id, scope, user_is_admin,
295 user_inherit_default_permissions, explicit, algo):
295 user_inherit_default_permissions, explicit, algo):
296
296
297 permissions = PermissionCalculator(
297 permissions = PermissionCalculator(
298 user_id, scope, user_is_admin, user_inherit_default_permissions,
298 user_id, scope, user_is_admin, user_inherit_default_permissions,
299 explicit, algo)
299 explicit, algo)
300 return permissions.calculate()
300 return permissions.calculate()
301
301
302 class PermOrigin:
303 ADMIN = 'superadmin'
304
305 REPO_USER = 'user:%s'
306 REPO_USERGROUP = 'usergroup:%s'
307 REPO_OWNER = 'repo.owner'
308 REPO_DEFAULT = 'repo.default'
309 REPO_PRIVATE = 'repo.private'
310
311 REPOGROUP_USER = 'user:%s'
312 REPOGROUP_USERGROUP = 'usergroup:%s'
313 REPOGROUP_OWNER = 'group.owner'
314 REPOGROUP_DEFAULT = 'group.default'
315
316 USERGROUP_USER = 'user:%s'
317 USERGROUP_USERGROUP = 'usergroup:%s'
318 USERGROUP_OWNER = 'usergroup.owner'
319 USERGROUP_DEFAULT = 'usergroup.default'
320
321
322 class PermOriginDict(dict):
323 """
324 A special dict used for tracking permissions along with their origins.
325
326 `__setitem__` has been overridden to expect a tuple(perm, origin)
327 `__getitem__` will return only the perm
328 `.perm_origin_stack` will return the stack of (perm, origin) set per key
329
330 >>> perms = PermOriginDict()
331 >>> perms['resource'] = 'read', 'default'
332 >>> perms['resource']
333 'read'
334 >>> perms['resource'] = 'write', 'admin'
335 >>> perms['resource']
336 'write'
337 >>> perms.perm_origin_stack
338 {'resource': [('read', 'default'), ('write', 'admin')]}
339 """
340
341
342 def __init__(self, *args, **kw):
343 dict.__init__(self, *args, **kw)
344 self.perm_origin_stack = {}
345
346 def __setitem__(self, key, (perm, origin)):
347 self.perm_origin_stack.setdefault(key, []).append((perm, origin))
348 dict.__setitem__(self, key, perm)
349
302
350
303 class PermissionCalculator(object):
351 class PermissionCalculator(object):
304
352
305 def __init__(
353 def __init__(
306 self, user_id, scope, user_is_admin,
354 self, user_id, scope, user_is_admin,
307 user_inherit_default_permissions, explicit, algo):
355 user_inherit_default_permissions, explicit, algo):
308 self.user_id = user_id
356 self.user_id = user_id
309 self.user_is_admin = user_is_admin
357 self.user_is_admin = user_is_admin
310 self.inherit_default_permissions = user_inherit_default_permissions
358 self.inherit_default_permissions = user_inherit_default_permissions
311 self.explicit = explicit
359 self.explicit = explicit
312 self.algo = algo
360 self.algo = algo
313
361
314 scope = scope or {}
362 scope = scope or {}
315 self.scope_repo_id = scope.get('repo_id')
363 self.scope_repo_id = scope.get('repo_id')
316 self.scope_repo_group_id = scope.get('repo_group_id')
364 self.scope_repo_group_id = scope.get('repo_group_id')
317 self.scope_user_group_id = scope.get('user_group_id')
365 self.scope_user_group_id = scope.get('user_group_id')
318
366
319 self.default_user_id = User.get_default_user(cache=True).user_id
367 self.default_user_id = User.get_default_user(cache=True).user_id
320
368
321 self.permissions_repositories = {}
369 self.permissions_repositories = PermOriginDict()
322 self.permissions_repository_groups = {}
370 self.permissions_repository_groups = PermOriginDict()
323 self.permissions_user_groups = {}
371 self.permissions_user_groups = PermOriginDict()
324 self.permissions_global = set()
372 self.permissions_global = set()
325
373
326 self.default_repo_perms = Permission.get_default_repo_perms(
374 self.default_repo_perms = Permission.get_default_repo_perms(
327 self.default_user_id, self.scope_repo_id)
375 self.default_user_id, self.scope_repo_id)
328 self.default_repo_groups_perms = Permission.get_default_group_perms(
376 self.default_repo_groups_perms = Permission.get_default_group_perms(
329 self.default_user_id, self.scope_repo_group_id)
377 self.default_user_id, self.scope_repo_group_id)
330 self.default_user_group_perms = \
378 self.default_user_group_perms = \
331 Permission.get_default_user_group_perms(
379 Permission.get_default_user_group_perms(
332 self.default_user_id, self.scope_user_group_id)
380 self.default_user_id, self.scope_user_group_id)
333
381
334 def calculate(self):
382 def calculate(self):
335 if self.user_is_admin:
383 if self.user_is_admin:
336 return self._admin_permissions()
384 return self._admin_permissions()
337
385
338 self._calculate_global_default_permissions()
386 self._calculate_global_default_permissions()
339 self._calculate_global_permissions()
387 self._calculate_global_permissions()
340 self._calculate_default_permissions()
388 self._calculate_default_permissions()
341 self._calculate_repository_permissions()
389 self._calculate_repository_permissions()
342 self._calculate_repository_group_permissions()
390 self._calculate_repository_group_permissions()
343 self._calculate_user_group_permissions()
391 self._calculate_user_group_permissions()
344 return self._permission_structure()
392 return self._permission_structure()
345
393
346 def _admin_permissions(self):
394 def _admin_permissions(self):
347 """
395 """
348 admin user have all default rights for repositories
396 admin user have all default rights for repositories
349 and groups set to admin
397 and groups set to admin
350 """
398 """
351 self.permissions_global.add('hg.admin')
399 self.permissions_global.add('hg.admin')
352 self.permissions_global.add('hg.create.write_on_repogroup.true')
400 self.permissions_global.add('hg.create.write_on_repogroup.true')
353
401
354 # repositories
402 # repositories
355 for perm in self.default_repo_perms:
403 for perm in self.default_repo_perms:
356 r_k = perm.UserRepoToPerm.repository.repo_name
404 r_k = perm.UserRepoToPerm.repository.repo_name
357 p = 'repository.admin'
405 p = 'repository.admin'
358 self.permissions_repositories[r_k] = p
406 self.permissions_repositories[r_k] = p, PermOrigin.ADMIN
359
407
360 # repository groups
408 # repository groups
361 for perm in self.default_repo_groups_perms:
409 for perm in self.default_repo_groups_perms:
362 rg_k = perm.UserRepoGroupToPerm.group.group_name
410 rg_k = perm.UserRepoGroupToPerm.group.group_name
363 p = 'group.admin'
411 p = 'group.admin'
364 self.permissions_repository_groups[rg_k] = p
412 self.permissions_repository_groups[rg_k] = p, PermOrigin.ADMIN
365
413
366 # user groups
414 # user groups
367 for perm in self.default_user_group_perms:
415 for perm in self.default_user_group_perms:
368 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
416 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
369 p = 'usergroup.admin'
417 p = 'usergroup.admin'
370 self.permissions_user_groups[u_k] = p
418 self.permissions_user_groups[u_k] = p, PermOrigin.ADMIN
371
419
372 return self._permission_structure()
420 return self._permission_structure()
373
421
374 def _calculate_global_default_permissions(self):
422 def _calculate_global_default_permissions(self):
375 """
423 """
376 global permissions taken from the default user
424 global permissions taken from the default user
377 """
425 """
378 default_global_perms = UserToPerm.query()\
426 default_global_perms = UserToPerm.query()\
379 .filter(UserToPerm.user_id == self.default_user_id)\
427 .filter(UserToPerm.user_id == self.default_user_id)\
380 .options(joinedload(UserToPerm.permission))
428 .options(joinedload(UserToPerm.permission))
381
429
382 for perm in default_global_perms:
430 for perm in default_global_perms:
383 self.permissions_global.add(perm.permission.permission_name)
431 self.permissions_global.add(perm.permission.permission_name)
384
432
385 def _calculate_global_permissions(self):
433 def _calculate_global_permissions(self):
386 """
434 """
387 Set global system permissions with user permissions or permissions
435 Set global system permissions with user permissions or permissions
388 taken from the user groups of the current user.
436 taken from the user groups of the current user.
389
437
390 The permissions include repo creating, repo group creating, forking
438 The permissions include repo creating, repo group creating, forking
391 etc.
439 etc.
392 """
440 """
393
441
394 # now we read the defined permissions and overwrite what we have set
442 # now we read the defined permissions and overwrite what we have set
395 # before those can be configured from groups or users explicitly.
443 # before those can be configured from groups or users explicitly.
396
444
397 # TODO: johbo: This seems to be out of sync, find out the reason
445 # TODO: johbo: This seems to be out of sync, find out the reason
398 # for the comment below and update it.
446 # for the comment below and update it.
399
447
400 # In case we want to extend this list we should be always in sync with
448 # In case we want to extend this list we should be always in sync with
401 # User.DEFAULT_USER_PERMISSIONS definitions
449 # User.DEFAULT_USER_PERMISSIONS definitions
402 _configurable = frozenset([
450 _configurable = frozenset([
403 'hg.fork.none', 'hg.fork.repository',
451 'hg.fork.none', 'hg.fork.repository',
404 'hg.create.none', 'hg.create.repository',
452 'hg.create.none', 'hg.create.repository',
405 'hg.usergroup.create.false', 'hg.usergroup.create.true',
453 'hg.usergroup.create.false', 'hg.usergroup.create.true',
406 'hg.repogroup.create.false', 'hg.repogroup.create.true',
454 'hg.repogroup.create.false', 'hg.repogroup.create.true',
407 'hg.create.write_on_repogroup.false',
455 'hg.create.write_on_repogroup.false',
408 'hg.create.write_on_repogroup.true',
456 'hg.create.write_on_repogroup.true',
409 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true'
457 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true'
410 ])
458 ])
411
459
412 # USER GROUPS comes first user group global permissions
460 # USER GROUPS comes first user group global permissions
413 user_perms_from_users_groups = Session().query(UserGroupToPerm)\
461 user_perms_from_users_groups = Session().query(UserGroupToPerm)\
414 .options(joinedload(UserGroupToPerm.permission))\
462 .options(joinedload(UserGroupToPerm.permission))\
415 .join((UserGroupMember, UserGroupToPerm.users_group_id ==
463 .join((UserGroupMember, UserGroupToPerm.users_group_id ==
416 UserGroupMember.users_group_id))\
464 UserGroupMember.users_group_id))\
417 .filter(UserGroupMember.user_id == self.user_id)\
465 .filter(UserGroupMember.user_id == self.user_id)\
418 .order_by(UserGroupToPerm.users_group_id)\
466 .order_by(UserGroupToPerm.users_group_id)\
419 .all()
467 .all()
420
468
421 # need to group here by groups since user can be in more than
469 # need to group here by groups since user can be in more than
422 # one group, so we get all groups
470 # one group, so we get all groups
423 _explicit_grouped_perms = [
471 _explicit_grouped_perms = [
424 [x, list(y)] for x, y in
472 [x, list(y)] for x, y in
425 itertools.groupby(user_perms_from_users_groups,
473 itertools.groupby(user_perms_from_users_groups,
426 lambda _x: _x.users_group)]
474 lambda _x: _x.users_group)]
427
475
428 for gr, perms in _explicit_grouped_perms:
476 for gr, perms in _explicit_grouped_perms:
429 # since user can be in multiple groups iterate over them and
477 # since user can be in multiple groups iterate over them and
430 # select the lowest permissions first (more explicit)
478 # select the lowest permissions first (more explicit)
431 # TODO: marcink: do this^^
479 # TODO: marcink: do this^^
432
480
433 # group doesn't inherit default permissions so we actually set them
481 # group doesn't inherit default permissions so we actually set them
434 if not gr.inherit_default_permissions:
482 if not gr.inherit_default_permissions:
435 # NEED TO IGNORE all previously set configurable permissions
483 # NEED TO IGNORE all previously set configurable permissions
436 # and replace them with explicitly set from this user
484 # and replace them with explicitly set from this user
437 # group permissions
485 # group permissions
438 self.permissions_global = self.permissions_global.difference(
486 self.permissions_global = self.permissions_global.difference(
439 _configurable)
487 _configurable)
440 for perm in perms:
488 for perm in perms:
441 self.permissions_global.add(
489 self.permissions_global.add(perm.permission.permission_name)
442 perm.permission.permission_name)
443
490
444 # user explicit global permissions
491 # user explicit global permissions
445 user_perms = Session().query(UserToPerm)\
492 user_perms = Session().query(UserToPerm)\
446 .options(joinedload(UserToPerm.permission))\
493 .options(joinedload(UserToPerm.permission))\
447 .filter(UserToPerm.user_id == self.user_id).all()
494 .filter(UserToPerm.user_id == self.user_id).all()
448
495
449 if not self.inherit_default_permissions:
496 if not self.inherit_default_permissions:
450 # NEED TO IGNORE all configurable permissions and
497 # NEED TO IGNORE all configurable permissions and
451 # replace them with explicitly set from this user permissions
498 # replace them with explicitly set from this user permissions
452 self.permissions_global = self.permissions_global.difference(
499 self.permissions_global = self.permissions_global.difference(
453 _configurable)
500 _configurable)
454 for perm in user_perms:
501 for perm in user_perms:
455 self.permissions_global.add(perm.permission.permission_name)
502 self.permissions_global.add(perm.permission.permission_name)
456
503
457 def _calculate_default_permissions(self):
504 def _calculate_default_permissions(self):
458 """
505 """
459 Set default user permissions for repositories, repository groups
506 Set default user permissions for repositories, repository groups
460 taken from the default user.
507 taken from the default user.
461
508
462 Calculate inheritance of object permissions based on what we have now
509 Calculate inheritance of object permissions based on what we have now
463 in GLOBAL permissions. We check if .false is in GLOBAL since this is
510 in GLOBAL permissions. We check if .false is in GLOBAL since this is
464 explicitly set. Inherit is the opposite of .false being there.
511 explicitly set. Inherit is the opposite of .false being there.
465
512
466 .. note::
513 .. note::
467
514
468 the syntax is little bit odd but what we need to check here is
515 the syntax is little bit odd but what we need to check here is
469 the opposite of .false permission being in the list so even for
516 the opposite of .false permission being in the list so even for
470 inconsistent state when both .true/.false is there
517 inconsistent state when both .true/.false is there
471 .false is more important
518 .false is more important
472
519
473 """
520 """
474 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
521 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
475 in self.permissions_global)
522 in self.permissions_global)
476
523
477 # defaults for repositories, taken from `default` user permissions
524 # defaults for repositories, taken from `default` user permissions
478 # on given repo
525 # on given repo
479 for perm in self.default_repo_perms:
526 for perm in self.default_repo_perms:
480 r_k = perm.UserRepoToPerm.repository.repo_name
527 r_k = perm.UserRepoToPerm.repository.repo_name
528 o = PermOrigin.REPO_DEFAULT
481 if perm.Repository.private and not (
529 if perm.Repository.private and not (
482 perm.Repository.user_id == self.user_id):
530 perm.Repository.user_id == self.user_id):
483 # disable defaults for private repos,
531 # disable defaults for private repos,
484 p = 'repository.none'
532 p = 'repository.none'
533 o = PermOrigin.REPO_PRIVATE
485 elif perm.Repository.user_id == self.user_id:
534 elif perm.Repository.user_id == self.user_id:
486 # set admin if owner
535 # set admin if owner
487 p = 'repository.admin'
536 p = 'repository.admin'
537 o = PermOrigin.REPO_OWNER
488 else:
538 else:
489 p = perm.Permission.permission_name
539 p = perm.Permission.permission_name
490 # if we decide this user isn't inheriting permissions from
540 # if we decide this user isn't inheriting permissions from
491 # default user we set him to .none so only explicit
541 # default user we set him to .none so only explicit
492 # permissions work
542 # permissions work
493 if not user_inherit_object_permissions:
543 if not user_inherit_object_permissions:
494 p = 'repository.none'
544 p = 'repository.none'
495 self.permissions_repositories[r_k] = p
545 self.permissions_repositories[r_k] = p, o
496
546
497 # defaults for repository groups taken from `default` user permission
547 # defaults for repository groups taken from `default` user permission
498 # on given group
548 # on given group
499 for perm in self.default_repo_groups_perms:
549 for perm in self.default_repo_groups_perms:
500 rg_k = perm.UserRepoGroupToPerm.group.group_name
550 rg_k = perm.UserRepoGroupToPerm.group.group_name
551 o = PermOrigin.REPOGROUP_DEFAULT
501 if perm.RepoGroup.user_id == self.user_id:
552 if perm.RepoGroup.user_id == self.user_id:
502 # set admin if owner
553 # set admin if owner
503 p = 'group.admin'
554 p = 'group.admin'
555 o = PermOrigin.REPOGROUP_OWNER
504 else:
556 else:
505 p = perm.Permission.permission_name
557 p = perm.Permission.permission_name
506
558
507 # if we decide this user isn't inheriting permissions from default
559 # if we decide this user isn't inheriting permissions from default
508 # user we set him to .none so only explicit permissions work
560 # user we set him to .none so only explicit permissions work
509 if not user_inherit_object_permissions:
561 if not user_inherit_object_permissions:
510 p = 'group.none'
562 p = 'group.none'
511 self.permissions_repository_groups[rg_k] = p
563 self.permissions_repository_groups[rg_k] = p, o
512
564
513 # defaults for user groups taken from `default` user permission
565 # defaults for user groups taken from `default` user permission
514 # on given user group
566 # on given user group
515 for perm in self.default_user_group_perms:
567 for perm in self.default_user_group_perms:
516 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
568 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
517 p = perm.Permission.permission_name
569 p = perm.Permission.permission_name
570 o = PermOrigin.USERGROUP_DEFAULT
518 # if we decide this user isn't inheriting permissions from default
571 # if we decide this user isn't inheriting permissions from default
519 # user we set him to .none so only explicit permissions work
572 # user we set him to .none so only explicit permissions work
520 if not user_inherit_object_permissions:
573 if not user_inherit_object_permissions:
521 p = 'usergroup.none'
574 p = 'usergroup.none'
522 self.permissions_user_groups[u_k] = p
575 self.permissions_user_groups[u_k] = p, o
523
576
524 def _calculate_repository_permissions(self):
577 def _calculate_repository_permissions(self):
525 """
578 """
526 Repository permissions for the current user.
579 Repository permissions for the current user.
527
580
528 Check if the user is part of user groups for this repository and
581 Check if the user is part of user groups for this repository and
529 fill in the permission from it. `_choose_permission` decides of which
582 fill in the permission from it. `_choose_permission` decides of which
530 permission should be selected based on selected method.
583 permission should be selected based on selected method.
531 """
584 """
532
585
533 # user group for repositories permissions
586 # user group for repositories permissions
534 user_repo_perms_from_user_group = Permission\
587 user_repo_perms_from_user_group = Permission\
535 .get_default_repo_perms_from_user_group(
588 .get_default_repo_perms_from_user_group(
536 self.user_id, self.scope_repo_id)
589 self.user_id, self.scope_repo_id)
537
590
538 multiple_counter = collections.defaultdict(int)
591 multiple_counter = collections.defaultdict(int)
539 for perm in user_repo_perms_from_user_group:
592 for perm in user_repo_perms_from_user_group:
540 r_k = perm.UserGroupRepoToPerm.repository.repo_name
593 r_k = perm.UserGroupRepoToPerm.repository.repo_name
594 ug_k = perm.UserGroupRepoToPerm.users_group.users_group_name
541 multiple_counter[r_k] += 1
595 multiple_counter[r_k] += 1
542 p = perm.Permission.permission_name
596 p = perm.Permission.permission_name
597 o = PermOrigin.REPO_USERGROUP % ug_k
543
598
544 if perm.Repository.user_id == self.user_id:
599 if perm.Repository.user_id == self.user_id:
545 # set admin if owner
600 # set admin if owner
546 p = 'repository.admin'
601 p = 'repository.admin'
602 o = PermOrigin.REPO_OWNER
547 else:
603 else:
548 if multiple_counter[r_k] > 1:
604 if multiple_counter[r_k] > 1:
549 cur_perm = self.permissions_repositories[r_k]
605 cur_perm = self.permissions_repositories[r_k]
550 p = self._choose_permission(p, cur_perm)
606 p = self._choose_permission(p, cur_perm)
551 self.permissions_repositories[r_k] = p
607 self.permissions_repositories[r_k] = p, o
552
608
553 # user explicit permissions for repositories, overrides any specified
609 # user explicit permissions for repositories, overrides any specified
554 # by the group permission
610 # by the group permission
555 user_repo_perms = Permission.get_default_repo_perms(
611 user_repo_perms = Permission.get_default_repo_perms(
556 self.user_id, self.scope_repo_id)
612 self.user_id, self.scope_repo_id)
557 for perm in user_repo_perms:
613 for perm in user_repo_perms:
558 r_k = perm.UserRepoToPerm.repository.repo_name
614 r_k = perm.UserRepoToPerm.repository.repo_name
615 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
559 # set admin if owner
616 # set admin if owner
560 if perm.Repository.user_id == self.user_id:
617 if perm.Repository.user_id == self.user_id:
561 p = 'repository.admin'
618 p = 'repository.admin'
619 o = PermOrigin.REPO_OWNER
562 else:
620 else:
563 p = perm.Permission.permission_name
621 p = perm.Permission.permission_name
564 if not self.explicit:
622 if not self.explicit:
565 cur_perm = self.permissions_repositories.get(
623 cur_perm = self.permissions_repositories.get(
566 r_k, 'repository.none')
624 r_k, 'repository.none')
567 p = self._choose_permission(p, cur_perm)
625 p = self._choose_permission(p, cur_perm)
568 self.permissions_repositories[r_k] = p
626 self.permissions_repositories[r_k] = p, o
569
627
570 def _calculate_repository_group_permissions(self):
628 def _calculate_repository_group_permissions(self):
571 """
629 """
572 Repository group permissions for the current user.
630 Repository group permissions for the current user.
573
631
574 Check if the user is part of user groups for repository groups and
632 Check if the user is part of user groups for repository groups and
575 fill in the permissions from it. `_choose_permmission` decides of which
633 fill in the permissions from it. `_choose_permmission` decides of which
576 permission should be selected based on selected method.
634 permission should be selected based on selected method.
577 """
635 """
578 # user group for repo groups permissions
636 # user group for repo groups permissions
579 user_repo_group_perms_from_user_group = Permission\
637 user_repo_group_perms_from_user_group = Permission\
580 .get_default_group_perms_from_user_group(
638 .get_default_group_perms_from_user_group(
581 self.user_id, self.scope_repo_group_id)
639 self.user_id, self.scope_repo_group_id)
582
640
583 multiple_counter = collections.defaultdict(int)
641 multiple_counter = collections.defaultdict(int)
584 for perm in user_repo_group_perms_from_user_group:
642 for perm in user_repo_group_perms_from_user_group:
585 g_k = perm.UserGroupRepoGroupToPerm.group.group_name
643 g_k = perm.UserGroupRepoGroupToPerm.group.group_name
644 ug_k = perm.UserGroupRepoGroupToPerm.users_group.users_group_name
645 o = PermOrigin.REPOGROUP_USERGROUP % ug_k
586 multiple_counter[g_k] += 1
646 multiple_counter[g_k] += 1
587 p = perm.Permission.permission_name
647 p = perm.Permission.permission_name
588 if perm.RepoGroup.user_id == self.user_id:
648 if perm.RepoGroup.user_id == self.user_id:
589 # set admin if owner
649 # set admin if owner
590 p = 'group.admin'
650 p = 'group.admin'
651 o = PermOrigin.REPOGROUP_OWNER
591 else:
652 else:
592 if multiple_counter[g_k] > 1:
653 if multiple_counter[g_k] > 1:
593 cur_perm = self.permissions_repository_groups[g_k]
654 cur_perm = self.permissions_repository_groups[g_k]
594 p = self._choose_permission(p, cur_perm)
655 p = self._choose_permission(p, cur_perm)
595 self.permissions_repository_groups[g_k] = p
656 self.permissions_repository_groups[g_k] = p, o
596
657
597 # user explicit permissions for repository groups
658 # user explicit permissions for repository groups
598 user_repo_groups_perms = Permission.get_default_group_perms(
659 user_repo_groups_perms = Permission.get_default_group_perms(
599 self.user_id, self.scope_repo_group_id)
660 self.user_id, self.scope_repo_group_id)
600 for perm in user_repo_groups_perms:
661 for perm in user_repo_groups_perms:
601 rg_k = perm.UserRepoGroupToPerm.group.group_name
662 rg_k = perm.UserRepoGroupToPerm.group.group_name
663 u_k = perm.UserRepoGroupToPerm.user.username
664 o = PermOrigin.REPOGROUP_USER % u_k
665
602 if perm.RepoGroup.user_id == self.user_id:
666 if perm.RepoGroup.user_id == self.user_id:
603 # set admin if owner
667 # set admin if owner
604 p = 'group.admin'
668 p = 'group.admin'
669 o = PermOrigin.REPOGROUP_OWNER
605 else:
670 else:
606 p = perm.Permission.permission_name
671 p = perm.Permission.permission_name
607 if not self.explicit:
672 if not self.explicit:
608 cur_perm = self.permissions_repository_groups.get(
673 cur_perm = self.permissions_repository_groups.get(
609 rg_k, 'group.none')
674 rg_k, 'group.none')
610 p = self._choose_permission(p, cur_perm)
675 p = self._choose_permission(p, cur_perm)
611 self.permissions_repository_groups[rg_k] = p
676 self.permissions_repository_groups[rg_k] = p, o
612
677
613 def _calculate_user_group_permissions(self):
678 def _calculate_user_group_permissions(self):
614 """
679 """
615 User group permissions for the current user.
680 User group permissions for the current user.
616 """
681 """
617 # user group for user group permissions
682 # user group for user group permissions
618 user_group_from_user_group = Permission\
683 user_group_from_user_group = Permission\
619 .get_default_user_group_perms_from_user_group(
684 .get_default_user_group_perms_from_user_group(
620 self.user_id, self.scope_repo_group_id)
685 self.user_id, self.scope_repo_group_id)
621
686
622 multiple_counter = collections.defaultdict(int)
687 multiple_counter = collections.defaultdict(int)
623 for perm in user_group_from_user_group:
688 for perm in user_group_from_user_group:
624 g_k = perm.UserGroupUserGroupToPerm\
689 g_k = perm.UserGroupUserGroupToPerm\
625 .target_user_group.users_group_name
690 .target_user_group.users_group_name
691 u_k = perm.UserGroupUserGroupToPerm\
692 .user_group.users_group_name
693 o = PermOrigin.USERGROUP_USERGROUP % u_k
626 multiple_counter[g_k] += 1
694 multiple_counter[g_k] += 1
627 p = perm.Permission.permission_name
695 p = perm.Permission.permission_name
628 if multiple_counter[g_k] > 1:
696 if multiple_counter[g_k] > 1:
629 cur_perm = self.permissions_user_groups[g_k]
697 cur_perm = self.permissions_user_groups[g_k]
630 p = self._choose_permission(p, cur_perm)
698 p = self._choose_permission(p, cur_perm)
631 self.permissions_user_groups[g_k] = p
699 self.permissions_user_groups[g_k] = p, o
632
700
633 # user explicit permission for user groups
701 # user explicit permission for user groups
634 user_user_groups_perms = Permission.get_default_user_group_perms(
702 user_user_groups_perms = Permission.get_default_user_group_perms(
635 self.user_id, self.scope_user_group_id)
703 self.user_id, self.scope_user_group_id)
636 for perm in user_user_groups_perms:
704 for perm in user_user_groups_perms:
637 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
705 ug_k = perm.UserUserGroupToPerm.user_group.users_group_name
706 u_k = perm.UserUserGroupToPerm.user.username
638 p = perm.Permission.permission_name
707 p = perm.Permission.permission_name
708 o = PermOrigin.USERGROUP_USER % u_k
639 if not self.explicit:
709 if not self.explicit:
640 cur_perm = self.permissions_user_groups.get(
710 cur_perm = self.permissions_user_groups.get(
641 u_k, 'usergroup.none')
711 ug_k, 'usergroup.none')
642 p = self._choose_permission(p, cur_perm)
712 p = self._choose_permission(p, cur_perm)
643 self.permissions_user_groups[u_k] = p
713 self.permissions_user_groups[ug_k] = p, o
644
714
645 def _choose_permission(self, new_perm, cur_perm):
715 def _choose_permission(self, new_perm, cur_perm):
646 new_perm_val = Permission.PERM_WEIGHTS[new_perm]
716 new_perm_val = Permission.PERM_WEIGHTS[new_perm]
647 cur_perm_val = Permission.PERM_WEIGHTS[cur_perm]
717 cur_perm_val = Permission.PERM_WEIGHTS[cur_perm]
648 if self.algo == 'higherwin':
718 if self.algo == 'higherwin':
649 if new_perm_val > cur_perm_val:
719 if new_perm_val > cur_perm_val:
650 return new_perm
720 return new_perm
651 return cur_perm
721 return cur_perm
652 elif self.algo == 'lowerwin':
722 elif self.algo == 'lowerwin':
653 if new_perm_val < cur_perm_val:
723 if new_perm_val < cur_perm_val:
654 return new_perm
724 return new_perm
655 return cur_perm
725 return cur_perm
656
726
657 def _permission_structure(self):
727 def _permission_structure(self):
658 return {
728 return {
659 'global': self.permissions_global,
729 'global': self.permissions_global,
660 'repositories': self.permissions_repositories,
730 'repositories': self.permissions_repositories,
661 'repositories_groups': self.permissions_repository_groups,
731 'repositories_groups': self.permissions_repository_groups,
662 'user_groups': self.permissions_user_groups,
732 'user_groups': self.permissions_user_groups,
663 }
733 }
664
734
665
735
666 def allowed_auth_token_access(controller_name, whitelist=None, auth_token=None):
736 def allowed_auth_token_access(controller_name, whitelist=None, auth_token=None):
667 """
737 """
668 Check if given controller_name is in whitelist of auth token access
738 Check if given controller_name is in whitelist of auth token access
669 """
739 """
670 if not whitelist:
740 if not whitelist:
671 from rhodecode import CONFIG
741 from rhodecode import CONFIG
672 whitelist = aslist(
742 whitelist = aslist(
673 CONFIG.get('api_access_controllers_whitelist'), sep=',')
743 CONFIG.get('api_access_controllers_whitelist'), sep=',')
674 log.debug(
744 log.debug(
675 'Allowed controllers for AUTH TOKEN access: %s' % (whitelist,))
745 'Allowed controllers for AUTH TOKEN access: %s' % (whitelist,))
676
746
677 auth_token_access_valid = False
747 auth_token_access_valid = False
678 for entry in whitelist:
748 for entry in whitelist:
679 if fnmatch.fnmatch(controller_name, entry):
749 if fnmatch.fnmatch(controller_name, entry):
680 auth_token_access_valid = True
750 auth_token_access_valid = True
681 break
751 break
682
752
683 if auth_token_access_valid:
753 if auth_token_access_valid:
684 log.debug('controller:%s matches entry in whitelist'
754 log.debug('controller:%s matches entry in whitelist'
685 % (controller_name,))
755 % (controller_name,))
686 else:
756 else:
687 msg = ('controller: %s does *NOT* match any entry in whitelist'
757 msg = ('controller: %s does *NOT* match any entry in whitelist'
688 % (controller_name,))
758 % (controller_name,))
689 if auth_token:
759 if auth_token:
690 # if we use auth token key and don't have access it's a warning
760 # if we use auth token key and don't have access it's a warning
691 log.warning(msg)
761 log.warning(msg)
692 else:
762 else:
693 log.debug(msg)
763 log.debug(msg)
694
764
695 return auth_token_access_valid
765 return auth_token_access_valid
696
766
697
767
698 class AuthUser(object):
768 class AuthUser(object):
699 """
769 """
700 A simple object that handles all attributes of user in RhodeCode
770 A simple object that handles all attributes of user in RhodeCode
701
771
702 It does lookup based on API key,given user, or user present in session
772 It does lookup based on API key,given user, or user present in session
703 Then it fills all required information for such user. It also checks if
773 Then it fills all required information for such user. It also checks if
704 anonymous access is enabled and if so, it returns default user as logged in
774 anonymous access is enabled and if so, it returns default user as logged in
705 """
775 """
706 GLOBAL_PERMS = [x[0] for x in Permission.PERMS]
776 GLOBAL_PERMS = [x[0] for x in Permission.PERMS]
707
777
708 def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):
778 def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):
709
779
710 self.user_id = user_id
780 self.user_id = user_id
711 self._api_key = api_key
781 self._api_key = api_key
712
782
713 self.api_key = None
783 self.api_key = None
714 self.feed_token = ''
784 self.feed_token = ''
715 self.username = username
785 self.username = username
716 self.ip_addr = ip_addr
786 self.ip_addr = ip_addr
717 self.name = ''
787 self.name = ''
718 self.lastname = ''
788 self.lastname = ''
719 self.email = ''
789 self.email = ''
720 self.is_authenticated = False
790 self.is_authenticated = False
721 self.admin = False
791 self.admin = False
722 self.inherit_default_permissions = False
792 self.inherit_default_permissions = False
723 self.password = ''
793 self.password = ''
724
794
725 self.anonymous_user = None # propagated on propagate_data
795 self.anonymous_user = None # propagated on propagate_data
726 self.propagate_data()
796 self.propagate_data()
727 self._instance = None
797 self._instance = None
728 self._permissions_scoped_cache = {} # used to bind scoped calculation
798 self._permissions_scoped_cache = {} # used to bind scoped calculation
729
799
730 @LazyProperty
800 @LazyProperty
731 def permissions(self):
801 def permissions(self):
732 return self.get_perms(user=self, cache=False)
802 return self.get_perms(user=self, cache=False)
733
803
734 def permissions_with_scope(self, scope):
804 def permissions_with_scope(self, scope):
735 """
805 """
736 Call the get_perms function with scoped data. The scope in that function
806 Call the get_perms function with scoped data. The scope in that function
737 narrows the SQL calls to the given ID of objects resulting in fetching
807 narrows the SQL calls to the given ID of objects resulting in fetching
738 Just particular permission we want to obtain. If scope is an empty dict
808 Just particular permission we want to obtain. If scope is an empty dict
739 then it basically narrows the scope to GLOBAL permissions only.
809 then it basically narrows the scope to GLOBAL permissions only.
740
810
741 :param scope: dict
811 :param scope: dict
742 """
812 """
743 if 'repo_name' in scope:
813 if 'repo_name' in scope:
744 obj = Repository.get_by_repo_name(scope['repo_name'])
814 obj = Repository.get_by_repo_name(scope['repo_name'])
745 if obj:
815 if obj:
746 scope['repo_id'] = obj.repo_id
816 scope['repo_id'] = obj.repo_id
747 _scope = {
817 _scope = {
748 'repo_id': -1,
818 'repo_id': -1,
749 'user_group_id': -1,
819 'user_group_id': -1,
750 'repo_group_id': -1,
820 'repo_group_id': -1,
751 }
821 }
752 _scope.update(scope)
822 _scope.update(scope)
753 cache_key = "_".join(map(safe_str, reduce(lambda a, b: a+b,
823 cache_key = "_".join(map(safe_str, reduce(lambda a, b: a+b,
754 _scope.items())))
824 _scope.items())))
755 if cache_key not in self._permissions_scoped_cache:
825 if cache_key not in self._permissions_scoped_cache:
756 # store in cache to mimic how the @LazyProperty works,
826 # store in cache to mimic how the @LazyProperty works,
757 # the difference here is that we use the unique key calculated
827 # the difference here is that we use the unique key calculated
758 # from params and values
828 # from params and values
759 res = self.get_perms(user=self, cache=False, scope=_scope)
829 res = self.get_perms(user=self, cache=False, scope=_scope)
760 self._permissions_scoped_cache[cache_key] = res
830 self._permissions_scoped_cache[cache_key] = res
761 return self._permissions_scoped_cache[cache_key]
831 return self._permissions_scoped_cache[cache_key]
762
832
763 @property
833 @property
764 def auth_tokens(self):
834 def auth_tokens(self):
765 return self.get_auth_tokens()
835 return self.get_auth_tokens()
766
836
767 def get_instance(self):
837 def get_instance(self):
768 return User.get(self.user_id)
838 return User.get(self.user_id)
769
839
770 def update_lastactivity(self):
840 def update_lastactivity(self):
771 if self.user_id:
841 if self.user_id:
772 User.get(self.user_id).update_lastactivity()
842 User.get(self.user_id).update_lastactivity()
773
843
774 def propagate_data(self):
844 def propagate_data(self):
775 """
845 """
776 Fills in user data and propagates values to this instance. Maps fetched
846 Fills in user data and propagates values to this instance. Maps fetched
777 user attributes to this class instance attributes
847 user attributes to this class instance attributes
778 """
848 """
779
849
780 user_model = UserModel()
850 user_model = UserModel()
781 anon_user = self.anonymous_user = User.get_default_user(cache=True)
851 anon_user = self.anonymous_user = User.get_default_user(cache=True)
782 is_user_loaded = False
852 is_user_loaded = False
783
853
784 # lookup by userid
854 # lookup by userid
785 if self.user_id is not None and self.user_id != anon_user.user_id:
855 if self.user_id is not None and self.user_id != anon_user.user_id:
786 log.debug('Trying Auth User lookup by USER ID %s' % self.user_id)
856 log.debug('Trying Auth User lookup by USER ID %s' % self.user_id)
787 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
857 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
788
858
789 # try go get user by api key
859 # try go get user by api key
790 elif self._api_key and self._api_key != anon_user.api_key:
860 elif self._api_key and self._api_key != anon_user.api_key:
791 log.debug('Trying Auth User lookup by API KEY %s' % self._api_key)
861 log.debug('Trying Auth User lookup by API KEY %s' % self._api_key)
792 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
862 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
793
863
794 # lookup by username
864 # lookup by username
795 elif self.username:
865 elif self.username:
796 log.debug('Trying Auth User lookup by USER NAME %s' % self.username)
866 log.debug('Trying Auth User lookup by USER NAME %s' % self.username)
797 is_user_loaded = user_model.fill_data(self, username=self.username)
867 is_user_loaded = user_model.fill_data(self, username=self.username)
798 else:
868 else:
799 log.debug('No data in %s that could been used to log in' % self)
869 log.debug('No data in %s that could been used to log in' % self)
800
870
801 if not is_user_loaded:
871 if not is_user_loaded:
802 log.debug('Failed to load user %s. Fallback to default user', self)
872 log.debug('Failed to load user. Fallback to default user')
803 # if we cannot authenticate user try anonymous
873 # if we cannot authenticate user try anonymous
804 if anon_user.active:
874 if anon_user.active:
805 user_model.fill_data(self, user_id=anon_user.user_id)
875 user_model.fill_data(self, user_id=anon_user.user_id)
806 # then we set this user is logged in
876 # then we set this user is logged in
807 self.is_authenticated = True
877 self.is_authenticated = True
808 else:
878 else:
809 # in case of disabled anonymous user we reset some of the
879 # in case of disabled anonymous user we reset some of the
810 # parameters so such user is "corrupted", skipping the fill_data
880 # parameters so such user is "corrupted", skipping the fill_data
811 for attr in ['user_id', 'username', 'admin', 'active']:
881 for attr in ['user_id', 'username', 'admin', 'active']:
812 setattr(self, attr, None)
882 setattr(self, attr, None)
813 self.is_authenticated = False
883 self.is_authenticated = False
814
884
815 if not self.username:
885 if not self.username:
816 self.username = 'None'
886 self.username = 'None'
817
887
818 log.debug('Auth User is now %s' % self)
888 log.debug('Auth User is now %s' % self)
819
889
820 def get_perms(self, user, scope=None, explicit=True, algo='higherwin',
890 def get_perms(self, user, scope=None, explicit=True, algo='higherwin',
821 cache=False):
891 cache=False):
822 """
892 """
823 Fills user permission attribute with permissions taken from database
893 Fills user permission attribute with permissions taken from database
824 works for permissions given for repositories, and for permissions that
894 works for permissions given for repositories, and for permissions that
825 are granted to groups
895 are granted to groups
826
896
827 :param user: instance of User object from database
897 :param user: instance of User object from database
828 :param explicit: In case there are permissions both for user and a group
898 :param explicit: In case there are permissions both for user and a group
829 that user is part of, explicit flag will defiine if user will
899 that user is part of, explicit flag will defiine if user will
830 explicitly override permissions from group, if it's False it will
900 explicitly override permissions from group, if it's False it will
831 make decision based on the algo
901 make decision based on the algo
832 :param algo: algorithm to decide what permission should be choose if
902 :param algo: algorithm to decide what permission should be choose if
833 it's multiple defined, eg user in two different groups. It also
903 it's multiple defined, eg user in two different groups. It also
834 decides if explicit flag is turned off how to specify the permission
904 decides if explicit flag is turned off how to specify the permission
835 for case when user is in a group + have defined separate permission
905 for case when user is in a group + have defined separate permission
836 """
906 """
837 user_id = user.user_id
907 user_id = user.user_id
838 user_is_admin = user.is_admin
908 user_is_admin = user.is_admin
839
909
840 # inheritance of global permissions like create repo/fork repo etc
910 # inheritance of global permissions like create repo/fork repo etc
841 user_inherit_default_permissions = user.inherit_default_permissions
911 user_inherit_default_permissions = user.inherit_default_permissions
842
912
843 log.debug('Computing PERMISSION tree for scope %s' % (scope, ))
913 log.debug('Computing PERMISSION tree for scope %s' % (scope, ))
844 compute = caches.conditional_cache(
914 compute = caches.conditional_cache(
845 'short_term', 'cache_desc',
915 'short_term', 'cache_desc',
846 condition=cache, func=_cached_perms_data)
916 condition=cache, func=_cached_perms_data)
847 result = compute(user_id, scope, user_is_admin,
917 result = compute(user_id, scope, user_is_admin,
848 user_inherit_default_permissions, explicit, algo)
918 user_inherit_default_permissions, explicit, algo)
849
919
850 result_repr = []
920 result_repr = []
851 for k in result:
921 for k in result:
852 result_repr.append((k, len(result[k])))
922 result_repr.append((k, len(result[k])))
853
923
854 log.debug('PERMISSION tree computed %s' % (result_repr,))
924 log.debug('PERMISSION tree computed %s' % (result_repr,))
855 return result
925 return result
856
926
857 def get_auth_tokens(self):
927 def get_auth_tokens(self):
858 auth_tokens = [self.api_key]
928 auth_tokens = [self.api_key]
859 for api_key in UserApiKeys.query()\
929 for api_key in UserApiKeys.query()\
860 .filter(UserApiKeys.user_id == self.user_id)\
930 .filter(UserApiKeys.user_id == self.user_id)\
861 .filter(or_(UserApiKeys.expires == -1,
931 .filter(or_(UserApiKeys.expires == -1,
862 UserApiKeys.expires >= time.time())).all():
932 UserApiKeys.expires >= time.time())).all():
863 auth_tokens.append(api_key.api_key)
933 auth_tokens.append(api_key.api_key)
864
934
865 return auth_tokens
935 return auth_tokens
866
936
867 @property
937 @property
868 def is_default(self):
938 def is_default(self):
869 return self.username == User.DEFAULT_USER
939 return self.username == User.DEFAULT_USER
870
940
871 @property
941 @property
872 def is_admin(self):
942 def is_admin(self):
873 return self.admin
943 return self.admin
874
944
875 @property
945 @property
876 def is_user_object(self):
946 def is_user_object(self):
877 return self.user_id is not None
947 return self.user_id is not None
878
948
879 @property
949 @property
880 def repositories_admin(self):
950 def repositories_admin(self):
881 """
951 """
882 Returns list of repositories you're an admin of
952 Returns list of repositories you're an admin of
883 """
953 """
884 return [x[0] for x in self.permissions['repositories'].iteritems()
954 return [x[0] for x in self.permissions['repositories'].iteritems()
885 if x[1] == 'repository.admin']
955 if x[1] == 'repository.admin']
886
956
887 @property
957 @property
888 def repository_groups_admin(self):
958 def repository_groups_admin(self):
889 """
959 """
890 Returns list of repository groups you're an admin of
960 Returns list of repository groups you're an admin of
891 """
961 """
892 return [x[0]
962 return [x[0]
893 for x in self.permissions['repositories_groups'].iteritems()
963 for x in self.permissions['repositories_groups'].iteritems()
894 if x[1] == 'group.admin']
964 if x[1] == 'group.admin']
895
965
896 @property
966 @property
897 def user_groups_admin(self):
967 def user_groups_admin(self):
898 """
968 """
899 Returns list of user groups you're an admin of
969 Returns list of user groups you're an admin of
900 """
970 """
901 return [x[0] for x in self.permissions['user_groups'].iteritems()
971 return [x[0] for x in self.permissions['user_groups'].iteritems()
902 if x[1] == 'usergroup.admin']
972 if x[1] == 'usergroup.admin']
903
973
904 @property
974 @property
905 def ip_allowed(self):
975 def ip_allowed(self):
906 """
976 """
907 Checks if ip_addr used in constructor is allowed from defined list of
977 Checks if ip_addr used in constructor is allowed from defined list of
908 allowed ip_addresses for user
978 allowed ip_addresses for user
909
979
910 :returns: boolean, True if ip is in allowed ip range
980 :returns: boolean, True if ip is in allowed ip range
911 """
981 """
912 # check IP
982 # check IP
913 inherit = self.inherit_default_permissions
983 inherit = self.inherit_default_permissions
914 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
984 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
915 inherit_from_default=inherit)
985 inherit_from_default=inherit)
916
986
917 @classmethod
987 @classmethod
918 def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default):
988 def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default):
919 allowed_ips = AuthUser.get_allowed_ips(
989 allowed_ips = AuthUser.get_allowed_ips(
920 user_id, cache=True, inherit_from_default=inherit_from_default)
990 user_id, cache=True, inherit_from_default=inherit_from_default)
921 if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
991 if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
922 log.debug('IP:%s is in range of %s' % (ip_addr, allowed_ips))
992 log.debug('IP:%s is in range of %s' % (ip_addr, allowed_ips))
923 return True
993 return True
924 else:
994 else:
925 log.info('Access for IP:%s forbidden, '
995 log.info('Access for IP:%s forbidden, '
926 'not in %s' % (ip_addr, allowed_ips))
996 'not in %s' % (ip_addr, allowed_ips))
927 return False
997 return False
928
998
929 def __repr__(self):
999 def __repr__(self):
930 return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
1000 return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
931 % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
1001 % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
932
1002
933 def set_authenticated(self, authenticated=True):
1003 def set_authenticated(self, authenticated=True):
934 if self.user_id != self.anonymous_user.user_id:
1004 if self.user_id != self.anonymous_user.user_id:
935 self.is_authenticated = authenticated
1005 self.is_authenticated = authenticated
936
1006
937 def get_cookie_store(self):
1007 def get_cookie_store(self):
938 return {
1008 return {
939 'username': self.username,
1009 'username': self.username,
940 'password': md5(self.password),
1010 'password': md5(self.password),
941 'user_id': self.user_id,
1011 'user_id': self.user_id,
942 'is_authenticated': self.is_authenticated
1012 'is_authenticated': self.is_authenticated
943 }
1013 }
944
1014
945 @classmethod
1015 @classmethod
946 def from_cookie_store(cls, cookie_store):
1016 def from_cookie_store(cls, cookie_store):
947 """
1017 """
948 Creates AuthUser from a cookie store
1018 Creates AuthUser from a cookie store
949
1019
950 :param cls:
1020 :param cls:
951 :param cookie_store:
1021 :param cookie_store:
952 """
1022 """
953 user_id = cookie_store.get('user_id')
1023 user_id = cookie_store.get('user_id')
954 username = cookie_store.get('username')
1024 username = cookie_store.get('username')
955 api_key = cookie_store.get('api_key')
1025 api_key = cookie_store.get('api_key')
956 return AuthUser(user_id, api_key, username)
1026 return AuthUser(user_id, api_key, username)
957
1027
958 @classmethod
1028 @classmethod
959 def get_allowed_ips(cls, user_id, cache=False, inherit_from_default=False):
1029 def get_allowed_ips(cls, user_id, cache=False, inherit_from_default=False):
960 _set = set()
1030 _set = set()
961
1031
962 if inherit_from_default:
1032 if inherit_from_default:
963 default_ips = UserIpMap.query().filter(
1033 default_ips = UserIpMap.query().filter(
964 UserIpMap.user == User.get_default_user(cache=True))
1034 UserIpMap.user == User.get_default_user(cache=True))
965 if cache:
1035 if cache:
966 default_ips = default_ips.options(FromCache("sql_cache_short",
1036 default_ips = default_ips.options(FromCache("sql_cache_short",
967 "get_user_ips_default"))
1037 "get_user_ips_default"))
968
1038
969 # populate from default user
1039 # populate from default user
970 for ip in default_ips:
1040 for ip in default_ips:
971 try:
1041 try:
972 _set.add(ip.ip_addr)
1042 _set.add(ip.ip_addr)
973 except ObjectDeletedError:
1043 except ObjectDeletedError:
974 # since we use heavy caching sometimes it happens that
1044 # since we use heavy caching sometimes it happens that
975 # we get deleted objects here, we just skip them
1045 # we get deleted objects here, we just skip them
976 pass
1046 pass
977
1047
978 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
1048 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
979 if cache:
1049 if cache:
980 user_ips = user_ips.options(FromCache("sql_cache_short",
1050 user_ips = user_ips.options(FromCache("sql_cache_short",
981 "get_user_ips_%s" % user_id))
1051 "get_user_ips_%s" % user_id))
982
1052
983 for ip in user_ips:
1053 for ip in user_ips:
984 try:
1054 try:
985 _set.add(ip.ip_addr)
1055 _set.add(ip.ip_addr)
986 except ObjectDeletedError:
1056 except ObjectDeletedError:
987 # since we use heavy caching sometimes it happens that we get
1057 # since we use heavy caching sometimes it happens that we get
988 # deleted objects here, we just skip them
1058 # deleted objects here, we just skip them
989 pass
1059 pass
990 return _set or set(['0.0.0.0/0', '::/0'])
1060 return _set or set(['0.0.0.0/0', '::/0'])
991
1061
992
1062
993 def set_available_permissions(config):
1063 def set_available_permissions(config):
994 """
1064 """
995 This function will propagate pylons globals with all available defined
1065 This function will propagate pylons globals with all available defined
996 permission given in db. We don't want to check each time from db for new
1066 permission given in db. We don't want to check each time from db for new
997 permissions since adding a new permission also requires application restart
1067 permissions since adding a new permission also requires application restart
998 ie. to decorate new views with the newly created permission
1068 ie. to decorate new views with the newly created permission
999
1069
1000 :param config: current pylons config instance
1070 :param config: current pylons config instance
1001
1071
1002 """
1072 """
1003 log.info('getting information about all available permissions')
1073 log.info('getting information about all available permissions')
1004 try:
1074 try:
1005 sa = meta.Session
1075 sa = meta.Session
1006 all_perms = sa.query(Permission).all()
1076 all_perms = sa.query(Permission).all()
1007 config['available_permissions'] = [x.permission_name for x in all_perms]
1077 config['available_permissions'] = [x.permission_name for x in all_perms]
1008 except Exception:
1078 except Exception:
1009 log.error(traceback.format_exc())
1079 log.error(traceback.format_exc())
1010 finally:
1080 finally:
1011 meta.Session.remove()
1081 meta.Session.remove()
1012
1082
1013
1083
1014 def get_csrf_token(session=None, force_new=False, save_if_missing=True):
1084 def get_csrf_token(session=None, force_new=False, save_if_missing=True):
1015 """
1085 """
1016 Return the current authentication token, creating one if one doesn't
1086 Return the current authentication token, creating one if one doesn't
1017 already exist and the save_if_missing flag is present.
1087 already exist and the save_if_missing flag is present.
1018
1088
1019 :param session: pass in the pylons session, else we use the global ones
1089 :param session: pass in the pylons session, else we use the global ones
1020 :param force_new: force to re-generate the token and store it in session
1090 :param force_new: force to re-generate the token and store it in session
1021 :param save_if_missing: save the newly generated token if it's missing in
1091 :param save_if_missing: save the newly generated token if it's missing in
1022 session
1092 session
1023 """
1093 """
1024 if not session:
1094 if not session:
1025 from pylons import session
1095 from pylons import session
1026
1096
1027 if (csrf_token_key not in session and save_if_missing) or force_new:
1097 if (csrf_token_key not in session and save_if_missing) or force_new:
1028 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
1098 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
1029 session[csrf_token_key] = token
1099 session[csrf_token_key] = token
1030 if hasattr(session, 'save'):
1100 if hasattr(session, 'save'):
1031 session.save()
1101 session.save()
1032 return session.get(csrf_token_key)
1102 return session.get(csrf_token_key)
1033
1103
1034
1104
1035 # CHECK DECORATORS
1105 # CHECK DECORATORS
1036 class CSRFRequired(object):
1106 class CSRFRequired(object):
1037 """
1107 """
1038 Decorator for authenticating a form
1108 Decorator for authenticating a form
1039
1109
1040 This decorator uses an authorization token stored in the client's
1110 This decorator uses an authorization token stored in the client's
1041 session for prevention of certain Cross-site request forgery (CSRF)
1111 session for prevention of certain Cross-site request forgery (CSRF)
1042 attacks (See
1112 attacks (See
1043 http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
1113 http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
1044 information).
1114 information).
1045
1115
1046 For use with the ``webhelpers.secure_form`` helper functions.
1116 For use with the ``webhelpers.secure_form`` helper functions.
1047
1117
1048 """
1118 """
1049 def __init__(self, token=csrf_token_key, header='X-CSRF-Token'):
1119 def __init__(self, token=csrf_token_key, header='X-CSRF-Token'):
1050 self.token = token
1120 self.token = token
1051 self.header = header
1121 self.header = header
1052
1122
1053 def __call__(self, func):
1123 def __call__(self, func):
1054 return get_cython_compat_decorator(self.__wrapper, func)
1124 return get_cython_compat_decorator(self.__wrapper, func)
1055
1125
1056 def _get_csrf(self, _request):
1126 def _get_csrf(self, _request):
1057 return _request.POST.get(self.token, _request.headers.get(self.header))
1127 return _request.POST.get(self.token, _request.headers.get(self.header))
1058
1128
1059 def check_csrf(self, _request, cur_token):
1129 def check_csrf(self, _request, cur_token):
1060 supplied_token = self._get_csrf(_request)
1130 supplied_token = self._get_csrf(_request)
1061 return supplied_token and supplied_token == cur_token
1131 return supplied_token and supplied_token == cur_token
1062
1132
1063 def __wrapper(self, func, *fargs, **fkwargs):
1133 def __wrapper(self, func, *fargs, **fkwargs):
1064 cur_token = get_csrf_token(save_if_missing=False)
1134 cur_token = get_csrf_token(save_if_missing=False)
1065 if self.check_csrf(request, cur_token):
1135 if self.check_csrf(request, cur_token):
1066 if request.POST.get(self.token):
1136 if request.POST.get(self.token):
1067 del request.POST[self.token]
1137 del request.POST[self.token]
1068 return func(*fargs, **fkwargs)
1138 return func(*fargs, **fkwargs)
1069 else:
1139 else:
1070 reason = 'token-missing'
1140 reason = 'token-missing'
1071 supplied_token = self._get_csrf(request)
1141 supplied_token = self._get_csrf(request)
1072 if supplied_token and cur_token != supplied_token:
1142 if supplied_token and cur_token != supplied_token:
1073 reason = 'token-mismatch [%s:%s]' % (cur_token or ''[:6],
1143 reason = 'token-mismatch [%s:%s]' % (cur_token or ''[:6],
1074 supplied_token or ''[:6])
1144 supplied_token or ''[:6])
1075
1145
1076 csrf_message = \
1146 csrf_message = \
1077 ("Cross-site request forgery detected, request denied. See "
1147 ("Cross-site request forgery detected, request denied. See "
1078 "http://en.wikipedia.org/wiki/Cross-site_request_forgery for "
1148 "http://en.wikipedia.org/wiki/Cross-site_request_forgery for "
1079 "more information.")
1149 "more information.")
1080 log.warn('Cross-site request forgery detected, request %r DENIED: %s '
1150 log.warn('Cross-site request forgery detected, request %r DENIED: %s '
1081 'REMOTE_ADDR:%s, HEADERS:%s' % (
1151 'REMOTE_ADDR:%s, HEADERS:%s' % (
1082 request, reason, request.remote_addr, request.headers))
1152 request, reason, request.remote_addr, request.headers))
1083
1153
1084 abort(403, detail=csrf_message)
1154 abort(403, detail=csrf_message)
1085
1155
1086
1156
1087 class LoginRequired(object):
1157 class LoginRequired(object):
1088 """
1158 """
1089 Must be logged in to execute this function else
1159 Must be logged in to execute this function else
1090 redirect to login page
1160 redirect to login page
1091
1161
1092 :param api_access: if enabled this checks only for valid auth token
1162 :param api_access: if enabled this checks only for valid auth token
1093 and grants access based on valid token
1163 and grants access based on valid token
1094 """
1164 """
1095 def __init__(self, auth_token_access=False):
1165 def __init__(self, auth_token_access=False):
1096 self.auth_token_access = auth_token_access
1166 self.auth_token_access = auth_token_access
1097
1167
1098 def __call__(self, func):
1168 def __call__(self, func):
1099 return get_cython_compat_decorator(self.__wrapper, func)
1169 return get_cython_compat_decorator(self.__wrapper, func)
1100
1170
1101 def __wrapper(self, func, *fargs, **fkwargs):
1171 def __wrapper(self, func, *fargs, **fkwargs):
1102 from rhodecode.lib import helpers as h
1172 from rhodecode.lib import helpers as h
1103 cls = fargs[0]
1173 cls = fargs[0]
1104 user = cls._rhodecode_user
1174 user = cls._rhodecode_user
1105 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
1175 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
1106 log.debug('Starting login restriction checks for user: %s' % (user,))
1176 log.debug('Starting login restriction checks for user: %s' % (user,))
1107 # check if our IP is allowed
1177 # check if our IP is allowed
1108 ip_access_valid = True
1178 ip_access_valid = True
1109 if not user.ip_allowed:
1179 if not user.ip_allowed:
1110 h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr,))),
1180 h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr,))),
1111 category='warning')
1181 category='warning')
1112 ip_access_valid = False
1182 ip_access_valid = False
1113
1183
1114 # check if we used an APIKEY and it's a valid one
1184 # check if we used an APIKEY and it's a valid one
1115 # defined whitelist of controllers which API access will be enabled
1185 # defined whitelist of controllers which API access will be enabled
1116 _auth_token = request.GET.get(
1186 _auth_token = request.GET.get(
1117 'auth_token', '') or request.GET.get('api_key', '')
1187 'auth_token', '') or request.GET.get('api_key', '')
1118 auth_token_access_valid = allowed_auth_token_access(
1188 auth_token_access_valid = allowed_auth_token_access(
1119 loc, auth_token=_auth_token)
1189 loc, auth_token=_auth_token)
1120
1190
1121 # explicit controller is enabled or API is in our whitelist
1191 # explicit controller is enabled or API is in our whitelist
1122 if self.auth_token_access or auth_token_access_valid:
1192 if self.auth_token_access or auth_token_access_valid:
1123 log.debug('Checking AUTH TOKEN access for %s' % (cls,))
1193 log.debug('Checking AUTH TOKEN access for %s' % (cls,))
1124
1194
1125 if _auth_token and _auth_token in user.auth_tokens:
1195 if _auth_token and _auth_token in user.auth_tokens:
1126 auth_token_access_valid = True
1196 auth_token_access_valid = True
1127 log.debug('AUTH TOKEN ****%s is VALID' % (_auth_token[-4:],))
1197 log.debug('AUTH TOKEN ****%s is VALID' % (_auth_token[-4:],))
1128 else:
1198 else:
1129 auth_token_access_valid = False
1199 auth_token_access_valid = False
1130 if not _auth_token:
1200 if not _auth_token:
1131 log.debug("AUTH TOKEN *NOT* present in request")
1201 log.debug("AUTH TOKEN *NOT* present in request")
1132 else:
1202 else:
1133 log.warning(
1203 log.warning(
1134 "AUTH TOKEN ****%s *NOT* valid" % _auth_token[-4:])
1204 "AUTH TOKEN ****%s *NOT* valid" % _auth_token[-4:])
1135
1205
1136 log.debug('Checking if %s is authenticated @ %s' % (user.username, loc))
1206 log.debug('Checking if %s is authenticated @ %s' % (user.username, loc))
1137 reason = 'RHODECODE_AUTH' if user.is_authenticated \
1207 reason = 'RHODECODE_AUTH' if user.is_authenticated \
1138 else 'AUTH_TOKEN_AUTH'
1208 else 'AUTH_TOKEN_AUTH'
1139
1209
1140 if ip_access_valid and (
1210 if ip_access_valid and (
1141 user.is_authenticated or auth_token_access_valid):
1211 user.is_authenticated or auth_token_access_valid):
1142 log.info(
1212 log.info(
1143 'user %s authenticating with:%s IS authenticated on func %s'
1213 'user %s authenticating with:%s IS authenticated on func %s'
1144 % (user, reason, loc))
1214 % (user, reason, loc))
1145
1215
1146 # update user data to check last activity
1216 # update user data to check last activity
1147 user.update_lastactivity()
1217 user.update_lastactivity()
1148 Session().commit()
1218 Session().commit()
1149 return func(*fargs, **fkwargs)
1219 return func(*fargs, **fkwargs)
1150 else:
1220 else:
1151 log.warning(
1221 log.warning(
1152 'user %s authenticating with:%s NOT authenticated on '
1222 'user %s authenticating with:%s NOT authenticated on '
1153 'func: %s: IP_ACCESS:%s AUTH_TOKEN_ACCESS:%s'
1223 'func: %s: IP_ACCESS:%s AUTH_TOKEN_ACCESS:%s'
1154 % (user, reason, loc, ip_access_valid,
1224 % (user, reason, loc, ip_access_valid,
1155 auth_token_access_valid))
1225 auth_token_access_valid))
1156 # we preserve the get PARAM
1226 # we preserve the get PARAM
1157 came_from = request.path_qs
1227 came_from = request.path_qs
1158
1228
1159 log.debug('redirecting to login page with %s' % (came_from,))
1229 log.debug('redirecting to login page with %s' % (came_from,))
1160 return redirect(
1230 return redirect(
1161 h.route_path('login', _query={'came_from': came_from}))
1231 h.route_path('login', _query={'came_from': came_from}))
1162
1232
1163
1233
1164 class NotAnonymous(object):
1234 class NotAnonymous(object):
1165 """
1235 """
1166 Must be logged in to execute this function else
1236 Must be logged in to execute this function else
1167 redirect to login page"""
1237 redirect to login page"""
1168
1238
1169 def __call__(self, func):
1239 def __call__(self, func):
1170 return get_cython_compat_decorator(self.__wrapper, func)
1240 return get_cython_compat_decorator(self.__wrapper, func)
1171
1241
1172 def __wrapper(self, func, *fargs, **fkwargs):
1242 def __wrapper(self, func, *fargs, **fkwargs):
1173 cls = fargs[0]
1243 cls = fargs[0]
1174 self.user = cls._rhodecode_user
1244 self.user = cls._rhodecode_user
1175
1245
1176 log.debug('Checking if user is not anonymous @%s' % cls)
1246 log.debug('Checking if user is not anonymous @%s' % cls)
1177
1247
1178 anonymous = self.user.username == User.DEFAULT_USER
1248 anonymous = self.user.username == User.DEFAULT_USER
1179
1249
1180 if anonymous:
1250 if anonymous:
1181 came_from = request.path_qs
1251 came_from = request.path_qs
1182
1252
1183 import rhodecode.lib.helpers as h
1253 import rhodecode.lib.helpers as h
1184 h.flash(_('You need to be a registered user to '
1254 h.flash(_('You need to be a registered user to '
1185 'perform this action'),
1255 'perform this action'),
1186 category='warning')
1256 category='warning')
1187 return redirect(
1257 return redirect(
1188 h.route_path('login', _query={'came_from': came_from}))
1258 h.route_path('login', _query={'came_from': came_from}))
1189 else:
1259 else:
1190 return func(*fargs, **fkwargs)
1260 return func(*fargs, **fkwargs)
1191
1261
1192
1262
1193 class XHRRequired(object):
1263 class XHRRequired(object):
1194 def __call__(self, func):
1264 def __call__(self, func):
1195 return get_cython_compat_decorator(self.__wrapper, func)
1265 return get_cython_compat_decorator(self.__wrapper, func)
1196
1266
1197 def __wrapper(self, func, *fargs, **fkwargs):
1267 def __wrapper(self, func, *fargs, **fkwargs):
1198 log.debug('Checking if request is XMLHttpRequest (XHR)')
1268 log.debug('Checking if request is XMLHttpRequest (XHR)')
1199 xhr_message = 'This is not a valid XMLHttpRequest (XHR) request'
1269 xhr_message = 'This is not a valid XMLHttpRequest (XHR) request'
1200 if not request.is_xhr:
1270 if not request.is_xhr:
1201 abort(400, detail=xhr_message)
1271 abort(400, detail=xhr_message)
1202
1272
1203 return func(*fargs, **fkwargs)
1273 return func(*fargs, **fkwargs)
1204
1274
1205
1275
1206 class HasAcceptedRepoType(object):
1276 class HasAcceptedRepoType(object):
1207 """
1277 """
1208 Check if requested repo is within given repo type aliases
1278 Check if requested repo is within given repo type aliases
1209
1279
1210 TODO: anderson: not sure where to put this decorator
1280 TODO: anderson: not sure where to put this decorator
1211 """
1281 """
1212
1282
1213 def __init__(self, *repo_type_list):
1283 def __init__(self, *repo_type_list):
1214 self.repo_type_list = set(repo_type_list)
1284 self.repo_type_list = set(repo_type_list)
1215
1285
1216 def __call__(self, func):
1286 def __call__(self, func):
1217 return get_cython_compat_decorator(self.__wrapper, func)
1287 return get_cython_compat_decorator(self.__wrapper, func)
1218
1288
1219 def __wrapper(self, func, *fargs, **fkwargs):
1289 def __wrapper(self, func, *fargs, **fkwargs):
1220 cls = fargs[0]
1290 cls = fargs[0]
1221 rhodecode_repo = cls.rhodecode_repo
1291 rhodecode_repo = cls.rhodecode_repo
1222
1292
1223 log.debug('%s checking repo type for %s in %s',
1293 log.debug('%s checking repo type for %s in %s',
1224 self.__class__.__name__,
1294 self.__class__.__name__,
1225 rhodecode_repo.alias, self.repo_type_list)
1295 rhodecode_repo.alias, self.repo_type_list)
1226
1296
1227 if rhodecode_repo.alias in self.repo_type_list:
1297 if rhodecode_repo.alias in self.repo_type_list:
1228 return func(*fargs, **fkwargs)
1298 return func(*fargs, **fkwargs)
1229 else:
1299 else:
1230 import rhodecode.lib.helpers as h
1300 import rhodecode.lib.helpers as h
1231 h.flash(h.literal(
1301 h.flash(h.literal(
1232 _('Action not supported for %s.' % rhodecode_repo.alias)),
1302 _('Action not supported for %s.' % rhodecode_repo.alias)),
1233 category='warning')
1303 category='warning')
1234 return redirect(
1304 return redirect(
1235 url('summary_home', repo_name=cls.rhodecode_db_repo.repo_name))
1305 url('summary_home', repo_name=cls.rhodecode_db_repo.repo_name))
1236
1306
1237
1307
1238 class PermsDecorator(object):
1308 class PermsDecorator(object):
1239 """
1309 """
1240 Base class for controller decorators, we extract the current user from
1310 Base class for controller decorators, we extract the current user from
1241 the class itself, which has it stored in base controllers
1311 the class itself, which has it stored in base controllers
1242 """
1312 """
1243
1313
1244 def __init__(self, *required_perms):
1314 def __init__(self, *required_perms):
1245 self.required_perms = set(required_perms)
1315 self.required_perms = set(required_perms)
1246
1316
1247 def __call__(self, func):
1317 def __call__(self, func):
1248 return get_cython_compat_decorator(self.__wrapper, func)
1318 return get_cython_compat_decorator(self.__wrapper, func)
1249
1319
1250 def __wrapper(self, func, *fargs, **fkwargs):
1320 def __wrapper(self, func, *fargs, **fkwargs):
1251 cls = fargs[0]
1321 cls = fargs[0]
1252 _user = cls._rhodecode_user
1322 _user = cls._rhodecode_user
1253
1323
1254 log.debug('checking %s permissions %s for %s %s',
1324 log.debug('checking %s permissions %s for %s %s',
1255 self.__class__.__name__, self.required_perms, cls, _user)
1325 self.__class__.__name__, self.required_perms, cls, _user)
1256
1326
1257 if self.check_permissions(_user):
1327 if self.check_permissions(_user):
1258 log.debug('Permission granted for %s %s', cls, _user)
1328 log.debug('Permission granted for %s %s', cls, _user)
1259 return func(*fargs, **fkwargs)
1329 return func(*fargs, **fkwargs)
1260
1330
1261 else:
1331 else:
1262 log.debug('Permission denied for %s %s', cls, _user)
1332 log.debug('Permission denied for %s %s', cls, _user)
1263 anonymous = _user.username == User.DEFAULT_USER
1333 anonymous = _user.username == User.DEFAULT_USER
1264
1334
1265 if anonymous:
1335 if anonymous:
1266 came_from = request.path_qs
1336 came_from = request.path_qs
1267
1337
1268 import rhodecode.lib.helpers as h
1338 import rhodecode.lib.helpers as h
1269 h.flash(_('You need to be signed in to view this page'),
1339 h.flash(_('You need to be signed in to view this page'),
1270 category='warning')
1340 category='warning')
1271 return redirect(
1341 return redirect(
1272 h.route_path('login', _query={'came_from': came_from}))
1342 h.route_path('login', _query={'came_from': came_from}))
1273
1343
1274 else:
1344 else:
1275 # redirect with forbidden ret code
1345 # redirect with forbidden ret code
1276 return abort(403)
1346 return abort(403)
1277
1347
1278 def check_permissions(self, user):
1348 def check_permissions(self, user):
1279 """Dummy function for overriding"""
1349 """Dummy function for overriding"""
1280 raise NotImplementedError(
1350 raise NotImplementedError(
1281 'You have to write this function in child class')
1351 'You have to write this function in child class')
1282
1352
1283
1353
1284 class HasPermissionAllDecorator(PermsDecorator):
1354 class HasPermissionAllDecorator(PermsDecorator):
1285 """
1355 """
1286 Checks for access permission for all given predicates. All of them
1356 Checks for access permission for all given predicates. All of them
1287 have to be meet in order to fulfill the request
1357 have to be meet in order to fulfill the request
1288 """
1358 """
1289
1359
1290 def check_permissions(self, user):
1360 def check_permissions(self, user):
1291 perms = user.permissions_with_scope({})
1361 perms = user.permissions_with_scope({})
1292 if self.required_perms.issubset(perms['global']):
1362 if self.required_perms.issubset(perms['global']):
1293 return True
1363 return True
1294 return False
1364 return False
1295
1365
1296
1366
1297 class HasPermissionAnyDecorator(PermsDecorator):
1367 class HasPermissionAnyDecorator(PermsDecorator):
1298 """
1368 """
1299 Checks for access permission for any of given predicates. In order to
1369 Checks for access permission for any of given predicates. In order to
1300 fulfill the request any of predicates must be meet
1370 fulfill the request any of predicates must be meet
1301 """
1371 """
1302
1372
1303 def check_permissions(self, user):
1373 def check_permissions(self, user):
1304 perms = user.permissions_with_scope({})
1374 perms = user.permissions_with_scope({})
1305 if self.required_perms.intersection(perms['global']):
1375 if self.required_perms.intersection(perms['global']):
1306 return True
1376 return True
1307 return False
1377 return False
1308
1378
1309
1379
1310 class HasRepoPermissionAllDecorator(PermsDecorator):
1380 class HasRepoPermissionAllDecorator(PermsDecorator):
1311 """
1381 """
1312 Checks for access permission for all given predicates for specific
1382 Checks for access permission for all given predicates for specific
1313 repository. All of them have to be meet in order to fulfill the request
1383 repository. All of them have to be meet in order to fulfill the request
1314 """
1384 """
1315
1385
1316 def check_permissions(self, user):
1386 def check_permissions(self, user):
1317 perms = user.permissions
1387 perms = user.permissions
1318 repo_name = get_repo_slug(request)
1388 repo_name = get_repo_slug(request)
1319 try:
1389 try:
1320 user_perms = set([perms['repositories'][repo_name]])
1390 user_perms = set([perms['repositories'][repo_name]])
1321 except KeyError:
1391 except KeyError:
1322 return False
1392 return False
1323 if self.required_perms.issubset(user_perms):
1393 if self.required_perms.issubset(user_perms):
1324 return True
1394 return True
1325 return False
1395 return False
1326
1396
1327
1397
1328 class HasRepoPermissionAnyDecorator(PermsDecorator):
1398 class HasRepoPermissionAnyDecorator(PermsDecorator):
1329 """
1399 """
1330 Checks for access permission for any of given predicates for specific
1400 Checks for access permission for any of given predicates for specific
1331 repository. In order to fulfill the request any of predicates must be meet
1401 repository. In order to fulfill the request any of predicates must be meet
1332 """
1402 """
1333
1403
1334 def check_permissions(self, user):
1404 def check_permissions(self, user):
1335 perms = user.permissions
1405 perms = user.permissions
1336 repo_name = get_repo_slug(request)
1406 repo_name = get_repo_slug(request)
1337 try:
1407 try:
1338 user_perms = set([perms['repositories'][repo_name]])
1408 user_perms = set([perms['repositories'][repo_name]])
1339 except KeyError:
1409 except KeyError:
1340 return False
1410 return False
1341
1411
1342 if self.required_perms.intersection(user_perms):
1412 if self.required_perms.intersection(user_perms):
1343 return True
1413 return True
1344 return False
1414 return False
1345
1415
1346
1416
1347 class HasRepoGroupPermissionAllDecorator(PermsDecorator):
1417 class HasRepoGroupPermissionAllDecorator(PermsDecorator):
1348 """
1418 """
1349 Checks for access permission for all given predicates for specific
1419 Checks for access permission for all given predicates for specific
1350 repository group. All of them have to be meet in order to
1420 repository group. All of them have to be meet in order to
1351 fulfill the request
1421 fulfill the request
1352 """
1422 """
1353
1423
1354 def check_permissions(self, user):
1424 def check_permissions(self, user):
1355 perms = user.permissions
1425 perms = user.permissions
1356 group_name = get_repo_group_slug(request)
1426 group_name = get_repo_group_slug(request)
1357 try:
1427 try:
1358 user_perms = set([perms['repositories_groups'][group_name]])
1428 user_perms = set([perms['repositories_groups'][group_name]])
1359 except KeyError:
1429 except KeyError:
1360 return False
1430 return False
1361
1431
1362 if self.required_perms.issubset(user_perms):
1432 if self.required_perms.issubset(user_perms):
1363 return True
1433 return True
1364 return False
1434 return False
1365
1435
1366
1436
1367 class HasRepoGroupPermissionAnyDecorator(PermsDecorator):
1437 class HasRepoGroupPermissionAnyDecorator(PermsDecorator):
1368 """
1438 """
1369 Checks for access permission for any of given predicates for specific
1439 Checks for access permission for any of given predicates for specific
1370 repository group. In order to fulfill the request any
1440 repository group. In order to fulfill the request any
1371 of predicates must be met
1441 of predicates must be met
1372 """
1442 """
1373
1443
1374 def check_permissions(self, user):
1444 def check_permissions(self, user):
1375 perms = user.permissions
1445 perms = user.permissions
1376 group_name = get_repo_group_slug(request)
1446 group_name = get_repo_group_slug(request)
1377 try:
1447 try:
1378 user_perms = set([perms['repositories_groups'][group_name]])
1448 user_perms = set([perms['repositories_groups'][group_name]])
1379 except KeyError:
1449 except KeyError:
1380 return False
1450 return False
1381
1451
1382 if self.required_perms.intersection(user_perms):
1452 if self.required_perms.intersection(user_perms):
1383 return True
1453 return True
1384 return False
1454 return False
1385
1455
1386
1456
1387 class HasUserGroupPermissionAllDecorator(PermsDecorator):
1457 class HasUserGroupPermissionAllDecorator(PermsDecorator):
1388 """
1458 """
1389 Checks for access permission for all given predicates for specific
1459 Checks for access permission for all given predicates for specific
1390 user group. All of them have to be meet in order to fulfill the request
1460 user group. All of them have to be meet in order to fulfill the request
1391 """
1461 """
1392
1462
1393 def check_permissions(self, user):
1463 def check_permissions(self, user):
1394 perms = user.permissions
1464 perms = user.permissions
1395 group_name = get_user_group_slug(request)
1465 group_name = get_user_group_slug(request)
1396 try:
1466 try:
1397 user_perms = set([perms['user_groups'][group_name]])
1467 user_perms = set([perms['user_groups'][group_name]])
1398 except KeyError:
1468 except KeyError:
1399 return False
1469 return False
1400
1470
1401 if self.required_perms.issubset(user_perms):
1471 if self.required_perms.issubset(user_perms):
1402 return True
1472 return True
1403 return False
1473 return False
1404
1474
1405
1475
1406 class HasUserGroupPermissionAnyDecorator(PermsDecorator):
1476 class HasUserGroupPermissionAnyDecorator(PermsDecorator):
1407 """
1477 """
1408 Checks for access permission for any of given predicates for specific
1478 Checks for access permission for any of given predicates for specific
1409 user group. In order to fulfill the request any of predicates must be meet
1479 user group. In order to fulfill the request any of predicates must be meet
1410 """
1480 """
1411
1481
1412 def check_permissions(self, user):
1482 def check_permissions(self, user):
1413 perms = user.permissions
1483 perms = user.permissions
1414 group_name = get_user_group_slug(request)
1484 group_name = get_user_group_slug(request)
1415 try:
1485 try:
1416 user_perms = set([perms['user_groups'][group_name]])
1486 user_perms = set([perms['user_groups'][group_name]])
1417 except KeyError:
1487 except KeyError:
1418 return False
1488 return False
1419
1489
1420 if self.required_perms.intersection(user_perms):
1490 if self.required_perms.intersection(user_perms):
1421 return True
1491 return True
1422 return False
1492 return False
1423
1493
1424
1494
1425 # CHECK FUNCTIONS
1495 # CHECK FUNCTIONS
1426 class PermsFunction(object):
1496 class PermsFunction(object):
1427 """Base function for other check functions"""
1497 """Base function for other check functions"""
1428
1498
1429 def __init__(self, *perms):
1499 def __init__(self, *perms):
1430 self.required_perms = set(perms)
1500 self.required_perms = set(perms)
1431 self.repo_name = None
1501 self.repo_name = None
1432 self.repo_group_name = None
1502 self.repo_group_name = None
1433 self.user_group_name = None
1503 self.user_group_name = None
1434
1504
1435 def __bool__(self):
1505 def __bool__(self):
1436 frame = inspect.currentframe()
1506 frame = inspect.currentframe()
1437 stack_trace = traceback.format_stack(frame)
1507 stack_trace = traceback.format_stack(frame)
1438 log.error('Checking bool value on a class instance of perm '
1508 log.error('Checking bool value on a class instance of perm '
1439 'function is not allowed: %s' % ''.join(stack_trace))
1509 'function is not allowed: %s' % ''.join(stack_trace))
1440 # rather than throwing errors, here we always return False so if by
1510 # rather than throwing errors, here we always return False so if by
1441 # accident someone checks truth for just an instance it will always end
1511 # accident someone checks truth for just an instance it will always end
1442 # up in returning False
1512 # up in returning False
1443 return False
1513 return False
1444 __nonzero__ = __bool__
1514 __nonzero__ = __bool__
1445
1515
1446 def __call__(self, check_location='', user=None):
1516 def __call__(self, check_location='', user=None):
1447 if not user:
1517 if not user:
1448 log.debug('Using user attribute from global request')
1518 log.debug('Using user attribute from global request')
1449 # TODO: remove this someday,put as user as attribute here
1519 # TODO: remove this someday,put as user as attribute here
1450 user = request.user
1520 user = request.user
1451
1521
1452 # init auth user if not already given
1522 # init auth user if not already given
1453 if not isinstance(user, AuthUser):
1523 if not isinstance(user, AuthUser):
1454 log.debug('Wrapping user %s into AuthUser', user)
1524 log.debug('Wrapping user %s into AuthUser', user)
1455 user = AuthUser(user.user_id)
1525 user = AuthUser(user.user_id)
1456
1526
1457 cls_name = self.__class__.__name__
1527 cls_name = self.__class__.__name__
1458 check_scope = self._get_check_scope(cls_name)
1528 check_scope = self._get_check_scope(cls_name)
1459 check_location = check_location or 'unspecified location'
1529 check_location = check_location or 'unspecified location'
1460
1530
1461 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
1531 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
1462 self.required_perms, user, check_scope, check_location)
1532 self.required_perms, user, check_scope, check_location)
1463 if not user:
1533 if not user:
1464 log.warning('Empty user given for permission check')
1534 log.warning('Empty user given for permission check')
1465 return False
1535 return False
1466
1536
1467 if self.check_permissions(user):
1537 if self.check_permissions(user):
1468 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1538 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1469 check_scope, user, check_location)
1539 check_scope, user, check_location)
1470 return True
1540 return True
1471
1541
1472 else:
1542 else:
1473 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1543 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1474 check_scope, user, check_location)
1544 check_scope, user, check_location)
1475 return False
1545 return False
1476
1546
1477 def _get_check_scope(self, cls_name):
1547 def _get_check_scope(self, cls_name):
1478 return {
1548 return {
1479 'HasPermissionAll': 'GLOBAL',
1549 'HasPermissionAll': 'GLOBAL',
1480 'HasPermissionAny': 'GLOBAL',
1550 'HasPermissionAny': 'GLOBAL',
1481 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
1551 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
1482 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
1552 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
1483 'HasRepoGroupPermissionAll': 'repo_group:%s' % self.repo_group_name,
1553 'HasRepoGroupPermissionAll': 'repo_group:%s' % self.repo_group_name,
1484 'HasRepoGroupPermissionAny': 'repo_group:%s' % self.repo_group_name,
1554 'HasRepoGroupPermissionAny': 'repo_group:%s' % self.repo_group_name,
1485 'HasUserGroupPermissionAll': 'user_group:%s' % self.user_group_name,
1555 'HasUserGroupPermissionAll': 'user_group:%s' % self.user_group_name,
1486 'HasUserGroupPermissionAny': 'user_group:%s' % self.user_group_name,
1556 'HasUserGroupPermissionAny': 'user_group:%s' % self.user_group_name,
1487 }.get(cls_name, '?:%s' % cls_name)
1557 }.get(cls_name, '?:%s' % cls_name)
1488
1558
1489 def check_permissions(self, user):
1559 def check_permissions(self, user):
1490 """Dummy function for overriding"""
1560 """Dummy function for overriding"""
1491 raise Exception('You have to write this function in child class')
1561 raise Exception('You have to write this function in child class')
1492
1562
1493
1563
1494 class HasPermissionAll(PermsFunction):
1564 class HasPermissionAll(PermsFunction):
1495 def check_permissions(self, user):
1565 def check_permissions(self, user):
1496 perms = user.permissions_with_scope({})
1566 perms = user.permissions_with_scope({})
1497 if self.required_perms.issubset(perms.get('global')):
1567 if self.required_perms.issubset(perms.get('global')):
1498 return True
1568 return True
1499 return False
1569 return False
1500
1570
1501
1571
1502 class HasPermissionAny(PermsFunction):
1572 class HasPermissionAny(PermsFunction):
1503 def check_permissions(self, user):
1573 def check_permissions(self, user):
1504 perms = user.permissions_with_scope({})
1574 perms = user.permissions_with_scope({})
1505 if self.required_perms.intersection(perms.get('global')):
1575 if self.required_perms.intersection(perms.get('global')):
1506 return True
1576 return True
1507 return False
1577 return False
1508
1578
1509
1579
1510 class HasRepoPermissionAll(PermsFunction):
1580 class HasRepoPermissionAll(PermsFunction):
1511 def __call__(self, repo_name=None, check_location='', user=None):
1581 def __call__(self, repo_name=None, check_location='', user=None):
1512 self.repo_name = repo_name
1582 self.repo_name = repo_name
1513 return super(HasRepoPermissionAll, self).__call__(check_location, user)
1583 return super(HasRepoPermissionAll, self).__call__(check_location, user)
1514
1584
1515 def check_permissions(self, user):
1585 def check_permissions(self, user):
1516 if not self.repo_name:
1586 if not self.repo_name:
1517 self.repo_name = get_repo_slug(request)
1587 self.repo_name = get_repo_slug(request)
1518
1588
1519 perms = user.permissions
1589 perms = user.permissions
1520 try:
1590 try:
1521 user_perms = set([perms['repositories'][self.repo_name]])
1591 user_perms = set([perms['repositories'][self.repo_name]])
1522 except KeyError:
1592 except KeyError:
1523 return False
1593 return False
1524 if self.required_perms.issubset(user_perms):
1594 if self.required_perms.issubset(user_perms):
1525 return True
1595 return True
1526 return False
1596 return False
1527
1597
1528
1598
1529 class HasRepoPermissionAny(PermsFunction):
1599 class HasRepoPermissionAny(PermsFunction):
1530 def __call__(self, repo_name=None, check_location='', user=None):
1600 def __call__(self, repo_name=None, check_location='', user=None):
1531 self.repo_name = repo_name
1601 self.repo_name = repo_name
1532 return super(HasRepoPermissionAny, self).__call__(check_location, user)
1602 return super(HasRepoPermissionAny, self).__call__(check_location, user)
1533
1603
1534 def check_permissions(self, user):
1604 def check_permissions(self, user):
1535 if not self.repo_name:
1605 if not self.repo_name:
1536 self.repo_name = get_repo_slug(request)
1606 self.repo_name = get_repo_slug(request)
1537
1607
1538 perms = user.permissions
1608 perms = user.permissions
1539 try:
1609 try:
1540 user_perms = set([perms['repositories'][self.repo_name]])
1610 user_perms = set([perms['repositories'][self.repo_name]])
1541 except KeyError:
1611 except KeyError:
1542 return False
1612 return False
1543 if self.required_perms.intersection(user_perms):
1613 if self.required_perms.intersection(user_perms):
1544 return True
1614 return True
1545 return False
1615 return False
1546
1616
1547
1617
1548 class HasRepoGroupPermissionAny(PermsFunction):
1618 class HasRepoGroupPermissionAny(PermsFunction):
1549 def __call__(self, group_name=None, check_location='', user=None):
1619 def __call__(self, group_name=None, check_location='', user=None):
1550 self.repo_group_name = group_name
1620 self.repo_group_name = group_name
1551 return super(HasRepoGroupPermissionAny, self).__call__(
1621 return super(HasRepoGroupPermissionAny, self).__call__(
1552 check_location, user)
1622 check_location, user)
1553
1623
1554 def check_permissions(self, user):
1624 def check_permissions(self, user):
1555 perms = user.permissions
1625 perms = user.permissions
1556 try:
1626 try:
1557 user_perms = set(
1627 user_perms = set(
1558 [perms['repositories_groups'][self.repo_group_name]])
1628 [perms['repositories_groups'][self.repo_group_name]])
1559 except KeyError:
1629 except KeyError:
1560 return False
1630 return False
1561 if self.required_perms.intersection(user_perms):
1631 if self.required_perms.intersection(user_perms):
1562 return True
1632 return True
1563 return False
1633 return False
1564
1634
1565
1635
1566 class HasRepoGroupPermissionAll(PermsFunction):
1636 class HasRepoGroupPermissionAll(PermsFunction):
1567 def __call__(self, group_name=None, check_location='', user=None):
1637 def __call__(self, group_name=None, check_location='', user=None):
1568 self.repo_group_name = group_name
1638 self.repo_group_name = group_name
1569 return super(HasRepoGroupPermissionAll, self).__call__(
1639 return super(HasRepoGroupPermissionAll, self).__call__(
1570 check_location, user)
1640 check_location, user)
1571
1641
1572 def check_permissions(self, user):
1642 def check_permissions(self, user):
1573 perms = user.permissions
1643 perms = user.permissions
1574 try:
1644 try:
1575 user_perms = set(
1645 user_perms = set(
1576 [perms['repositories_groups'][self.repo_group_name]])
1646 [perms['repositories_groups'][self.repo_group_name]])
1577 except KeyError:
1647 except KeyError:
1578 return False
1648 return False
1579 if self.required_perms.issubset(user_perms):
1649 if self.required_perms.issubset(user_perms):
1580 return True
1650 return True
1581 return False
1651 return False
1582
1652
1583
1653
1584 class HasUserGroupPermissionAny(PermsFunction):
1654 class HasUserGroupPermissionAny(PermsFunction):
1585 def __call__(self, user_group_name=None, check_location='', user=None):
1655 def __call__(self, user_group_name=None, check_location='', user=None):
1586 self.user_group_name = user_group_name
1656 self.user_group_name = user_group_name
1587 return super(HasUserGroupPermissionAny, self).__call__(
1657 return super(HasUserGroupPermissionAny, self).__call__(
1588 check_location, user)
1658 check_location, user)
1589
1659
1590 def check_permissions(self, user):
1660 def check_permissions(self, user):
1591 perms = user.permissions
1661 perms = user.permissions
1592 try:
1662 try:
1593 user_perms = set([perms['user_groups'][self.user_group_name]])
1663 user_perms = set([perms['user_groups'][self.user_group_name]])
1594 except KeyError:
1664 except KeyError:
1595 return False
1665 return False
1596 if self.required_perms.intersection(user_perms):
1666 if self.required_perms.intersection(user_perms):
1597 return True
1667 return True
1598 return False
1668 return False
1599
1669
1600
1670
1601 class HasUserGroupPermissionAll(PermsFunction):
1671 class HasUserGroupPermissionAll(PermsFunction):
1602 def __call__(self, user_group_name=None, check_location='', user=None):
1672 def __call__(self, user_group_name=None, check_location='', user=None):
1603 self.user_group_name = user_group_name
1673 self.user_group_name = user_group_name
1604 return super(HasUserGroupPermissionAll, self).__call__(
1674 return super(HasUserGroupPermissionAll, self).__call__(
1605 check_location, user)
1675 check_location, user)
1606
1676
1607 def check_permissions(self, user):
1677 def check_permissions(self, user):
1608 perms = user.permissions
1678 perms = user.permissions
1609 try:
1679 try:
1610 user_perms = set([perms['user_groups'][self.user_group_name]])
1680 user_perms = set([perms['user_groups'][self.user_group_name]])
1611 except KeyError:
1681 except KeyError:
1612 return False
1682 return False
1613 if self.required_perms.issubset(user_perms):
1683 if self.required_perms.issubset(user_perms):
1614 return True
1684 return True
1615 return False
1685 return False
1616
1686
1617
1687
1618 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
1688 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
1619 class HasPermissionAnyMiddleware(object):
1689 class HasPermissionAnyMiddleware(object):
1620 def __init__(self, *perms):
1690 def __init__(self, *perms):
1621 self.required_perms = set(perms)
1691 self.required_perms = set(perms)
1622
1692
1623 def __call__(self, user, repo_name):
1693 def __call__(self, user, repo_name):
1624 # repo_name MUST be unicode, since we handle keys in permission
1694 # repo_name MUST be unicode, since we handle keys in permission
1625 # dict by unicode
1695 # dict by unicode
1626 repo_name = safe_unicode(repo_name)
1696 repo_name = safe_unicode(repo_name)
1627 user = AuthUser(user.user_id)
1697 user = AuthUser(user.user_id)
1628 log.debug(
1698 log.debug(
1629 'Checking VCS protocol permissions %s for user:%s repo:`%s`',
1699 'Checking VCS protocol permissions %s for user:%s repo:`%s`',
1630 self.required_perms, user, repo_name)
1700 self.required_perms, user, repo_name)
1631
1701
1632 if self.check_permissions(user, repo_name):
1702 if self.check_permissions(user, repo_name):
1633 log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s',
1703 log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s',
1634 repo_name, user, 'PermissionMiddleware')
1704 repo_name, user, 'PermissionMiddleware')
1635 return True
1705 return True
1636
1706
1637 else:
1707 else:
1638 log.debug('Permission to repo:`%s` DENIED for user:%s @ %s',
1708 log.debug('Permission to repo:`%s` DENIED for user:%s @ %s',
1639 repo_name, user, 'PermissionMiddleware')
1709 repo_name, user, 'PermissionMiddleware')
1640 return False
1710 return False
1641
1711
1642 def check_permissions(self, user, repo_name):
1712 def check_permissions(self, user, repo_name):
1643 perms = user.permissions_with_scope({'repo_name': repo_name})
1713 perms = user.permissions_with_scope({'repo_name': repo_name})
1644
1714
1645 try:
1715 try:
1646 user_perms = set([perms['repositories'][repo_name]])
1716 user_perms = set([perms['repositories'][repo_name]])
1647 except Exception:
1717 except Exception:
1648 log.exception('Error while accessing user permissions')
1718 log.exception('Error while accessing user permissions')
1649 return False
1719 return False
1650
1720
1651 if self.required_perms.intersection(user_perms):
1721 if self.required_perms.intersection(user_perms):
1652 return True
1722 return True
1653 return False
1723 return False
1654
1724
1655
1725
1656 # SPECIAL VERSION TO HANDLE API AUTH
1726 # SPECIAL VERSION TO HANDLE API AUTH
1657 class _BaseApiPerm(object):
1727 class _BaseApiPerm(object):
1658 def __init__(self, *perms):
1728 def __init__(self, *perms):
1659 self.required_perms = set(perms)
1729 self.required_perms = set(perms)
1660
1730
1661 def __call__(self, check_location=None, user=None, repo_name=None,
1731 def __call__(self, check_location=None, user=None, repo_name=None,
1662 group_name=None, user_group_name=None):
1732 group_name=None, user_group_name=None):
1663 cls_name = self.__class__.__name__
1733 cls_name = self.__class__.__name__
1664 check_scope = 'global:%s' % (self.required_perms,)
1734 check_scope = 'global:%s' % (self.required_perms,)
1665 if repo_name:
1735 if repo_name:
1666 check_scope += ', repo_name:%s' % (repo_name,)
1736 check_scope += ', repo_name:%s' % (repo_name,)
1667
1737
1668 if group_name:
1738 if group_name:
1669 check_scope += ', repo_group_name:%s' % (group_name,)
1739 check_scope += ', repo_group_name:%s' % (group_name,)
1670
1740
1671 if user_group_name:
1741 if user_group_name:
1672 check_scope += ', user_group_name:%s' % (user_group_name,)
1742 check_scope += ', user_group_name:%s' % (user_group_name,)
1673
1743
1674 log.debug(
1744 log.debug(
1675 'checking cls:%s %s %s @ %s'
1745 'checking cls:%s %s %s @ %s'
1676 % (cls_name, self.required_perms, check_scope, check_location))
1746 % (cls_name, self.required_perms, check_scope, check_location))
1677 if not user:
1747 if not user:
1678 log.debug('Empty User passed into arguments')
1748 log.debug('Empty User passed into arguments')
1679 return False
1749 return False
1680
1750
1681 # process user
1751 # process user
1682 if not isinstance(user, AuthUser):
1752 if not isinstance(user, AuthUser):
1683 user = AuthUser(user.user_id)
1753 user = AuthUser(user.user_id)
1684 if not check_location:
1754 if not check_location:
1685 check_location = 'unspecified'
1755 check_location = 'unspecified'
1686 if self.check_permissions(user.permissions, repo_name, group_name,
1756 if self.check_permissions(user.permissions, repo_name, group_name,
1687 user_group_name):
1757 user_group_name):
1688 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1758 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1689 check_scope, user, check_location)
1759 check_scope, user, check_location)
1690 return True
1760 return True
1691
1761
1692 else:
1762 else:
1693 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1763 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1694 check_scope, user, check_location)
1764 check_scope, user, check_location)
1695 return False
1765 return False
1696
1766
1697 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1767 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1698 user_group_name=None):
1768 user_group_name=None):
1699 """
1769 """
1700 implement in child class should return True if permissions are ok,
1770 implement in child class should return True if permissions are ok,
1701 False otherwise
1771 False otherwise
1702
1772
1703 :param perm_defs: dict with permission definitions
1773 :param perm_defs: dict with permission definitions
1704 :param repo_name: repo name
1774 :param repo_name: repo name
1705 """
1775 """
1706 raise NotImplementedError()
1776 raise NotImplementedError()
1707
1777
1708
1778
1709 class HasPermissionAllApi(_BaseApiPerm):
1779 class HasPermissionAllApi(_BaseApiPerm):
1710 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1780 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1711 user_group_name=None):
1781 user_group_name=None):
1712 if self.required_perms.issubset(perm_defs.get('global')):
1782 if self.required_perms.issubset(perm_defs.get('global')):
1713 return True
1783 return True
1714 return False
1784 return False
1715
1785
1716
1786
1717 class HasPermissionAnyApi(_BaseApiPerm):
1787 class HasPermissionAnyApi(_BaseApiPerm):
1718 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1788 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1719 user_group_name=None):
1789 user_group_name=None):
1720 if self.required_perms.intersection(perm_defs.get('global')):
1790 if self.required_perms.intersection(perm_defs.get('global')):
1721 return True
1791 return True
1722 return False
1792 return False
1723
1793
1724
1794
1725 class HasRepoPermissionAllApi(_BaseApiPerm):
1795 class HasRepoPermissionAllApi(_BaseApiPerm):
1726 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1796 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1727 user_group_name=None):
1797 user_group_name=None):
1728 try:
1798 try:
1729 _user_perms = set([perm_defs['repositories'][repo_name]])
1799 _user_perms = set([perm_defs['repositories'][repo_name]])
1730 except KeyError:
1800 except KeyError:
1731 log.warning(traceback.format_exc())
1801 log.warning(traceback.format_exc())
1732 return False
1802 return False
1733 if self.required_perms.issubset(_user_perms):
1803 if self.required_perms.issubset(_user_perms):
1734 return True
1804 return True
1735 return False
1805 return False
1736
1806
1737
1807
1738 class HasRepoPermissionAnyApi(_BaseApiPerm):
1808 class HasRepoPermissionAnyApi(_BaseApiPerm):
1739 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1809 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1740 user_group_name=None):
1810 user_group_name=None):
1741 try:
1811 try:
1742 _user_perms = set([perm_defs['repositories'][repo_name]])
1812 _user_perms = set([perm_defs['repositories'][repo_name]])
1743 except KeyError:
1813 except KeyError:
1744 log.warning(traceback.format_exc())
1814 log.warning(traceback.format_exc())
1745 return False
1815 return False
1746 if self.required_perms.intersection(_user_perms):
1816 if self.required_perms.intersection(_user_perms):
1747 return True
1817 return True
1748 return False
1818 return False
1749
1819
1750
1820
1751 class HasRepoGroupPermissionAnyApi(_BaseApiPerm):
1821 class HasRepoGroupPermissionAnyApi(_BaseApiPerm):
1752 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1822 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1753 user_group_name=None):
1823 user_group_name=None):
1754 try:
1824 try:
1755 _user_perms = set([perm_defs['repositories_groups'][group_name]])
1825 _user_perms = set([perm_defs['repositories_groups'][group_name]])
1756 except KeyError:
1826 except KeyError:
1757 log.warning(traceback.format_exc())
1827 log.warning(traceback.format_exc())
1758 return False
1828 return False
1759 if self.required_perms.intersection(_user_perms):
1829 if self.required_perms.intersection(_user_perms):
1760 return True
1830 return True
1761 return False
1831 return False
1762
1832
1763
1833
1764 class HasRepoGroupPermissionAllApi(_BaseApiPerm):
1834 class HasRepoGroupPermissionAllApi(_BaseApiPerm):
1765 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1835 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1766 user_group_name=None):
1836 user_group_name=None):
1767 try:
1837 try:
1768 _user_perms = set([perm_defs['repositories_groups'][group_name]])
1838 _user_perms = set([perm_defs['repositories_groups'][group_name]])
1769 except KeyError:
1839 except KeyError:
1770 log.warning(traceback.format_exc())
1840 log.warning(traceback.format_exc())
1771 return False
1841 return False
1772 if self.required_perms.issubset(_user_perms):
1842 if self.required_perms.issubset(_user_perms):
1773 return True
1843 return True
1774 return False
1844 return False
1775
1845
1776
1846
1777 class HasUserGroupPermissionAnyApi(_BaseApiPerm):
1847 class HasUserGroupPermissionAnyApi(_BaseApiPerm):
1778 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1848 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1779 user_group_name=None):
1849 user_group_name=None):
1780 try:
1850 try:
1781 _user_perms = set([perm_defs['user_groups'][user_group_name]])
1851 _user_perms = set([perm_defs['user_groups'][user_group_name]])
1782 except KeyError:
1852 except KeyError:
1783 log.warning(traceback.format_exc())
1853 log.warning(traceback.format_exc())
1784 return False
1854 return False
1785 if self.required_perms.intersection(_user_perms):
1855 if self.required_perms.intersection(_user_perms):
1786 return True
1856 return True
1787 return False
1857 return False
1788
1858
1789
1859
1790 def check_ip_access(source_ip, allowed_ips=None):
1860 def check_ip_access(source_ip, allowed_ips=None):
1791 """
1861 """
1792 Checks if source_ip is a subnet of any of allowed_ips.
1862 Checks if source_ip is a subnet of any of allowed_ips.
1793
1863
1794 :param source_ip:
1864 :param source_ip:
1795 :param allowed_ips: list of allowed ips together with mask
1865 :param allowed_ips: list of allowed ips together with mask
1796 """
1866 """
1797 log.debug('checking if ip:%s is subnet of %s' % (source_ip, allowed_ips))
1867 log.debug('checking if ip:%s is subnet of %s' % (source_ip, allowed_ips))
1798 source_ip_address = ipaddress.ip_address(source_ip)
1868 source_ip_address = ipaddress.ip_address(source_ip)
1799 if isinstance(allowed_ips, (tuple, list, set)):
1869 if isinstance(allowed_ips, (tuple, list, set)):
1800 for ip in allowed_ips:
1870 for ip in allowed_ips:
1801 try:
1871 try:
1802 network_address = ipaddress.ip_network(ip, strict=False)
1872 network_address = ipaddress.ip_network(ip, strict=False)
1803 if source_ip_address in network_address:
1873 if source_ip_address in network_address:
1804 log.debug('IP %s is network %s' %
1874 log.debug('IP %s is network %s' %
1805 (source_ip_address, network_address))
1875 (source_ip_address, network_address))
1806 return True
1876 return True
1807 # for any case we cannot determine the IP, don't crash just
1877 # for any case we cannot determine the IP, don't crash just
1808 # skip it and log as error, we want to say forbidden still when
1878 # skip it and log as error, we want to say forbidden still when
1809 # sending bad IP
1879 # sending bad IP
1810 except Exception:
1880 except Exception:
1811 log.error(traceback.format_exc())
1881 log.error(traceback.format_exc())
1812 continue
1882 continue
1813 return False
1883 return False
1814
1884
1815
1885
1816 def get_cython_compat_decorator(wrapper, func):
1886 def get_cython_compat_decorator(wrapper, func):
1817 """
1887 """
1818 Creates a cython compatible decorator. The previously used
1888 Creates a cython compatible decorator. The previously used
1819 decorator.decorator() function seems to be incompatible with cython.
1889 decorator.decorator() function seems to be incompatible with cython.
1820
1890
1821 :param wrapper: __wrapper method of the decorator class
1891 :param wrapper: __wrapper method of the decorator class
1822 :param func: decorated function
1892 :param func: decorated function
1823 """
1893 """
1824 @wraps(func)
1894 @wraps(func)
1825 def local_wrapper(*args, **kwds):
1895 def local_wrapper(*args, **kwds):
1826 return wrapper(func, *args, **kwds)
1896 return wrapper(func, *args, **kwds)
1827 local_wrapper.__wrapped__ = func
1897 local_wrapper.__wrapped__ = func
1828 return local_wrapper
1898 return local_wrapper
@@ -1,96 +1,101 b''
1 // tags.less
1 // tags.less
2 // For use in RhodeCode applications;
2 // For use in RhodeCode applications;
3 // see style guide documentation for guidelines.
3 // see style guide documentation for guidelines.
4
4
5 // TAGS
5 // TAGS
6 .tag,
6 .tag,
7 .tagtag {
7 .tagtag {
8 display: inline-block;
8 display: inline-block;
9 min-height: 0;
9 min-height: 0;
10 margin: 0 auto;
10 margin: 0 auto;
11 padding: .25em;
11 padding: .25em;
12 text-align: center;
12 text-align: center;
13 font-size: (-1 + @basefontsize); //fit in tables
13 font-size: (-1 + @basefontsize); //fit in tables
14 line-height: .9em;
14 line-height: .9em;
15 border: none;
15 border: none;
16 .border-radius(@border-radius);
16 .border-radius(@border-radius);
17 font-family: @text-regular;
17 font-family: @text-regular;
18 background-image: none;
18 background-image: none;
19 color: @grey4;
19 color: @grey4;
20 .border ( @border-thickness-tags, @grey4 );
20 .border ( @border-thickness-tags, @grey4 );
21 white-space: nowrap;
21 white-space: nowrap;
22 a {
22 a {
23 color: inherit;
23 color: inherit;
24 text-decoration: underline;
24 text-decoration: underline;
25
25
26 i,
26 i,
27 [class^="icon-"]:before,
27 [class^="icon-"]:before,
28 [class*=" icon-"]:before {
28 [class*=" icon-"]:before {
29 text-decoration: none;
29 text-decoration: none;
30 }
30 }
31 }
31 }
32 }
32 }
33
33
34 .tag0 { .border ( @border-thickness-tags, @grey4 ); color:@grey4; }
34 .tag0 { .border ( @border-thickness-tags, @grey4 ); color:@grey4; }
35 .tag1 { .border ( @border-thickness-tags, @color1 ); color:@color1; }
35 .tag1 { .border ( @border-thickness-tags, @color1 ); color:@color1; }
36 .tag2 { .border ( @border-thickness-tags, @color2 ); color:@color2; }
36 .tag2 { .border ( @border-thickness-tags, @color2 ); color:@color2; }
37 .tag3 { .border ( @border-thickness-tags, @color3 ); color:@color3; }
37 .tag3 { .border ( @border-thickness-tags, @color3 ); color:@color3; }
38 .tag4 { .border ( @border-thickness-tags, @color4 ); color:@color4; }
38 .tag4 { .border ( @border-thickness-tags, @color4 ); color:@color4; }
39 .tag5 { .border ( @border-thickness-tags, @color5 ); color:@color5; }
39 .tag5 { .border ( @border-thickness-tags, @color5 ); color:@color5; }
40 .tag6 { .border ( @border-thickness-tags, @color6 ); color:@color6; }
40 .tag6 { .border ( @border-thickness-tags, @color6 ); color:@color6; }
41 .tag7 { .border ( @border-thickness-tags, @color7 ); color:@color7; }
41 .tag7 { .border ( @border-thickness-tags, @color7 ); color:@color7; }
42 .tag8 { .border ( @border-thickness-tags, @color8 ); color:@color8; }
42 .tag8 { .border ( @border-thickness-tags, @color8 ); color:@color8; }
43
43
44 .metatag-list {
44 .metatag-list {
45 margin: 0;
45 margin: 0;
46 padding: 0;
46 padding: 0;
47
47
48 li {
48 li {
49 margin: 0 0 @padding;
49 margin: 0 0 @padding;
50 line-height: 1em;
50 line-height: 1em;
51 list-style-type: none;
51 list-style-type: none;
52
52
53 &:before { content: none; }
53 &:before { content: none; }
54 }
54 }
55 }
55 }
56
56
57 .branchtag, .booktag {
57 .branchtag, .booktag {
58 &:extend(.tag);
58 &:extend(.tag);
59
59
60
60
61 a {
61 a {
62 color:inherit;
62 color:inherit;
63 }
63 }
64 }
64 }
65
65
66 .metatag {
66 .metatag {
67 &:extend(.tag);
67 &:extend(.tag);
68 a {
68 a {
69 color:inherit;
69 color:inherit;
70 text-decoration: underline;
70 text-decoration: underline;
71 }
71 }
72 }
72 }
73
73
74 [tag="featured"] { &:extend(.tag1); }
74 [tag="featured"] { &:extend(.tag1); }
75 [tag="stale"] { &:extend(.tag2); }
75 [tag="stale"] { &:extend(.tag2); }
76 [tag="dead"] { &:extend(.tag3); }
76 [tag="dead"] { &:extend(.tag3); }
77 [tag="lang"] { &:extend(.tag4); }
77 [tag="lang"] { &:extend(.tag4); }
78 [tag="license"] { &:extend(.tag5); }
78 [tag="license"] { &:extend(.tag5); }
79 [tag="requires"] { &:extend(.tag6); }
79 [tag="requires"] { &:extend(.tag6); }
80 [tag="recommends"] { &:extend(.tag7); }
80 [tag="recommends"] { &:extend(.tag7); }
81 [tag="see"] { &:extend(.tag8); }
81 [tag="see"] { &:extend(.tag8); }
82
82
83 .perm_overriden {
84 text-decoration: line-through;
85 opacity: 0.6;
86 }
87
83 .perm_tag {
88 .perm_tag {
84 &:extend(.tag);
89 &:extend(.tag);
85
90
86 &.read {
91 &.read {
87 &:extend(.tag1);
92 &:extend(.tag1);
88 }
93 }
89
94
90 &.write {
95 &.write {
91 &:extend(.tag4);
96 &:extend(.tag4);
92 }
97 }
93 &.admin {
98 &.admin {
94 &:extend(.tag5);
99 &:extend(.tag5);
95 }
100 }
96 } No newline at end of file
101 }
@@ -1,200 +1,207 b''
1 ## snippet for displaying permissions overview for users
1 ## snippet for displaying permissions overview for users
2 ## usage:
2 ## usage:
3 ## <%namespace name="p" file="/base/perms_summary.html"/>
3 ## <%namespace name="p" file="/base/perms_summary.html"/>
4 ## ${p.perms_summary(c.perm_user.permissions)}
4 ## ${p.perms_summary(c.perm_user.permissions)}
5
5
6 <%def name="perms_summary(permissions, show_all=False, actions=True)">
6 <%def name="perms_summary(permissions, show_all=False, actions=True)">
7
8 <div id="perms" class="table fields">
7 <div id="perms" class="table fields">
9 %for section in sorted(permissions.keys()):
8 %for section in sorted(permissions.keys()):
10 <div class="panel panel-default">
9 <div class="panel panel-default">
11 <div class="panel-heading">
10 <div class="panel-heading">
12 <h3 class="panel-title">${section.replace("_"," ").capitalize()}</h3>
11 <h3 class="panel-title">${section.replace("_"," ").capitalize()}</h3>
13 </div>
12 </div>
14 <div class="panel-body">
13 <div class="panel-body">
15 <div class="perms_section_head field">
14 <div class="perms_section_head field">
16 <div class="radios">
15 <div class="radios">
17 %if section != 'global':
16 %if section != 'global':
18 <span class="permissions_boxes">
17 <span class="permissions_boxes">
19 <span class="desc">${_('show')}: </span>
18 <span class="desc">${_('show')}: </span>
20 ${h.checkbox('perms_filter_none_%s' % section, 'none', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='none')} <label for="${'perms_filter_none_%s' % section}"><span class="perm_tag none">${_('none')}</span></label>
19 ${h.checkbox('perms_filter_none_%s' % section, 'none', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='none')} <label for="${'perms_filter_none_%s' % section}"><span class="perm_tag none">${_('none')}</span></label>
21 ${h.checkbox('perms_filter_read_%s' % section, 'read', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='read')} <label for="${'perms_filter_read_%s' % section}"><span class="perm_tag read">${_('read')}</span></label>
20 ${h.checkbox('perms_filter_read_%s' % section, 'read', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='read')} <label for="${'perms_filter_read_%s' % section}"><span class="perm_tag read">${_('read')}</span></label>
22 ${h.checkbox('perms_filter_write_%s' % section, 'write', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='write')} <label for="${'perms_filter_write_%s' % section}"> <span class="perm_tag write">${_('write')}</span></label>
21 ${h.checkbox('perms_filter_write_%s' % section, 'write', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='write')} <label for="${'perms_filter_write_%s' % section}"> <span class="perm_tag write">${_('write')}</span></label>
23 ${h.checkbox('perms_filter_admin_%s' % section, 'admin', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='admin')} <label for="${'perms_filter_admin_%s' % section}"><span class="perm_tag admin">${_('admin')}</span></label>
22 ${h.checkbox('perms_filter_admin_%s' % section, 'admin', 'checked', class_='perm_filter filter_%s' % section, section=section, perm_type='admin')} <label for="${'perms_filter_admin_%s' % section}"><span class="perm_tag admin">${_('admin')}</span></label>
24 </span>
23 </span>
25 %endif
24 %endif
26 </div>
25 </div>
27 </div>
26 </div>
28 <div class="field">
27 <div class="field">
29 %if not permissions[section]:
28 %if not permissions[section]:
30 <p class="empty_data help-block">${_('No permissions defined')}</p>
29 <p class="empty_data help-block">${_('No permissions defined')}</p>
31 %else:
30 %else:
32 <div id='tbl_list_wrap_${section}'>
31 <div id='tbl_list_wrap_${section}'>
33 <table id="tbl_list_${section}" class="rctable">
32 <table id="tbl_list_${section}" class="rctable">
34 ## global permission box
33 ## global permission box
35 %if section == 'global':
34 %if section == 'global':
36 <thead>
35 <thead>
37 <tr>
36 <tr>
38 <th colspan="2" class="left">${_('Permission')}</th>
37 <th colspan="2" class="left">${_('Permission')}</th>
39 %if actions:
38 %if actions:
40 <th>${_('Edit Permission')}</th>
39 <th>${_('Edit Permission')}</th>
41 %endif
40 %endif
42 </thead>
41 </thead>
43 <tbody>
42 <tbody>
44
43
45 <%
44 <%
46 def get_section_perms(prefix, opts):
45 def get_section_perms(prefix, opts):
47 _selected = []
46 _selected = []
48 for op in opts:
47 for op in opts:
49 if op.startswith(prefix) and not op.startswith('hg.create.write_on_repogroup'):
48 if op.startswith(prefix) and not op.startswith('hg.create.write_on_repogroup'):
50 _selected.append(op)
49 _selected.append(op)
51 admin = 'hg.admin' in opts
50 admin = 'hg.admin' in opts
52 _selected_vals = [x.partition(prefix)[-1] for x in _selected]
51 _selected_vals = [x.partition(prefix)[-1] for x in _selected]
53 return admin, _selected_vals, _selected
52 return admin, _selected_vals, _selected
54 %>
53 %>
55 <%def name="glob(lbl, val, val_lbl=None, custom_url=None)">
54 <%def name="glob(lbl, val, val_lbl=None, custom_url=None)">
56 <tr>
55 <tr>
57 <td class="td-tags">
56 <td class="td-tags">
58 ${lbl}
57 ${lbl}
59 </td>
58 </td>
60 <td class="td-tags">
59 <td class="td-tags">
61 %if val[0]:
60 %if val[0]:
62 %if not val_lbl:
61 %if not val_lbl:
63 ${h.bool2icon(True)}
62 ${h.bool2icon(True)}
64 %else:
63 %else:
65 <span class="perm_tag admin">${val_lbl}.admin</span>
64 <span class="perm_tag admin">${val_lbl}.admin</span>
66 %endif
65 %endif
67 %else:
66 %else:
68 %if not val_lbl:
67 %if not val_lbl:
69 ${h.bool2icon({'false': False,
68 ${h.bool2icon({'false': False,
70 'true': True,
69 'true': True,
71 'none': False,
70 'none': False,
72 'repository': True}.get(val[1][0] if 0 < len(val[1]) else 'false'))}
71 'repository': True}.get(val[1][0] if 0 < len(val[1]) else 'false'))}
73 %else:
72 %else:
74 <span class="perm_tag ${val[1][0]}">${val_lbl}.${val[1][0]}</span>
73 <span class="perm_tag ${val[1][0]}">${val_lbl}.${val[1][0]}</span>
75 %endif
74 %endif
76 %endif
75 %endif
77 </td>
76 </td>
78 %if actions:
77 %if actions:
79 <td class="td-action">
78 <td class="td-action">
80 <a href="${custom_url or h.url('admin_permissions_global')}">${_('edit')}</a>
79 <a href="${custom_url or h.url('admin_permissions_global')}">${_('edit')}</a>
81 </td>
80 </td>
82 %endif
81 %endif
83 </tr>
82 </tr>
84 </%def>
83 </%def>
85
84
86 ${glob(_('Super admin'), get_section_perms('hg.admin', permissions[section]))}
85 ${glob(_('Super admin'), get_section_perms('hg.admin', permissions[section]))}
87
86
88 ${glob(_('Repository default permission'), get_section_perms('repository.', permissions[section]), 'repository', h.url('admin_permissions_object'))}
87 ${glob(_('Repository default permission'), get_section_perms('repository.', permissions[section]), 'repository', h.url('admin_permissions_object'))}
89 ${glob(_('Repository group default permission'), get_section_perms('group.', permissions[section]), 'group', h.url('admin_permissions_object'))}
88 ${glob(_('Repository group default permission'), get_section_perms('group.', permissions[section]), 'group', h.url('admin_permissions_object'))}
90 ${glob(_('User group default permission'), get_section_perms('usergroup.', permissions[section]), 'usergroup', h.url('admin_permissions_object'))}
89 ${glob(_('User group default permission'), get_section_perms('usergroup.', permissions[section]), 'usergroup', h.url('admin_permissions_object'))}
91
90
92 ${glob(_('Create repositories'), get_section_perms('hg.create.', permissions[section]), custom_url=h.url('admin_permissions_global'))}
91 ${glob(_('Create repositories'), get_section_perms('hg.create.', permissions[section]), custom_url=h.url('admin_permissions_global'))}
93 ${glob(_('Fork repositories'), get_section_perms('hg.fork.', permissions[section]), custom_url=h.url('admin_permissions_global'))}
92 ${glob(_('Fork repositories'), get_section_perms('hg.fork.', permissions[section]), custom_url=h.url('admin_permissions_global'))}
94 ${glob(_('Create repository groups'), get_section_perms('hg.repogroup.create.', permissions[section]), custom_url=h.url('admin_permissions_global'))}
93 ${glob(_('Create repository groups'), get_section_perms('hg.repogroup.create.', permissions[section]), custom_url=h.url('admin_permissions_global'))}
95 ${glob(_('Create user groups'), get_section_perms('hg.usergroup.create.', permissions[section]), custom_url=h.url('admin_permissions_global'))}
94 ${glob(_('Create user groups'), get_section_perms('hg.usergroup.create.', permissions[section]), custom_url=h.url('admin_permissions_global'))}
96
95
97
96
98 </tbody>
97 </tbody>
99 %else:
98 %else:
100 ## none/read/write/admin permissions on groups/repos etc
99 ## none/read/write/admin permissions on groups/repos etc
101 <thead>
100 <thead>
102 <tr>
101 <tr>
103 <th>${_('Name')}</th>
102 <th>${_('Name')}</th>
104 <th>${_('Permission')}</th>
103 <th>${_('Permission')}</th>
105 %if actions:
104 %if actions:
106 <th>${_('Edit Permission')}</th>
105 <th>${_('Edit Permission')}</th>
107 %endif
106 %endif
108 </thead>
107 </thead>
109 <tbody class="section_${section}">
108 <tbody class="section_${section}">
110 <%
109 <%
111 def sorter(permissions):
110 def sorter(permissions):
112 def custom_sorter(item):
111 def custom_sorter(item):
113 ## read/write/admin
112 ## read/write/admin
114 section = item[1].split('.')[-1]
113 section = item[1].split('.')[-1]
115 section_importance = {'none': u'0',
114 section_importance = {'none': u'0',
116 'read': u'1',
115 'read': u'1',
117 'write':u'2',
116 'write':u'2',
118 'admin':u'3'}.get(section)
117 'admin':u'3'}.get(section)
119 ## sort by group importance+name
118 ## sort by group importance+name
120 return section_importance+item[0]
119 return section_importance+item[0]
121 return sorted(permissions, key=custom_sorter)
120 return sorted(permissions, key=custom_sorter)
122 %>
121 %>
123 %for k, section_perm in sorter(permissions[section].items()):
122 %for k, section_perm in sorter(permissions[section].items()):
124 %if section_perm.split('.')[-1] != 'none' or show_all:
123 %if section_perm.split('.')[-1] != 'none' or show_all:
125 <tr class="perm_row ${'%s_%s' % (section, section_perm.split('.')[-1])}">
124 <tr class="perm_row ${'%s_%s' % (section, section_perm.split('.')[-1])}">
126 <td class="td-componentname">
125 <td class="td-componentname">
127 %if section == 'repositories':
126 %if section == 'repositories':
128 <a href="${h.url('summary_home',repo_name=k)}">${k}</a>
127 <a href="${h.url('summary_home',repo_name=k)}">${k}</a>
129 %elif section == 'repositories_groups':
128 %elif section == 'repositories_groups':
130 <a href="${h.url('repo_group_home',group_name=k)}">${k}</a>
129 <a href="${h.url('repo_group_home',group_name=k)}">${k}</a>
131 %elif section == 'user_groups':
130 %elif section == 'user_groups':
132 ##<a href="${h.url('edit_users_group',user_group_id=k)}">${k}</a>
131 ##<a href="${h.url('edit_users_group',user_group_id=k)}">${k}</a>
133 ${k}
132 ${k}
134 %endif
133 %endif
135 </td>
134 </td>
136 <td class="td-tags">
135 <td class="td-tags">
136 %if hasattr(permissions[section], 'perm_origin_stack'):
137 %for i, (perm, origin) in enumerate(reversed(permissions[section].perm_origin_stack[k])):
138 <span class="${i > 0 and 'perm_overriden' or ''} perm_tag ${perm.split('.')[-1]}">
139 ${perm} (${origin})
140 </span>
141 %endfor
142 %else:
137 <span class="perm_tag ${section_perm.split('.')[-1]}">${section_perm}</span>
143 <span class="perm_tag ${section_perm.split('.')[-1]}">${section_perm}</span>
144 %endif
138 </td>
145 </td>
139 %if actions:
146 %if actions:
140 <td class="td-action">
147 <td class="td-action">
141 %if section == 'repositories':
148 %if section == 'repositories':
142 <a href="${h.url('edit_repo_perms',repo_name=k,anchor='permissions_manage')}">${_('edit')}</a>
149 <a href="${h.url('edit_repo_perms',repo_name=k,anchor='permissions_manage')}">${_('edit')}</a>
143 %elif section == 'repositories_groups':
150 %elif section == 'repositories_groups':
144 <a href="${h.url('edit_repo_group_perms',group_name=k,anchor='permissions_manage')}">${_('edit')}</a>
151 <a href="${h.url('edit_repo_group_perms',group_name=k,anchor='permissions_manage')}">${_('edit')}</a>
145 %elif section == 'user_groups':
152 %elif section == 'user_groups':
146 ##<a href="${h.url('edit_users_group',user_group_id=k)}">${_('edit')}</a>
153 ##<a href="${h.url('edit_users_group',user_group_id=k)}">${_('edit')}</a>
147 %endif
154 %endif
148 </td>
155 </td>
149 %endif
156 %endif
150 </tr>
157 </tr>
151 %endif
158 %endif
152 %endfor
159 %endfor
153
160
154 <tr id="empty_${section}" class="noborder" style="display:none;">
161 <tr id="empty_${section}" class="noborder" style="display:none;">
155 <td colspan="6">${_('No permission defined')}</td>
162 <td colspan="6">${_('No permission defined')}</td>
156 </tr>
163 </tr>
157
164
158 </tbody>
165 </tbody>
159 %endif
166 %endif
160 </table>
167 </table>
161 </div>
168 </div>
162 %endif
169 %endif
163 </div>
170 </div>
164 </div>
171 </div>
165 </div>
172 </div>
166 %endfor
173 %endfor
167 </div>
174 </div>
168
175
169 <script>
176 <script>
170 $(document).ready(function(){
177 $(document).ready(function(){
171 var show_empty = function(section){
178 var show_empty = function(section){
172 var visible = $('.section_{0} tr.perm_row:visible'.format(section)).length;
179 var visible = $('.section_{0} tr.perm_row:visible'.format(section)).length;
173 if(visible == 0){
180 if(visible == 0){
174 $('#empty_{0}'.format(section)).show();
181 $('#empty_{0}'.format(section)).show();
175 }
182 }
176 else{
183 else{
177 $('#empty_{0}'.format(section)).hide();
184 $('#empty_{0}'.format(section)).hide();
178 }
185 }
179 };
186 };
180 $('.perm_filter').on('change', function(e){
187 $('.perm_filter').on('change', function(e){
181 var self = this;
188 var self = this;
182 var section = $(this).attr('section');
189 var section = $(this).attr('section');
183
190
184 var opts = {};
191 var opts = {};
185 var elems = $('.filter_' + section).each(function(el){
192 var elems = $('.filter_' + section).each(function(el){
186 var perm_type = $(this).attr('perm_type');
193 var perm_type = $(this).attr('perm_type');
187 var checked = this.checked;
194 var checked = this.checked;
188 opts[perm_type] = checked;
195 opts[perm_type] = checked;
189 if(checked){
196 if(checked){
190 $('.'+section+'_'+perm_type).show();
197 $('.'+section+'_'+perm_type).show();
191 }
198 }
192 else{
199 else{
193 $('.'+section+'_'+perm_type).hide();
200 $('.'+section+'_'+perm_type).hide();
194 }
201 }
195 });
202 });
196 show_empty(section);
203 show_empty(section);
197 })
204 })
198 })
205 })
199 </script>
206 </script>
200 </%def>
207 </%def>
@@ -1,186 +1,186 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import pytest
21 import pytest
22
22
23 from rhodecode.tests import (
23 from rhodecode.tests import (
24 TestController, url, assert_session_flash, link_to)
24 TestController, url, assert_session_flash, link_to)
25 from rhodecode.model.db import User, UserGroup
25 from rhodecode.model.db import User, UserGroup
26 from rhodecode.model.meta import Session
26 from rhodecode.model.meta import Session
27 from rhodecode.tests.fixture import Fixture
27 from rhodecode.tests.fixture import Fixture
28
28
29 TEST_USER_GROUP = 'admins_test'
29 TEST_USER_GROUP = 'admins_test'
30
30
31 fixture = Fixture()
31 fixture = Fixture()
32
32
33
33
34 class TestAdminUsersGroupsController(TestController):
34 class TestAdminUsersGroupsController(TestController):
35
35
36 def test_index(self):
36 def test_index(self):
37 self.log_user()
37 self.log_user()
38 response = self.app.get(url('users_groups'))
38 response = self.app.get(url('users_groups'))
39 response.mustcontain('No members yet')
39 response.status_int == 200
40
40
41 def test_create(self):
41 def test_create(self):
42 self.log_user()
42 self.log_user()
43 users_group_name = TEST_USER_GROUP
43 users_group_name = TEST_USER_GROUP
44 response = self.app.post(url('users_groups'), {
44 response = self.app.post(url('users_groups'), {
45 'users_group_name': users_group_name,
45 'users_group_name': users_group_name,
46 'user_group_description': 'DESC',
46 'user_group_description': 'DESC',
47 'active': True,
47 'active': True,
48 'csrf_token': self.csrf_token})
48 'csrf_token': self.csrf_token})
49
49
50 user_group_link = link_to(
50 user_group_link = link_to(
51 users_group_name,
51 users_group_name,
52 url('edit_users_group',
52 url('edit_users_group',
53 user_group_id=UserGroup.get_by_group_name(
53 user_group_id=UserGroup.get_by_group_name(
54 users_group_name).users_group_id))
54 users_group_name).users_group_id))
55 assert_session_flash(
55 assert_session_flash(
56 response,
56 response,
57 'Created user group %s' % user_group_link)
57 'Created user group %s' % user_group_link)
58
58
59 def test_delete(self):
59 def test_delete(self):
60 self.log_user()
60 self.log_user()
61 users_group_name = TEST_USER_GROUP + 'another'
61 users_group_name = TEST_USER_GROUP + 'another'
62 response = self.app.post(url('users_groups'), {
62 response = self.app.post(url('users_groups'), {
63 'users_group_name': users_group_name,
63 'users_group_name': users_group_name,
64 'user_group_description': 'DESC',
64 'user_group_description': 'DESC',
65 'active': True,
65 'active': True,
66 'csrf_token': self.csrf_token})
66 'csrf_token': self.csrf_token})
67
67
68 user_group_link = link_to(
68 user_group_link = link_to(
69 users_group_name,
69 users_group_name,
70 url('edit_users_group',
70 url('edit_users_group',
71 user_group_id=UserGroup.get_by_group_name(
71 user_group_id=UserGroup.get_by_group_name(
72 users_group_name).users_group_id))
72 users_group_name).users_group_id))
73 assert_session_flash(
73 assert_session_flash(
74 response,
74 response,
75 'Created user group %s' % user_group_link)
75 'Created user group %s' % user_group_link)
76
76
77 group = Session().query(UserGroup).filter(
77 group = Session().query(UserGroup).filter(
78 UserGroup.users_group_name == users_group_name).one()
78 UserGroup.users_group_name == users_group_name).one()
79
79
80 response = self.app.post(
80 response = self.app.post(
81 url('delete_users_group', user_group_id=group.users_group_id),
81 url('delete_users_group', user_group_id=group.users_group_id),
82 params={'_method': 'delete', 'csrf_token': self.csrf_token})
82 params={'_method': 'delete', 'csrf_token': self.csrf_token})
83
83
84 group = Session().query(UserGroup).filter(
84 group = Session().query(UserGroup).filter(
85 UserGroup.users_group_name == users_group_name).scalar()
85 UserGroup.users_group_name == users_group_name).scalar()
86
86
87 assert group is None
87 assert group is None
88
88
89 @pytest.mark.parametrize('repo_create, repo_create_write, user_group_create, repo_group_create, fork_create, inherit_default_permissions, expect_error, expect_form_error', [
89 @pytest.mark.parametrize('repo_create, repo_create_write, user_group_create, repo_group_create, fork_create, inherit_default_permissions, expect_error, expect_form_error', [
90 ('hg.create.none', 'hg.create.write_on_repogroup.false', 'hg.usergroup.create.false', 'hg.repogroup.create.false', 'hg.fork.none', 'hg.inherit_default_perms.false', False, False),
90 ('hg.create.none', 'hg.create.write_on_repogroup.false', 'hg.usergroup.create.false', 'hg.repogroup.create.false', 'hg.fork.none', 'hg.inherit_default_perms.false', False, False),
91 ('hg.create.repository', 'hg.create.write_on_repogroup.true', 'hg.usergroup.create.true', 'hg.repogroup.create.true', 'hg.fork.repository', 'hg.inherit_default_perms.false', False, False),
91 ('hg.create.repository', 'hg.create.write_on_repogroup.true', 'hg.usergroup.create.true', 'hg.repogroup.create.true', 'hg.fork.repository', 'hg.inherit_default_perms.false', False, False),
92 ('hg.create.XXX', 'hg.create.write_on_repogroup.true', 'hg.usergroup.create.true', 'hg.repogroup.create.true', 'hg.fork.repository', 'hg.inherit_default_perms.false', False, True),
92 ('hg.create.XXX', 'hg.create.write_on_repogroup.true', 'hg.usergroup.create.true', 'hg.repogroup.create.true', 'hg.fork.repository', 'hg.inherit_default_perms.false', False, True),
93 ('', '', '', '', '', '', True, False),
93 ('', '', '', '', '', '', True, False),
94 ])
94 ])
95 def test_global_perms_on_group(
95 def test_global_perms_on_group(
96 self, repo_create, repo_create_write, user_group_create,
96 self, repo_create, repo_create_write, user_group_create,
97 repo_group_create, fork_create, expect_error, expect_form_error,
97 repo_group_create, fork_create, expect_error, expect_form_error,
98 inherit_default_permissions):
98 inherit_default_permissions):
99 self.log_user()
99 self.log_user()
100 users_group_name = TEST_USER_GROUP + 'another2'
100 users_group_name = TEST_USER_GROUP + 'another2'
101 response = self.app.post(url('users_groups'),
101 response = self.app.post(url('users_groups'),
102 {'users_group_name': users_group_name,
102 {'users_group_name': users_group_name,
103 'user_group_description': 'DESC',
103 'user_group_description': 'DESC',
104 'active': True,
104 'active': True,
105 'csrf_token': self.csrf_token})
105 'csrf_token': self.csrf_token})
106
106
107 ug = UserGroup.get_by_group_name(users_group_name)
107 ug = UserGroup.get_by_group_name(users_group_name)
108 user_group_link = link_to(
108 user_group_link = link_to(
109 users_group_name,
109 users_group_name,
110 url('edit_users_group', user_group_id=ug.users_group_id))
110 url('edit_users_group', user_group_id=ug.users_group_id))
111 assert_session_flash(
111 assert_session_flash(
112 response,
112 response,
113 'Created user group %s' % user_group_link)
113 'Created user group %s' % user_group_link)
114 response.follow()
114 response.follow()
115
115
116 # ENABLE REPO CREATE ON A GROUP
116 # ENABLE REPO CREATE ON A GROUP
117 perm_params = {
117 perm_params = {
118 'inherit_default_permissions': False,
118 'inherit_default_permissions': False,
119 'default_repo_create': repo_create,
119 'default_repo_create': repo_create,
120 'default_repo_create_on_write': repo_create_write,
120 'default_repo_create_on_write': repo_create_write,
121 'default_user_group_create': user_group_create,
121 'default_user_group_create': user_group_create,
122 'default_repo_group_create': repo_group_create,
122 'default_repo_group_create': repo_group_create,
123 'default_fork_create': fork_create,
123 'default_fork_create': fork_create,
124 'default_inherit_default_permissions': inherit_default_permissions,
124 'default_inherit_default_permissions': inherit_default_permissions,
125
125
126 '_method': 'put',
126 '_method': 'put',
127 'csrf_token': self.csrf_token,
127 'csrf_token': self.csrf_token,
128 }
128 }
129 response = self.app.post(
129 response = self.app.post(
130 url('edit_user_group_global_perms',
130 url('edit_user_group_global_perms',
131 user_group_id=ug.users_group_id),
131 user_group_id=ug.users_group_id),
132 params=perm_params)
132 params=perm_params)
133
133
134 if expect_form_error:
134 if expect_form_error:
135 assert response.status_int == 200
135 assert response.status_int == 200
136 response.mustcontain('Value must be one of')
136 response.mustcontain('Value must be one of')
137 else:
137 else:
138 if expect_error:
138 if expect_error:
139 msg = 'An error occurred during permissions saving'
139 msg = 'An error occurred during permissions saving'
140 else:
140 else:
141 msg = 'User Group global permissions updated successfully'
141 msg = 'User Group global permissions updated successfully'
142 ug = UserGroup.get_by_group_name(users_group_name)
142 ug = UserGroup.get_by_group_name(users_group_name)
143 del perm_params['_method']
143 del perm_params['_method']
144 del perm_params['csrf_token']
144 del perm_params['csrf_token']
145 del perm_params['inherit_default_permissions']
145 del perm_params['inherit_default_permissions']
146 assert perm_params == ug.get_default_perms()
146 assert perm_params == ug.get_default_perms()
147 assert_session_flash(response, msg)
147 assert_session_flash(response, msg)
148
148
149 fixture.destroy_user_group(users_group_name)
149 fixture.destroy_user_group(users_group_name)
150
150
151 def test_edit(self):
151 def test_edit(self):
152 self.log_user()
152 self.log_user()
153 response = self.app.get(url('edit_users_group', user_group_id=1))
153 response = self.app.get(url('edit_users_group', user_group_id=1))
154
154
155 def test_edit_user_group_members(self):
155 def test_edit_user_group_members(self):
156 self.log_user()
156 self.log_user()
157 response = self.app.get(url('edit_user_group_members', user_group_id=1))
157 response = self.app.get(url('edit_user_group_members', user_group_id=1))
158 response.mustcontain('No members yet')
158 response.mustcontain('No members yet')
159
159
160 def test_usergroup_escape(self):
160 def test_usergroup_escape(self):
161 user = User.get_by_username('test_admin')
161 user = User.get_by_username('test_admin')
162 user.name = '<img src="/image1" onload="alert(\'Hello, World!\');">'
162 user.name = '<img src="/image1" onload="alert(\'Hello, World!\');">'
163 user.lastname = (
163 user.lastname = (
164 '<img src="/image2" onload="alert(\'Hello, World!\');">')
164 '<img src="/image2" onload="alert(\'Hello, World!\');">')
165 Session().add(user)
165 Session().add(user)
166 Session().commit()
166 Session().commit()
167
167
168 self.log_user()
168 self.log_user()
169 users_group_name = 'samplegroup'
169 users_group_name = 'samplegroup'
170 data = {
170 data = {
171 'users_group_name': users_group_name,
171 'users_group_name': users_group_name,
172 'user_group_description': (
172 'user_group_description': (
173 '<strong onload="alert();">DESC</strong>'),
173 '<strong onload="alert();">DESC</strong>'),
174 'active': True,
174 'active': True,
175 'csrf_token': self.csrf_token
175 'csrf_token': self.csrf_token
176 }
176 }
177
177
178 response = self.app.post(url('users_groups'), data)
178 response = self.app.post(url('users_groups'), data)
179 response = self.app.get(url('users_groups'))
179 response = self.app.get(url('users_groups'))
180
180
181 response.mustcontain(
181 response.mustcontain(
182 '&lt;strong onload=&#34;alert();&#34;&gt;'
182 '&lt;strong onload=&#34;alert();&#34;&gt;'
183 'DESC&lt;/strong&gt;')
183 'DESC&lt;/strong&gt;')
184 response.mustcontain(
184 response.mustcontain(
185 '&lt;img src=&#34;/image2&#34; onload=&#34;'
185 '&lt;img src=&#34;/image2&#34; onload=&#34;'
186 'alert(&#39;Hello, World!&#39;);&#34;&gt;')
186 'alert(&#39;Hello, World!&#39;);&#34;&gt;')
@@ -1,552 +1,582 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 from hashlib import sha1
22 from hashlib import sha1
23
23
24 import pytest
24 import pytest
25 from mock import patch
25 from mock import patch
26
26
27 from rhodecode.lib import auth
27 from rhodecode.lib import auth
28 from rhodecode.lib.utils2 import md5
28 from rhodecode.lib.utils2 import md5
29 from rhodecode.model.db import User
29 from rhodecode.model.db import User
30 from rhodecode.model.repo import RepoModel
30 from rhodecode.model.repo import RepoModel
31 from rhodecode.model.user import UserModel
31 from rhodecode.model.user import UserModel
32 from rhodecode.model.user_group import UserGroupModel
32 from rhodecode.model.user_group import UserGroupModel
33
33
34
34
35 def test_perm_origin_dict():
36 pod = auth.PermOriginDict()
37 pod['thing'] = 'read', 'default'
38 assert pod['thing'] == 'read'
39
40 assert pod.perm_origin_stack == {
41 'thing': [('read', 'default')]}
42
43 pod['thing'] = 'write', 'admin'
44 assert pod['thing'] == 'write'
45
46 assert pod.perm_origin_stack == {
47 'thing': [('read', 'default'), ('write', 'admin')]}
48
49 pod['other'] = 'write', 'default'
50
51 assert pod.perm_origin_stack == {
52 'other': [('write', 'default')],
53 'thing': [('read', 'default'), ('write', 'admin')]}
54
55 pod['other'] = 'none', 'override'
56
57 assert pod.perm_origin_stack == {
58 'other': [('write', 'default'), ('none', 'override')],
59 'thing': [('read', 'default'), ('write', 'admin')]}
60
61 with pytest.raises(ValueError):
62 pod['thing'] = 'read'
63
64
35 def test_cached_perms_data(user_regular, backend_random):
65 def test_cached_perms_data(user_regular, backend_random):
36 permissions = get_permissions(user_regular)
66 permissions = get_permissions(user_regular)
37 repo_name = backend_random.repo.repo_name
67 repo_name = backend_random.repo.repo_name
38 expected_global_permissions = {
68 expected_global_permissions = {
39 'repository.read', 'group.read', 'usergroup.read'}
69 'repository.read', 'group.read', 'usergroup.read'}
40 assert expected_global_permissions.issubset(permissions['global'])
70 assert expected_global_permissions.issubset(permissions['global'])
41 assert permissions['repositories'][repo_name] == 'repository.read'
71 assert permissions['repositories'][repo_name] == 'repository.read'
42
72
43
73
44 def test_cached_perms_data_with_admin_user(user_regular, backend_random):
74 def test_cached_perms_data_with_admin_user(user_regular, backend_random):
45 permissions = get_permissions(user_regular, user_is_admin=True)
75 permissions = get_permissions(user_regular, user_is_admin=True)
46 repo_name = backend_random.repo.repo_name
76 repo_name = backend_random.repo.repo_name
47 assert 'hg.admin' in permissions['global']
77 assert 'hg.admin' in permissions['global']
48 assert permissions['repositories'][repo_name] == 'repository.admin'
78 assert permissions['repositories'][repo_name] == 'repository.admin'
49
79
50
80
51 def test_cached_perms_data_user_group_global_permissions(user_util):
81 def test_cached_perms_data_user_group_global_permissions(user_util):
52 user, user_group = user_util.create_user_with_group()
82 user, user_group = user_util.create_user_with_group()
53 user_group.inherit_default_permissions = False
83 user_group.inherit_default_permissions = False
54
84
55 granted_permission = 'repository.write'
85 granted_permission = 'repository.write'
56 UserGroupModel().grant_perm(user_group, granted_permission)
86 UserGroupModel().grant_perm(user_group, granted_permission)
57
87
58 permissions = get_permissions(user)
88 permissions = get_permissions(user)
59 assert granted_permission in permissions['global']
89 assert granted_permission in permissions['global']
60
90
61
91
62 @pytest.mark.xfail(reason="Not implemented, see TODO note")
92 @pytest.mark.xfail(reason="Not implemented, see TODO note")
63 def test_cached_perms_data_user_group_global_permissions_(user_util):
93 def test_cached_perms_data_user_group_global_permissions_(user_util):
64 user, user_group = user_util.create_user_with_group()
94 user, user_group = user_util.create_user_with_group()
65
95
66 granted_permission = 'repository.write'
96 granted_permission = 'repository.write'
67 UserGroupModel().grant_perm(user_group, granted_permission)
97 UserGroupModel().grant_perm(user_group, granted_permission)
68
98
69 permissions = get_permissions(user)
99 permissions = get_permissions(user)
70 assert granted_permission in permissions['global']
100 assert granted_permission in permissions['global']
71
101
72
102
73 def test_cached_perms_data_user_global_permissions(user_util):
103 def test_cached_perms_data_user_global_permissions(user_util):
74 user = user_util.create_user()
104 user = user_util.create_user()
75 UserModel().grant_perm(user, 'repository.none')
105 UserModel().grant_perm(user, 'repository.none')
76
106
77 permissions = get_permissions(user, user_inherit_default_permissions=True)
107 permissions = get_permissions(user, user_inherit_default_permissions=True)
78 assert 'repository.read' in permissions['global']
108 assert 'repository.read' in permissions['global']
79
109
80
110
81 def test_cached_perms_data_repository_permissions_on_private_repository(
111 def test_cached_perms_data_repository_permissions_on_private_repository(
82 backend_random, user_util):
112 backend_random, user_util):
83 user, user_group = user_util.create_user_with_group()
113 user, user_group = user_util.create_user_with_group()
84
114
85 repo = backend_random.create_repo()
115 repo = backend_random.create_repo()
86 repo.private = True
116 repo.private = True
87
117
88 granted_permission = 'repository.write'
118 granted_permission = 'repository.write'
89 RepoModel().grant_user_group_permission(
119 RepoModel().grant_user_group_permission(
90 repo, user_group.users_group_name, granted_permission)
120 repo, user_group.users_group_name, granted_permission)
91
121
92 permissions = get_permissions(user)
122 permissions = get_permissions(user)
93 assert permissions['repositories'][repo.repo_name] == granted_permission
123 assert permissions['repositories'][repo.repo_name] == granted_permission
94
124
95
125
96 def test_cached_perms_data_repository_permissions_for_owner(
126 def test_cached_perms_data_repository_permissions_for_owner(
97 backend_random, user_util):
127 backend_random, user_util):
98 user = user_util.create_user()
128 user = user_util.create_user()
99
129
100 repo = backend_random.create_repo()
130 repo = backend_random.create_repo()
101 repo.user_id = user.user_id
131 repo.user_id = user.user_id
102
132
103 permissions = get_permissions(user)
133 permissions = get_permissions(user)
104 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
134 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
105
135
106 # TODO: johbo: Make cleanup in UserUtility smarter, then remove this hack
136 # TODO: johbo: Make cleanup in UserUtility smarter, then remove this hack
107 repo.user_id = User.get_default_user().user_id
137 repo.user_id = User.get_default_user().user_id
108
138
109
139
110 def test_cached_perms_data_repository_permissions_not_inheriting_defaults(
140 def test_cached_perms_data_repository_permissions_not_inheriting_defaults(
111 backend_random, user_util):
141 backend_random, user_util):
112 user = user_util.create_user()
142 user = user_util.create_user()
113 repo = backend_random.create_repo()
143 repo = backend_random.create_repo()
114
144
115 # Don't inherit default object permissions
145 # Don't inherit default object permissions
116 UserModel().grant_perm(user, 'hg.inherit_default_perms.false')
146 UserModel().grant_perm(user, 'hg.inherit_default_perms.false')
117
147
118 permissions = get_permissions(user)
148 permissions = get_permissions(user)
119 assert permissions['repositories'][repo.repo_name] == 'repository.none'
149 assert permissions['repositories'][repo.repo_name] == 'repository.none'
120
150
121
151
122 def test_cached_perms_data_default_permissions_on_repository_group(user_util):
152 def test_cached_perms_data_default_permissions_on_repository_group(user_util):
123 # Have a repository group with default permissions set
153 # Have a repository group with default permissions set
124 repo_group = user_util.create_repo_group()
154 repo_group = user_util.create_repo_group()
125 default_user = User.get_default_user()
155 default_user = User.get_default_user()
126 user_util.grant_user_permission_to_repo_group(
156 user_util.grant_user_permission_to_repo_group(
127 repo_group, default_user, 'repository.write')
157 repo_group, default_user, 'repository.write')
128 user = user_util.create_user()
158 user = user_util.create_user()
129
159
130 permissions = get_permissions(user)
160 permissions = get_permissions(user)
131 assert permissions['repositories_groups'][repo_group.group_name] == \
161 assert permissions['repositories_groups'][repo_group.group_name] == \
132 'repository.write'
162 'repository.write'
133
163
134
164
135 def test_cached_perms_data_default_permissions_on_repository_group_owner(
165 def test_cached_perms_data_default_permissions_on_repository_group_owner(
136 user_util):
166 user_util):
137 # Have a repository group
167 # Have a repository group
138 repo_group = user_util.create_repo_group()
168 repo_group = user_util.create_repo_group()
139 default_user = User.get_default_user()
169 default_user = User.get_default_user()
140
170
141 # Add a permission for the default user to hit the code path
171 # Add a permission for the default user to hit the code path
142 user_util.grant_user_permission_to_repo_group(
172 user_util.grant_user_permission_to_repo_group(
143 repo_group, default_user, 'repository.write')
173 repo_group, default_user, 'repository.write')
144
174
145 # Have an owner of the group
175 # Have an owner of the group
146 user = user_util.create_user()
176 user = user_util.create_user()
147 repo_group.user_id = user.user_id
177 repo_group.user_id = user.user_id
148
178
149 permissions = get_permissions(user)
179 permissions = get_permissions(user)
150 assert permissions['repositories_groups'][repo_group.group_name] == \
180 assert permissions['repositories_groups'][repo_group.group_name] == \
151 'group.admin'
181 'group.admin'
152
182
153
183
154 def test_cached_perms_data_default_permissions_on_repository_group_no_inherit(
184 def test_cached_perms_data_default_permissions_on_repository_group_no_inherit(
155 user_util):
185 user_util):
156 # Have a repository group
186 # Have a repository group
157 repo_group = user_util.create_repo_group()
187 repo_group = user_util.create_repo_group()
158 default_user = User.get_default_user()
188 default_user = User.get_default_user()
159
189
160 # Add a permission for the default user to hit the code path
190 # Add a permission for the default user to hit the code path
161 user_util.grant_user_permission_to_repo_group(
191 user_util.grant_user_permission_to_repo_group(
162 repo_group, default_user, 'repository.write')
192 repo_group, default_user, 'repository.write')
163
193
164 # Don't inherit default object permissions
194 # Don't inherit default object permissions
165 user = user_util.create_user()
195 user = user_util.create_user()
166 UserModel().grant_perm(user, 'hg.inherit_default_perms.false')
196 UserModel().grant_perm(user, 'hg.inherit_default_perms.false')
167
197
168 permissions = get_permissions(user)
198 permissions = get_permissions(user)
169 assert permissions['repositories_groups'][repo_group.group_name] == \
199 assert permissions['repositories_groups'][repo_group.group_name] == \
170 'group.none'
200 'group.none'
171
201
172
202
173 def test_cached_perms_data_repository_permissions_from_user_group(
203 def test_cached_perms_data_repository_permissions_from_user_group(
174 user_util, backend_random):
204 user_util, backend_random):
175 user, user_group = user_util.create_user_with_group()
205 user, user_group = user_util.create_user_with_group()
176
206
177 # Needs a second user group to make sure that we select the right
207 # Needs a second user group to make sure that we select the right
178 # permissions.
208 # permissions.
179 user_group2 = user_util.create_user_group()
209 user_group2 = user_util.create_user_group()
180 UserGroupModel().add_user_to_group(user_group2, user)
210 UserGroupModel().add_user_to_group(user_group2, user)
181
211
182 repo = backend_random.create_repo()
212 repo = backend_random.create_repo()
183
213
184 RepoModel().grant_user_group_permission(
214 RepoModel().grant_user_group_permission(
185 repo, user_group.users_group_name, 'repository.read')
215 repo, user_group.users_group_name, 'repository.read')
186 RepoModel().grant_user_group_permission(
216 RepoModel().grant_user_group_permission(
187 repo, user_group2.users_group_name, 'repository.write')
217 repo, user_group2.users_group_name, 'repository.write')
188
218
189 permissions = get_permissions(user)
219 permissions = get_permissions(user)
190 assert permissions['repositories'][repo.repo_name] == 'repository.write'
220 assert permissions['repositories'][repo.repo_name] == 'repository.write'
191
221
192
222
193 def test_cached_perms_data_repository_permissions_from_user_group_owner(
223 def test_cached_perms_data_repository_permissions_from_user_group_owner(
194 user_util, backend_random):
224 user_util, backend_random):
195 user, user_group = user_util.create_user_with_group()
225 user, user_group = user_util.create_user_with_group()
196
226
197 repo = backend_random.create_repo()
227 repo = backend_random.create_repo()
198 repo.user_id = user.user_id
228 repo.user_id = user.user_id
199
229
200 RepoModel().grant_user_group_permission(
230 RepoModel().grant_user_group_permission(
201 repo, user_group.users_group_name, 'repository.write')
231 repo, user_group.users_group_name, 'repository.write')
202
232
203 permissions = get_permissions(user)
233 permissions = get_permissions(user)
204 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
234 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
205
235
206
236
207 def test_cached_perms_data_user_repository_permissions(
237 def test_cached_perms_data_user_repository_permissions(
208 user_util, backend_random):
238 user_util, backend_random):
209 user = user_util.create_user()
239 user = user_util.create_user()
210 repo = backend_random.create_repo()
240 repo = backend_random.create_repo()
211 granted_permission = 'repository.write'
241 granted_permission = 'repository.write'
212 RepoModel().grant_user_permission(repo, user, granted_permission)
242 RepoModel().grant_user_permission(repo, user, granted_permission)
213
243
214 permissions = get_permissions(user)
244 permissions = get_permissions(user)
215 assert permissions['repositories'][repo.repo_name] == granted_permission
245 assert permissions['repositories'][repo.repo_name] == granted_permission
216
246
217
247
218 def test_cached_perms_data_user_repository_permissions_explicit(
248 def test_cached_perms_data_user_repository_permissions_explicit(
219 user_util, backend_random):
249 user_util, backend_random):
220 user = user_util.create_user()
250 user = user_util.create_user()
221 repo = backend_random.create_repo()
251 repo = backend_random.create_repo()
222 granted_permission = 'repository.none'
252 granted_permission = 'repository.none'
223 RepoModel().grant_user_permission(repo, user, granted_permission)
253 RepoModel().grant_user_permission(repo, user, granted_permission)
224
254
225 permissions = get_permissions(user, explicit=True)
255 permissions = get_permissions(user, explicit=True)
226 assert permissions['repositories'][repo.repo_name] == granted_permission
256 assert permissions['repositories'][repo.repo_name] == granted_permission
227
257
228
258
229 def test_cached_perms_data_user_repository_permissions_owner(
259 def test_cached_perms_data_user_repository_permissions_owner(
230 user_util, backend_random):
260 user_util, backend_random):
231 user = user_util.create_user()
261 user = user_util.create_user()
232 repo = backend_random.create_repo()
262 repo = backend_random.create_repo()
233 repo.user_id = user.user_id
263 repo.user_id = user.user_id
234 RepoModel().grant_user_permission(repo, user, 'repository.write')
264 RepoModel().grant_user_permission(repo, user, 'repository.write')
235
265
236 permissions = get_permissions(user)
266 permissions = get_permissions(user)
237 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
267 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
238
268
239
269
240 def test_cached_perms_data_repository_groups_permissions_inherited(
270 def test_cached_perms_data_repository_groups_permissions_inherited(
241 user_util, backend_random):
271 user_util, backend_random):
242 user, user_group = user_util.create_user_with_group()
272 user, user_group = user_util.create_user_with_group()
243
273
244 # Needs a second group to hit the last condition
274 # Needs a second group to hit the last condition
245 user_group2 = user_util.create_user_group()
275 user_group2 = user_util.create_user_group()
246 UserGroupModel().add_user_to_group(user_group2, user)
276 UserGroupModel().add_user_to_group(user_group2, user)
247
277
248 repo_group = user_util.create_repo_group()
278 repo_group = user_util.create_repo_group()
249
279
250 user_util.grant_user_group_permission_to_repo_group(
280 user_util.grant_user_group_permission_to_repo_group(
251 repo_group, user_group, 'group.read')
281 repo_group, user_group, 'group.read')
252 user_util.grant_user_group_permission_to_repo_group(
282 user_util.grant_user_group_permission_to_repo_group(
253 repo_group, user_group2, 'group.write')
283 repo_group, user_group2, 'group.write')
254
284
255 permissions = get_permissions(user)
285 permissions = get_permissions(user)
256 assert permissions['repositories_groups'][repo_group.group_name] == \
286 assert permissions['repositories_groups'][repo_group.group_name] == \
257 'group.write'
287 'group.write'
258
288
259
289
260 def test_cached_perms_data_repository_groups_permissions_inherited_owner(
290 def test_cached_perms_data_repository_groups_permissions_inherited_owner(
261 user_util, backend_random):
291 user_util, backend_random):
262 user, user_group = user_util.create_user_with_group()
292 user, user_group = user_util.create_user_with_group()
263 repo_group = user_util.create_repo_group()
293 repo_group = user_util.create_repo_group()
264 repo_group.user_id = user.user_id
294 repo_group.user_id = user.user_id
265
295
266 granted_permission = 'group.write'
296 granted_permission = 'group.write'
267 user_util.grant_user_group_permission_to_repo_group(
297 user_util.grant_user_group_permission_to_repo_group(
268 repo_group, user_group, granted_permission)
298 repo_group, user_group, granted_permission)
269
299
270 permissions = get_permissions(user)
300 permissions = get_permissions(user)
271 assert permissions['repositories_groups'][repo_group.group_name] == \
301 assert permissions['repositories_groups'][repo_group.group_name] == \
272 'group.admin'
302 'group.admin'
273
303
274
304
275 def test_cached_perms_data_repository_groups_permissions(
305 def test_cached_perms_data_repository_groups_permissions(
276 user_util, backend_random):
306 user_util, backend_random):
277 user = user_util.create_user()
307 user = user_util.create_user()
278
308
279 repo_group = user_util.create_repo_group()
309 repo_group = user_util.create_repo_group()
280
310
281 granted_permission = 'group.write'
311 granted_permission = 'group.write'
282 user_util.grant_user_permission_to_repo_group(
312 user_util.grant_user_permission_to_repo_group(
283 repo_group, user, granted_permission)
313 repo_group, user, granted_permission)
284
314
285 permissions = get_permissions(user)
315 permissions = get_permissions(user)
286 assert permissions['repositories_groups'][repo_group.group_name] == \
316 assert permissions['repositories_groups'][repo_group.group_name] == \
287 'group.write'
317 'group.write'
288
318
289
319
290 def test_cached_perms_data_repository_groups_permissions_explicit(
320 def test_cached_perms_data_repository_groups_permissions_explicit(
291 user_util, backend_random):
321 user_util, backend_random):
292 user = user_util.create_user()
322 user = user_util.create_user()
293
323
294 repo_group = user_util.create_repo_group()
324 repo_group = user_util.create_repo_group()
295
325
296 granted_permission = 'group.none'
326 granted_permission = 'group.none'
297 user_util.grant_user_permission_to_repo_group(
327 user_util.grant_user_permission_to_repo_group(
298 repo_group, user, granted_permission)
328 repo_group, user, granted_permission)
299
329
300 permissions = get_permissions(user, explicit=True)
330 permissions = get_permissions(user, explicit=True)
301 assert permissions['repositories_groups'][repo_group.group_name] == \
331 assert permissions['repositories_groups'][repo_group.group_name] == \
302 'group.none'
332 'group.none'
303
333
304
334
305 def test_cached_perms_data_repository_groups_permissions_owner(
335 def test_cached_perms_data_repository_groups_permissions_owner(
306 user_util, backend_random):
336 user_util, backend_random):
307 user = user_util.create_user()
337 user = user_util.create_user()
308
338
309 repo_group = user_util.create_repo_group()
339 repo_group = user_util.create_repo_group()
310 repo_group.user_id = user.user_id
340 repo_group.user_id = user.user_id
311
341
312 granted_permission = 'group.write'
342 granted_permission = 'group.write'
313 user_util.grant_user_permission_to_repo_group(
343 user_util.grant_user_permission_to_repo_group(
314 repo_group, user, granted_permission)
344 repo_group, user, granted_permission)
315
345
316 permissions = get_permissions(user)
346 permissions = get_permissions(user)
317 assert permissions['repositories_groups'][repo_group.group_name] == \
347 assert permissions['repositories_groups'][repo_group.group_name] == \
318 'group.admin'
348 'group.admin'
319
349
320
350
321 def test_cached_perms_data_user_group_permissions_inherited(
351 def test_cached_perms_data_user_group_permissions_inherited(
322 user_util, backend_random):
352 user_util, backend_random):
323 user, user_group = user_util.create_user_with_group()
353 user, user_group = user_util.create_user_with_group()
324 user_group2 = user_util.create_user_group()
354 user_group2 = user_util.create_user_group()
325 UserGroupModel().add_user_to_group(user_group2, user)
355 UserGroupModel().add_user_to_group(user_group2, user)
326
356
327 target_user_group = user_util.create_user_group()
357 target_user_group = user_util.create_user_group()
328
358
329 user_util.grant_user_group_permission_to_user_group(
359 user_util.grant_user_group_permission_to_user_group(
330 target_user_group, user_group, 'usergroup.read')
360 target_user_group, user_group, 'usergroup.read')
331 user_util.grant_user_group_permission_to_user_group(
361 user_util.grant_user_group_permission_to_user_group(
332 target_user_group, user_group2, 'usergroup.write')
362 target_user_group, user_group2, 'usergroup.write')
333
363
334 permissions = get_permissions(user)
364 permissions = get_permissions(user)
335 assert permissions['user_groups'][target_user_group.users_group_name] == \
365 assert permissions['user_groups'][target_user_group.users_group_name] == \
336 'usergroup.write'
366 'usergroup.write'
337
367
338
368
339 def test_cached_perms_data_user_group_permissions(
369 def test_cached_perms_data_user_group_permissions(
340 user_util, backend_random):
370 user_util, backend_random):
341 user = user_util.create_user()
371 user = user_util.create_user()
342 user_group = user_util.create_user_group()
372 user_group = user_util.create_user_group()
343 UserGroupModel().grant_user_permission(user_group, user, 'usergroup.write')
373 UserGroupModel().grant_user_permission(user_group, user, 'usergroup.write')
344
374
345 permissions = get_permissions(user)
375 permissions = get_permissions(user)
346 assert permissions['user_groups'][user_group.users_group_name] == \
376 assert permissions['user_groups'][user_group.users_group_name] == \
347 'usergroup.write'
377 'usergroup.write'
348
378
349
379
350 def test_cached_perms_data_user_group_permissions_explicit(
380 def test_cached_perms_data_user_group_permissions_explicit(
351 user_util, backend_random):
381 user_util, backend_random):
352 user = user_util.create_user()
382 user = user_util.create_user()
353 user_group = user_util.create_user_group()
383 user_group = user_util.create_user_group()
354 UserGroupModel().grant_user_permission(user_group, user, 'usergroup.none')
384 UserGroupModel().grant_user_permission(user_group, user, 'usergroup.none')
355
385
356 permissions = get_permissions(user, explicit=True)
386 permissions = get_permissions(user, explicit=True)
357 assert permissions['user_groups'][user_group.users_group_name] == \
387 assert permissions['user_groups'][user_group.users_group_name] == \
358 'usergroup.none'
388 'usergroup.none'
359
389
360
390
361 def test_cached_perms_data_user_group_permissions_not_inheriting_defaults(
391 def test_cached_perms_data_user_group_permissions_not_inheriting_defaults(
362 user_util, backend_random):
392 user_util, backend_random):
363 user = user_util.create_user()
393 user = user_util.create_user()
364 user_group = user_util.create_user_group()
394 user_group = user_util.create_user_group()
365
395
366 # Don't inherit default object permissions
396 # Don't inherit default object permissions
367 UserModel().grant_perm(user, 'hg.inherit_default_perms.false')
397 UserModel().grant_perm(user, 'hg.inherit_default_perms.false')
368
398
369 permissions = get_permissions(user)
399 permissions = get_permissions(user)
370 assert permissions['user_groups'][user_group.users_group_name] == \
400 assert permissions['user_groups'][user_group.users_group_name] == \
371 'usergroup.none'
401 'usergroup.none'
372
402
373
403
374 def test_permission_calculator_admin_permissions(
404 def test_permission_calculator_admin_permissions(
375 user_util, backend_random):
405 user_util, backend_random):
376 user = user_util.create_user()
406 user = user_util.create_user()
377 user_group = user_util.create_user_group()
407 user_group = user_util.create_user_group()
378 repo = backend_random.repo
408 repo = backend_random.repo
379 repo_group = user_util.create_repo_group()
409 repo_group = user_util.create_repo_group()
380
410
381 calculator = auth.PermissionCalculator(
411 calculator = auth.PermissionCalculator(
382 user.user_id, {}, False, False, True, 'higherwin')
412 user.user_id, {}, False, False, True, 'higherwin')
383 permissions = calculator._admin_permissions()
413 permissions = calculator._admin_permissions()
384
414
385 assert permissions['repositories_groups'][repo_group.group_name] == \
415 assert permissions['repositories_groups'][repo_group.group_name] == \
386 'group.admin'
416 'group.admin'
387 assert permissions['user_groups'][user_group.users_group_name] == \
417 assert permissions['user_groups'][user_group.users_group_name] == \
388 'usergroup.admin'
418 'usergroup.admin'
389 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
419 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
390 assert 'hg.admin' in permissions['global']
420 assert 'hg.admin' in permissions['global']
391
421
392
422
393 def test_permission_calculator_repository_permissions_robustness_from_group(
423 def test_permission_calculator_repository_permissions_robustness_from_group(
394 user_util, backend_random):
424 user_util, backend_random):
395 user, user_group = user_util.create_user_with_group()
425 user, user_group = user_util.create_user_with_group()
396
426
397 RepoModel().grant_user_group_permission(
427 RepoModel().grant_user_group_permission(
398 backend_random.repo, user_group.users_group_name, 'repository.write')
428 backend_random.repo, user_group.users_group_name, 'repository.write')
399
429
400 calculator = auth.PermissionCalculator(
430 calculator = auth.PermissionCalculator(
401 user.user_id, {}, False, False, False, 'higherwin')
431 user.user_id, {}, False, False, False, 'higherwin')
402 calculator._calculate_repository_permissions()
432 calculator._calculate_repository_permissions()
403
433
404
434
405 def test_permission_calculator_repository_permissions_robustness_from_user(
435 def test_permission_calculator_repository_permissions_robustness_from_user(
406 user_util, backend_random):
436 user_util, backend_random):
407 user = user_util.create_user()
437 user = user_util.create_user()
408
438
409 RepoModel().grant_user_permission(
439 RepoModel().grant_user_permission(
410 backend_random.repo, user, 'repository.write')
440 backend_random.repo, user, 'repository.write')
411
441
412 calculator = auth.PermissionCalculator(
442 calculator = auth.PermissionCalculator(
413 user.user_id, {}, False, False, False, 'higherwin')
443 user.user_id, {}, False, False, False, 'higherwin')
414 calculator._calculate_repository_permissions()
444 calculator._calculate_repository_permissions()
415
445
416
446
417 def test_permission_calculator_repo_group_permissions_robustness_from_group(
447 def test_permission_calculator_repo_group_permissions_robustness_from_group(
418 user_util, backend_random):
448 user_util, backend_random):
419 user, user_group = user_util.create_user_with_group()
449 user, user_group = user_util.create_user_with_group()
420 repo_group = user_util.create_repo_group()
450 repo_group = user_util.create_repo_group()
421
451
422 user_util.grant_user_group_permission_to_repo_group(
452 user_util.grant_user_group_permission_to_repo_group(
423 repo_group, user_group, 'group.write')
453 repo_group, user_group, 'group.write')
424
454
425 calculator = auth.PermissionCalculator(
455 calculator = auth.PermissionCalculator(
426 user.user_id, {}, False, False, False, 'higherwin')
456 user.user_id, {}, False, False, False, 'higherwin')
427 calculator._calculate_repository_group_permissions()
457 calculator._calculate_repository_group_permissions()
428
458
429
459
430 def test_permission_calculator_repo_group_permissions_robustness_from_user(
460 def test_permission_calculator_repo_group_permissions_robustness_from_user(
431 user_util, backend_random):
461 user_util, backend_random):
432 user = user_util.create_user()
462 user = user_util.create_user()
433 repo_group = user_util.create_repo_group()
463 repo_group = user_util.create_repo_group()
434
464
435 user_util.grant_user_permission_to_repo_group(
465 user_util.grant_user_permission_to_repo_group(
436 repo_group, user, 'group.write')
466 repo_group, user, 'group.write')
437
467
438 calculator = auth.PermissionCalculator(
468 calculator = auth.PermissionCalculator(
439 user.user_id, {}, False, False, False, 'higherwin')
469 user.user_id, {}, False, False, False, 'higherwin')
440 calculator._calculate_repository_group_permissions()
470 calculator._calculate_repository_group_permissions()
441
471
442
472
443 def test_permission_calculator_user_group_permissions_robustness_from_group(
473 def test_permission_calculator_user_group_permissions_robustness_from_group(
444 user_util, backend_random):
474 user_util, backend_random):
445 user, user_group = user_util.create_user_with_group()
475 user, user_group = user_util.create_user_with_group()
446 target_user_group = user_util.create_user_group()
476 target_user_group = user_util.create_user_group()
447
477
448 user_util.grant_user_group_permission_to_user_group(
478 user_util.grant_user_group_permission_to_user_group(
449 target_user_group, user_group, 'usergroup.write')
479 target_user_group, user_group, 'usergroup.write')
450
480
451 calculator = auth.PermissionCalculator(
481 calculator = auth.PermissionCalculator(
452 user.user_id, {}, False, False, False, 'higherwin')
482 user.user_id, {}, False, False, False, 'higherwin')
453 calculator._calculate_user_group_permissions()
483 calculator._calculate_user_group_permissions()
454
484
455
485
456 def test_permission_calculator_user_group_permissions_robustness_from_user(
486 def test_permission_calculator_user_group_permissions_robustness_from_user(
457 user_util, backend_random):
487 user_util, backend_random):
458 user = user_util.create_user()
488 user = user_util.create_user()
459 target_user_group = user_util.create_user_group()
489 target_user_group = user_util.create_user_group()
460
490
461 user_util.grant_user_permission_to_user_group(
491 user_util.grant_user_permission_to_user_group(
462 target_user_group, user, 'usergroup.write')
492 target_user_group, user, 'usergroup.write')
463
493
464 calculator = auth.PermissionCalculator(
494 calculator = auth.PermissionCalculator(
465 user.user_id, {}, False, False, False, 'higherwin')
495 user.user_id, {}, False, False, False, 'higherwin')
466 calculator._calculate_user_group_permissions()
496 calculator._calculate_user_group_permissions()
467
497
468
498
469 @pytest.mark.parametrize("algo, new_permission, old_permission, expected", [
499 @pytest.mark.parametrize("algo, new_permission, old_permission, expected", [
470 ('higherwin', 'repository.none', 'repository.none', 'repository.none'),
500 ('higherwin', 'repository.none', 'repository.none', 'repository.none'),
471 ('higherwin', 'repository.read', 'repository.none', 'repository.read'),
501 ('higherwin', 'repository.read', 'repository.none', 'repository.read'),
472 ('lowerwin', 'repository.write', 'repository.write', 'repository.write'),
502 ('lowerwin', 'repository.write', 'repository.write', 'repository.write'),
473 ('lowerwin', 'repository.read', 'repository.write', 'repository.read'),
503 ('lowerwin', 'repository.read', 'repository.write', 'repository.read'),
474 ])
504 ])
475 def test_permission_calculator_choose_permission(
505 def test_permission_calculator_choose_permission(
476 user_regular, algo, new_permission, old_permission, expected):
506 user_regular, algo, new_permission, old_permission, expected):
477 calculator = auth.PermissionCalculator(
507 calculator = auth.PermissionCalculator(
478 user_regular.user_id, {}, False, False, False, algo)
508 user_regular.user_id, {}, False, False, False, algo)
479 result = calculator._choose_permission(new_permission, old_permission)
509 result = calculator._choose_permission(new_permission, old_permission)
480 assert result == expected
510 assert result == expected
481
511
482
512
483 def test_permission_calculator_choose_permission_raises_on_wrong_algo(
513 def test_permission_calculator_choose_permission_raises_on_wrong_algo(
484 user_regular):
514 user_regular):
485 calculator = auth.PermissionCalculator(
515 calculator = auth.PermissionCalculator(
486 user_regular.user_id, {}, False, False, False, 'invalid')
516 user_regular.user_id, {}, False, False, False, 'invalid')
487 result = calculator._choose_permission(
517 result = calculator._choose_permission(
488 'repository.read', 'repository.read')
518 'repository.read', 'repository.read')
489 # TODO: johbo: This documents the existing behavior. Think of an
519 # TODO: johbo: This documents the existing behavior. Think of an
490 # improvement.
520 # improvement.
491 assert result is None
521 assert result is None
492
522
493
523
494 def test_auth_user_get_cookie_store_for_normal_user(user_util):
524 def test_auth_user_get_cookie_store_for_normal_user(user_util):
495 user = user_util.create_user()
525 user = user_util.create_user()
496 auth_user = auth.AuthUser(user_id=user.user_id)
526 auth_user = auth.AuthUser(user_id=user.user_id)
497 expected_data = {
527 expected_data = {
498 'username': user.username,
528 'username': user.username,
499 'user_id': user.user_id,
529 'user_id': user.user_id,
500 'password': md5(user.password),
530 'password': md5(user.password),
501 'is_authenticated': False
531 'is_authenticated': False
502 }
532 }
503 assert auth_user.get_cookie_store() == expected_data
533 assert auth_user.get_cookie_store() == expected_data
504
534
505
535
506 def test_auth_user_get_cookie_store_for_default_user():
536 def test_auth_user_get_cookie_store_for_default_user():
507 default_user = User.get_default_user()
537 default_user = User.get_default_user()
508 auth_user = auth.AuthUser()
538 auth_user = auth.AuthUser()
509 expected_data = {
539 expected_data = {
510 'username': User.DEFAULT_USER,
540 'username': User.DEFAULT_USER,
511 'user_id': default_user.user_id,
541 'user_id': default_user.user_id,
512 'password': md5(default_user.password),
542 'password': md5(default_user.password),
513 'is_authenticated': True
543 'is_authenticated': True
514 }
544 }
515 assert auth_user.get_cookie_store() == expected_data
545 assert auth_user.get_cookie_store() == expected_data
516
546
517
547
518 def get_permissions(user, **kwargs):
548 def get_permissions(user, **kwargs):
519 """
549 """
520 Utility filling in useful defaults into the call to `_cached_perms_data`.
550 Utility filling in useful defaults into the call to `_cached_perms_data`.
521
551
522 Fill in `**kwargs` if specific values are needed for a test.
552 Fill in `**kwargs` if specific values are needed for a test.
523 """
553 """
524 call_args = {
554 call_args = {
525 'user_id': user.user_id,
555 'user_id': user.user_id,
526 'scope': {},
556 'scope': {},
527 'user_is_admin': False,
557 'user_is_admin': False,
528 'user_inherit_default_permissions': False,
558 'user_inherit_default_permissions': False,
529 'explicit': False,
559 'explicit': False,
530 'algo': 'higherwin',
560 'algo': 'higherwin',
531 }
561 }
532 call_args.update(kwargs)
562 call_args.update(kwargs)
533 permissions = auth._cached_perms_data(**call_args)
563 permissions = auth._cached_perms_data(**call_args)
534 return permissions
564 return permissions
535
565
536
566
537 class TestGenerateAuthToken(object):
567 class TestGenerateAuthToken(object):
538 def test_salt_is_used_when_specified(self):
568 def test_salt_is_used_when_specified(self):
539 salt = 'abcde'
569 salt = 'abcde'
540 user_name = 'test_user'
570 user_name = 'test_user'
541 result = auth.generate_auth_token(user_name, salt)
571 result = auth.generate_auth_token(user_name, salt)
542 expected_result = sha1(user_name + salt).hexdigest()
572 expected_result = sha1(user_name + salt).hexdigest()
543 assert result == expected_result
573 assert result == expected_result
544
574
545 def test_salt_is_geneated_when_not_specified(self):
575 def test_salt_is_geneated_when_not_specified(self):
546 user_name = 'test_user'
576 user_name = 'test_user'
547 random_salt = os.urandom(16)
577 random_salt = os.urandom(16)
548 with patch.object(auth, 'os') as os_mock:
578 with patch.object(auth, 'os') as os_mock:
549 os_mock.urandom.return_value = random_salt
579 os_mock.urandom.return_value = random_salt
550 result = auth.generate_auth_token(user_name)
580 result = auth.generate_auth_token(user_name)
551 expected_result = sha1(user_name + random_salt).hexdigest()
581 expected_result = sha1(user_name + random_salt).hexdigest()
552 assert result == expected_result
582 assert result == expected_result
General Comments 0
You need to be logged in to leave comments. Login now