##// END OF EJS Templates
auth: expose a option to calculate how we end up having super-admin permission....
marcink -
r2065:adc2d1ca default
parent child Browse files
Show More
@@ -1,2103 +1,2162 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 os
25 import os
26 import inspect
26 import inspect
27 import collections
27 import collections
28 import fnmatch
28 import fnmatch
29 import hashlib
29 import hashlib
30 import itertools
30 import itertools
31 import logging
31 import logging
32 import random
32 import random
33 import traceback
33 import traceback
34 from functools import wraps
34 from functools import wraps
35
35
36 import ipaddress
36 import ipaddress
37 from beaker.cache import cache_region
37 from beaker.cache import cache_region
38 from pyramid.httpexceptions import HTTPForbidden, HTTPFound, HTTPNotFound
38 from pyramid.httpexceptions import HTTPForbidden, HTTPFound, HTTPNotFound
39 from pylons.i18n.translation import _
39 from pylons.i18n.translation import _
40 # NOTE(marcink): this has to be removed only after pyramid migration,
40 # NOTE(marcink): this has to be removed only after pyramid migration,
41 # replace with _ = request.translate
41 # replace with _ = request.translate
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, RepoGroup, UserGroup)
52 UserIpMap, UserApiKeys, RepoGroup, UserGroup)
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 ENC_PREF = None
101 ENC_PREF = None
102
102
103 def hash_create(self, str_):
103 def hash_create(self, str_):
104 """
104 """
105 hash the string using
105 hash the string using
106
106
107 :param str_: password to hash
107 :param str_: password to hash
108 """
108 """
109 raise NotImplementedError
109 raise NotImplementedError
110
110
111 def hash_check_with_upgrade(self, password, hashed):
111 def hash_check_with_upgrade(self, password, hashed):
112 """
112 """
113 Returns tuple in which first element is boolean that states that
113 Returns tuple in which first element is boolean that states that
114 given password matches it's hashed version, and the second is new hash
114 given password matches it's hashed version, and the second is new hash
115 of the password, in case this password should be migrated to new
115 of the password, in case this password should be migrated to new
116 cipher.
116 cipher.
117 """
117 """
118 checked_hash = self.hash_check(password, hashed)
118 checked_hash = self.hash_check(password, hashed)
119 return checked_hash, None
119 return checked_hash, None
120
120
121 def hash_check(self, password, hashed):
121 def hash_check(self, password, hashed):
122 """
122 """
123 Checks matching password with it's hashed value.
123 Checks matching password with it's hashed value.
124
124
125 :param password: password
125 :param password: password
126 :param hashed: password in hashed form
126 :param hashed: password in hashed form
127 """
127 """
128 raise NotImplementedError
128 raise NotImplementedError
129
129
130 def _assert_bytes(self, value):
130 def _assert_bytes(self, value):
131 """
131 """
132 Passing in an `unicode` object can lead to hard to detect issues
132 Passing in an `unicode` object can lead to hard to detect issues
133 if passwords contain non-ascii characters. Doing a type check
133 if passwords contain non-ascii characters. Doing a type check
134 during runtime, so that such mistakes are detected early on.
134 during runtime, so that such mistakes are detected early on.
135 """
135 """
136 if not isinstance(value, str):
136 if not isinstance(value, str):
137 raise TypeError(
137 raise TypeError(
138 "Bytestring required as input, got %r." % (value, ))
138 "Bytestring required as input, got %r." % (value, ))
139
139
140
140
141 class _RhodeCodeCryptoBCrypt(_RhodeCodeCryptoBase):
141 class _RhodeCodeCryptoBCrypt(_RhodeCodeCryptoBase):
142 ENC_PREF = ('$2a$10', '$2b$10')
142 ENC_PREF = ('$2a$10', '$2b$10')
143
143
144 def hash_create(self, str_):
144 def hash_create(self, str_):
145 self._assert_bytes(str_)
145 self._assert_bytes(str_)
146 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
146 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
147
147
148 def hash_check_with_upgrade(self, password, hashed):
148 def hash_check_with_upgrade(self, password, hashed):
149 """
149 """
150 Returns tuple in which first element is boolean that states that
150 Returns tuple in which first element is boolean that states that
151 given password matches it's hashed version, and the second is new hash
151 given password matches it's hashed version, and the second is new hash
152 of the password, in case this password should be migrated to new
152 of the password, in case this password should be migrated to new
153 cipher.
153 cipher.
154
154
155 This implements special upgrade logic which works like that:
155 This implements special upgrade logic which works like that:
156 - check if the given password == bcrypted hash, if yes then we
156 - check if the given password == bcrypted hash, if yes then we
157 properly used password and it was already in bcrypt. Proceed
157 properly used password and it was already in bcrypt. Proceed
158 without any changes
158 without any changes
159 - if bcrypt hash check is not working try with sha256. If hash compare
159 - if bcrypt hash check is not working try with sha256. If hash compare
160 is ok, it means we using correct but old hashed password. indicate
160 is ok, it means we using correct but old hashed password. indicate
161 hash change and proceed
161 hash change and proceed
162 """
162 """
163
163
164 new_hash = None
164 new_hash = None
165
165
166 # regular pw check
166 # regular pw check
167 password_match_bcrypt = self.hash_check(password, hashed)
167 password_match_bcrypt = self.hash_check(password, hashed)
168
168
169 # now we want to know if the password was maybe from sha256
169 # now we want to know if the password was maybe from sha256
170 # basically calling _RhodeCodeCryptoSha256().hash_check()
170 # basically calling _RhodeCodeCryptoSha256().hash_check()
171 if not password_match_bcrypt:
171 if not password_match_bcrypt:
172 if _RhodeCodeCryptoSha256().hash_check(password, hashed):
172 if _RhodeCodeCryptoSha256().hash_check(password, hashed):
173 new_hash = self.hash_create(password) # make new bcrypt hash
173 new_hash = self.hash_create(password) # make new bcrypt hash
174 password_match_bcrypt = True
174 password_match_bcrypt = True
175
175
176 return password_match_bcrypt, new_hash
176 return password_match_bcrypt, new_hash
177
177
178 def hash_check(self, password, hashed):
178 def hash_check(self, password, hashed):
179 """
179 """
180 Checks matching password with it's hashed value.
180 Checks matching password with it's hashed value.
181
181
182 :param password: password
182 :param password: password
183 :param hashed: password in hashed form
183 :param hashed: password in hashed form
184 """
184 """
185 self._assert_bytes(password)
185 self._assert_bytes(password)
186 try:
186 try:
187 return bcrypt.hashpw(password, hashed) == hashed
187 return bcrypt.hashpw(password, hashed) == hashed
188 except ValueError as e:
188 except ValueError as e:
189 # we're having a invalid salt here probably, we should not crash
189 # we're having a invalid salt here probably, we should not crash
190 # just return with False as it would be a wrong password.
190 # just return with False as it would be a wrong password.
191 log.debug('Failed to check password hash using bcrypt %s',
191 log.debug('Failed to check password hash using bcrypt %s',
192 safe_str(e))
192 safe_str(e))
193
193
194 return False
194 return False
195
195
196
196
197 class _RhodeCodeCryptoSha256(_RhodeCodeCryptoBase):
197 class _RhodeCodeCryptoSha256(_RhodeCodeCryptoBase):
198 ENC_PREF = '_'
198 ENC_PREF = '_'
199
199
200 def hash_create(self, str_):
200 def hash_create(self, str_):
201 self._assert_bytes(str_)
201 self._assert_bytes(str_)
202 return hashlib.sha256(str_).hexdigest()
202 return hashlib.sha256(str_).hexdigest()
203
203
204 def hash_check(self, password, hashed):
204 def hash_check(self, password, hashed):
205 """
205 """
206 Checks matching password with it's hashed value.
206 Checks matching password with it's hashed value.
207
207
208 :param password: password
208 :param password: password
209 :param hashed: password in hashed form
209 :param hashed: password in hashed form
210 """
210 """
211 self._assert_bytes(password)
211 self._assert_bytes(password)
212 return hashlib.sha256(password).hexdigest() == hashed
212 return hashlib.sha256(password).hexdigest() == hashed
213
213
214
214
215 class _RhodeCodeCryptoMd5(_RhodeCodeCryptoBase):
215 class _RhodeCodeCryptoMd5(_RhodeCodeCryptoBase):
216 ENC_PREF = '_'
216 ENC_PREF = '_'
217
217
218 def hash_create(self, str_):
218 def hash_create(self, str_):
219 self._assert_bytes(str_)
219 self._assert_bytes(str_)
220 return hashlib.md5(str_).hexdigest()
220 return hashlib.md5(str_).hexdigest()
221
221
222 def hash_check(self, password, hashed):
222 def hash_check(self, password, hashed):
223 """
223 """
224 Checks matching password with it's hashed value.
224 Checks matching password with it's hashed value.
225
225
226 :param password: password
226 :param password: password
227 :param hashed: password in hashed form
227 :param hashed: password in hashed form
228 """
228 """
229 self._assert_bytes(password)
229 self._assert_bytes(password)
230 return hashlib.md5(password).hexdigest() == hashed
230 return hashlib.md5(password).hexdigest() == hashed
231
231
232
232
233 def crypto_backend():
233 def crypto_backend():
234 """
234 """
235 Return the matching crypto backend.
235 Return the matching crypto backend.
236
236
237 Selection is based on if we run tests or not, we pick md5 backend to run
237 Selection is based on if we run tests or not, we pick md5 backend to run
238 tests faster since BCRYPT is expensive to calculate
238 tests faster since BCRYPT is expensive to calculate
239 """
239 """
240 if rhodecode.is_test:
240 if rhodecode.is_test:
241 RhodeCodeCrypto = _RhodeCodeCryptoMd5()
241 RhodeCodeCrypto = _RhodeCodeCryptoMd5()
242 else:
242 else:
243 RhodeCodeCrypto = _RhodeCodeCryptoBCrypt()
243 RhodeCodeCrypto = _RhodeCodeCryptoBCrypt()
244
244
245 return RhodeCodeCrypto
245 return RhodeCodeCrypto
246
246
247
247
248 def get_crypt_password(password):
248 def get_crypt_password(password):
249 """
249 """
250 Create the hash of `password` with the active crypto backend.
250 Create the hash of `password` with the active crypto backend.
251
251
252 :param password: The cleartext password.
252 :param password: The cleartext password.
253 :type password: unicode
253 :type password: unicode
254 """
254 """
255 password = safe_str(password)
255 password = safe_str(password)
256 return crypto_backend().hash_create(password)
256 return crypto_backend().hash_create(password)
257
257
258
258
259 def check_password(password, hashed):
259 def check_password(password, hashed):
260 """
260 """
261 Check if the value in `password` matches the hash in `hashed`.
261 Check if the value in `password` matches the hash in `hashed`.
262
262
263 :param password: The cleartext password.
263 :param password: The cleartext password.
264 :type password: unicode
264 :type password: unicode
265
265
266 :param hashed: The expected hashed version of the password.
266 :param hashed: The expected hashed version of the password.
267 :type hashed: The hash has to be passed in in text representation.
267 :type hashed: The hash has to be passed in in text representation.
268 """
268 """
269 password = safe_str(password)
269 password = safe_str(password)
270 return crypto_backend().hash_check(password, hashed)
270 return crypto_backend().hash_check(password, hashed)
271
271
272
272
273 def generate_auth_token(data, salt=None):
273 def generate_auth_token(data, salt=None):
274 """
274 """
275 Generates API KEY from given string
275 Generates API KEY from given string
276 """
276 """
277
277
278 if salt is None:
278 if salt is None:
279 salt = os.urandom(16)
279 salt = os.urandom(16)
280 return hashlib.sha1(safe_str(data) + salt).hexdigest()
280 return hashlib.sha1(safe_str(data) + salt).hexdigest()
281
281
282
282
283 class CookieStoreWrapper(object):
283 class CookieStoreWrapper(object):
284
284
285 def __init__(self, cookie_store):
285 def __init__(self, cookie_store):
286 self.cookie_store = cookie_store
286 self.cookie_store = cookie_store
287
287
288 def __repr__(self):
288 def __repr__(self):
289 return 'CookieStore<%s>' % (self.cookie_store)
289 return 'CookieStore<%s>' % (self.cookie_store)
290
290
291 def get(self, key, other=None):
291 def get(self, key, other=None):
292 if isinstance(self.cookie_store, dict):
292 if isinstance(self.cookie_store, dict):
293 return self.cookie_store.get(key, other)
293 return self.cookie_store.get(key, other)
294 elif isinstance(self.cookie_store, AuthUser):
294 elif isinstance(self.cookie_store, AuthUser):
295 return self.cookie_store.__dict__.get(key, other)
295 return self.cookie_store.__dict__.get(key, other)
296
296
297
297
298 def _cached_perms_data(user_id, scope, user_is_admin,
298 def _cached_perms_data(user_id, scope, user_is_admin,
299 user_inherit_default_permissions, explicit, algo):
299 user_inherit_default_permissions, explicit, algo,
300 calculate_super_admin):
300
301
301 permissions = PermissionCalculator(
302 permissions = PermissionCalculator(
302 user_id, scope, user_is_admin, user_inherit_default_permissions,
303 user_id, scope, user_is_admin, user_inherit_default_permissions,
303 explicit, algo)
304 explicit, algo, calculate_super_admin)
304 return permissions.calculate()
305 return permissions.calculate()
305
306
306
307
307 class PermOrigin(object):
308 class PermOrigin(object):
308 ADMIN = 'superadmin'
309 SUPER_ADMIN = 'superadmin'
309
310
310 REPO_USER = 'user:%s'
311 REPO_USER = 'user:%s'
311 REPO_USERGROUP = 'usergroup:%s'
312 REPO_USERGROUP = 'usergroup:%s'
312 REPO_OWNER = 'repo.owner'
313 REPO_OWNER = 'repo.owner'
313 REPO_DEFAULT = 'repo.default'
314 REPO_DEFAULT = 'repo.default'
314 REPO_DEFAULT_NO_INHERIT = 'repo.default.no.inherit'
315 REPO_DEFAULT_NO_INHERIT = 'repo.default.no.inherit'
315 REPO_PRIVATE = 'repo.private'
316 REPO_PRIVATE = 'repo.private'
316
317
317 REPOGROUP_USER = 'user:%s'
318 REPOGROUP_USER = 'user:%s'
318 REPOGROUP_USERGROUP = 'usergroup:%s'
319 REPOGROUP_USERGROUP = 'usergroup:%s'
319 REPOGROUP_OWNER = 'group.owner'
320 REPOGROUP_OWNER = 'group.owner'
320 REPOGROUP_DEFAULT = 'group.default'
321 REPOGROUP_DEFAULT = 'group.default'
321 REPOGROUP_DEFAULT_NO_INHERIT = 'group.default.no.inherit'
322 REPOGROUP_DEFAULT_NO_INHERIT = 'group.default.no.inherit'
322
323
323 USERGROUP_USER = 'user:%s'
324 USERGROUP_USER = 'user:%s'
324 USERGROUP_USERGROUP = 'usergroup:%s'
325 USERGROUP_USERGROUP = 'usergroup:%s'
325 USERGROUP_OWNER = 'usergroup.owner'
326 USERGROUP_OWNER = 'usergroup.owner'
326 USERGROUP_DEFAULT = 'usergroup.default'
327 USERGROUP_DEFAULT = 'usergroup.default'
327 USERGROUP_DEFAULT_NO_INHERIT = 'usergroup.default.no.inherit'
328 USERGROUP_DEFAULT_NO_INHERIT = 'usergroup.default.no.inherit'
328
329
329
330
330 class PermOriginDict(dict):
331 class PermOriginDict(dict):
331 """
332 """
332 A special dict used for tracking permissions along with their origins.
333 A special dict used for tracking permissions along with their origins.
333
334
334 `__setitem__` has been overridden to expect a tuple(perm, origin)
335 `__setitem__` has been overridden to expect a tuple(perm, origin)
335 `__getitem__` will return only the perm
336 `__getitem__` will return only the perm
336 `.perm_origin_stack` will return the stack of (perm, origin) set per key
337 `.perm_origin_stack` will return the stack of (perm, origin) set per key
337
338
338 >>> perms = PermOriginDict()
339 >>> perms = PermOriginDict()
339 >>> perms['resource'] = 'read', 'default'
340 >>> perms['resource'] = 'read', 'default'
340 >>> perms['resource']
341 >>> perms['resource']
341 'read'
342 'read'
342 >>> perms['resource'] = 'write', 'admin'
343 >>> perms['resource'] = 'write', 'admin'
343 >>> perms['resource']
344 >>> perms['resource']
344 'write'
345 'write'
345 >>> perms.perm_origin_stack
346 >>> perms.perm_origin_stack
346 {'resource': [('read', 'default'), ('write', 'admin')]}
347 {'resource': [('read', 'default'), ('write', 'admin')]}
347 """
348 """
348
349
349 def __init__(self, *args, **kw):
350 def __init__(self, *args, **kw):
350 dict.__init__(self, *args, **kw)
351 dict.__init__(self, *args, **kw)
351 self.perm_origin_stack = collections.OrderedDict()
352 self.perm_origin_stack = collections.OrderedDict()
352
353
353 def __setitem__(self, key, (perm, origin)):
354 def __setitem__(self, key, (perm, origin)):
354 self.perm_origin_stack.setdefault(key, []).append((perm, origin))
355 self.perm_origin_stack.setdefault(key, []).append((perm, origin))
355 dict.__setitem__(self, key, perm)
356 dict.__setitem__(self, key, perm)
356
357
357
358
358 class PermissionCalculator(object):
359 class PermissionCalculator(object):
359
360
360 def __init__(
361 def __init__(
361 self, user_id, scope, user_is_admin,
362 self, user_id, scope, user_is_admin,
362 user_inherit_default_permissions, explicit, algo):
363 user_inherit_default_permissions, explicit, algo,
364 calculate_super_admin=False):
365
363 self.user_id = user_id
366 self.user_id = user_id
364 self.user_is_admin = user_is_admin
367 self.user_is_admin = user_is_admin
365 self.inherit_default_permissions = user_inherit_default_permissions
368 self.inherit_default_permissions = user_inherit_default_permissions
366 self.explicit = explicit
369 self.explicit = explicit
367 self.algo = algo
370 self.algo = algo
371 self.calculate_super_admin = calculate_super_admin
368
372
369 scope = scope or {}
373 scope = scope or {}
370 self.scope_repo_id = scope.get('repo_id')
374 self.scope_repo_id = scope.get('repo_id')
371 self.scope_repo_group_id = scope.get('repo_group_id')
375 self.scope_repo_group_id = scope.get('repo_group_id')
372 self.scope_user_group_id = scope.get('user_group_id')
376 self.scope_user_group_id = scope.get('user_group_id')
373
377
374 self.default_user_id = User.get_default_user(cache=True).user_id
378 self.default_user_id = User.get_default_user(cache=True).user_id
375
379
376 self.permissions_repositories = PermOriginDict()
380 self.permissions_repositories = PermOriginDict()
377 self.permissions_repository_groups = PermOriginDict()
381 self.permissions_repository_groups = PermOriginDict()
378 self.permissions_user_groups = PermOriginDict()
382 self.permissions_user_groups = PermOriginDict()
379 self.permissions_global = set()
383 self.permissions_global = set()
380
384
381 self.default_repo_perms = Permission.get_default_repo_perms(
385 self.default_repo_perms = Permission.get_default_repo_perms(
382 self.default_user_id, self.scope_repo_id)
386 self.default_user_id, self.scope_repo_id)
383 self.default_repo_groups_perms = Permission.get_default_group_perms(
387 self.default_repo_groups_perms = Permission.get_default_group_perms(
384 self.default_user_id, self.scope_repo_group_id)
388 self.default_user_id, self.scope_repo_group_id)
385 self.default_user_group_perms = \
389 self.default_user_group_perms = \
386 Permission.get_default_user_group_perms(
390 Permission.get_default_user_group_perms(
387 self.default_user_id, self.scope_user_group_id)
391 self.default_user_id, self.scope_user_group_id)
388
392
389 def calculate(self):
393 def calculate(self):
390 if self.user_is_admin:
394 if self.user_is_admin and not self.calculate_super_admin:
391 return self._admin_permissions()
395 return self._admin_permissions()
392
396
393 self._calculate_global_default_permissions()
397 self._calculate_global_default_permissions()
394 self._calculate_global_permissions()
398 self._calculate_global_permissions()
395 self._calculate_default_permissions()
399 self._calculate_default_permissions()
396 self._calculate_repository_permissions()
400 self._calculate_repository_permissions()
397 self._calculate_repository_group_permissions()
401 self._calculate_repository_group_permissions()
398 self._calculate_user_group_permissions()
402 self._calculate_user_group_permissions()
399 return self._permission_structure()
403 return self._permission_structure()
400
404
401 def _admin_permissions(self):
405 def _admin_permissions(self):
402 """
406 """
403 admin user have all default rights for repositories
407 admin user have all default rights for repositories
404 and groups set to admin
408 and groups set to admin
405 """
409 """
406 self.permissions_global.add('hg.admin')
410 self.permissions_global.add('hg.admin')
407 self.permissions_global.add('hg.create.write_on_repogroup.true')
411 self.permissions_global.add('hg.create.write_on_repogroup.true')
408
412
409 # repositories
413 # repositories
410 for perm in self.default_repo_perms:
414 for perm in self.default_repo_perms:
411 r_k = perm.UserRepoToPerm.repository.repo_name
415 r_k = perm.UserRepoToPerm.repository.repo_name
412 p = 'repository.admin'
416 p = 'repository.admin'
413 self.permissions_repositories[r_k] = p, PermOrigin.ADMIN
417 self.permissions_repositories[r_k] = p, PermOrigin.SUPER_ADMIN
414
418
415 # repository groups
419 # repository groups
416 for perm in self.default_repo_groups_perms:
420 for perm in self.default_repo_groups_perms:
417 rg_k = perm.UserRepoGroupToPerm.group.group_name
421 rg_k = perm.UserRepoGroupToPerm.group.group_name
418 p = 'group.admin'
422 p = 'group.admin'
419 self.permissions_repository_groups[rg_k] = p, PermOrigin.ADMIN
423 self.permissions_repository_groups[rg_k] = p, PermOrigin.SUPER_ADMIN
420
424
421 # user groups
425 # user groups
422 for perm in self.default_user_group_perms:
426 for perm in self.default_user_group_perms:
423 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
427 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
424 p = 'usergroup.admin'
428 p = 'usergroup.admin'
425 self.permissions_user_groups[u_k] = p, PermOrigin.ADMIN
429 self.permissions_user_groups[u_k] = p, PermOrigin.SUPER_ADMIN
426
430
427 return self._permission_structure()
431 return self._permission_structure()
428
432
429 def _calculate_global_default_permissions(self):
433 def _calculate_global_default_permissions(self):
430 """
434 """
431 global permissions taken from the default user
435 global permissions taken from the default user
432 """
436 """
433 default_global_perms = UserToPerm.query()\
437 default_global_perms = UserToPerm.query()\
434 .filter(UserToPerm.user_id == self.default_user_id)\
438 .filter(UserToPerm.user_id == self.default_user_id)\
435 .options(joinedload(UserToPerm.permission))
439 .options(joinedload(UserToPerm.permission))
436
440
437 for perm in default_global_perms:
441 for perm in default_global_perms:
438 self.permissions_global.add(perm.permission.permission_name)
442 self.permissions_global.add(perm.permission.permission_name)
439
443
444 if self.user_is_admin:
445 self.permissions_global.add('hg.admin')
446 self.permissions_global.add('hg.create.write_on_repogroup.true')
447
440 def _calculate_global_permissions(self):
448 def _calculate_global_permissions(self):
441 """
449 """
442 Set global system permissions with user permissions or permissions
450 Set global system permissions with user permissions or permissions
443 taken from the user groups of the current user.
451 taken from the user groups of the current user.
444
452
445 The permissions include repo creating, repo group creating, forking
453 The permissions include repo creating, repo group creating, forking
446 etc.
454 etc.
447 """
455 """
448
456
449 # now we read the defined permissions and overwrite what we have set
457 # now we read the defined permissions and overwrite what we have set
450 # before those can be configured from groups or users explicitly.
458 # before those can be configured from groups or users explicitly.
451
459
452 # TODO: johbo: This seems to be out of sync, find out the reason
460 # TODO: johbo: This seems to be out of sync, find out the reason
453 # for the comment below and update it.
461 # for the comment below and update it.
454
462
455 # In case we want to extend this list we should be always in sync with
463 # In case we want to extend this list we should be always in sync with
456 # User.DEFAULT_USER_PERMISSIONS definitions
464 # User.DEFAULT_USER_PERMISSIONS definitions
457 _configurable = frozenset([
465 _configurable = frozenset([
458 'hg.fork.none', 'hg.fork.repository',
466 'hg.fork.none', 'hg.fork.repository',
459 'hg.create.none', 'hg.create.repository',
467 'hg.create.none', 'hg.create.repository',
460 'hg.usergroup.create.false', 'hg.usergroup.create.true',
468 'hg.usergroup.create.false', 'hg.usergroup.create.true',
461 'hg.repogroup.create.false', 'hg.repogroup.create.true',
469 'hg.repogroup.create.false', 'hg.repogroup.create.true',
462 'hg.create.write_on_repogroup.false',
470 'hg.create.write_on_repogroup.false',
463 'hg.create.write_on_repogroup.true',
471 'hg.create.write_on_repogroup.true',
464 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true'
472 'hg.inherit_default_perms.false', 'hg.inherit_default_perms.true'
465 ])
473 ])
466
474
467 # USER GROUPS comes first user group global permissions
475 # USER GROUPS comes first user group global permissions
468 user_perms_from_users_groups = Session().query(UserGroupToPerm)\
476 user_perms_from_users_groups = Session().query(UserGroupToPerm)\
469 .options(joinedload(UserGroupToPerm.permission))\
477 .options(joinedload(UserGroupToPerm.permission))\
470 .join((UserGroupMember, UserGroupToPerm.users_group_id ==
478 .join((UserGroupMember, UserGroupToPerm.users_group_id ==
471 UserGroupMember.users_group_id))\
479 UserGroupMember.users_group_id))\
472 .filter(UserGroupMember.user_id == self.user_id)\
480 .filter(UserGroupMember.user_id == self.user_id)\
473 .order_by(UserGroupToPerm.users_group_id)\
481 .order_by(UserGroupToPerm.users_group_id)\
474 .all()
482 .all()
475
483
476 # need to group here by groups since user can be in more than
484 # need to group here by groups since user can be in more than
477 # one group, so we get all groups
485 # one group, so we get all groups
478 _explicit_grouped_perms = [
486 _explicit_grouped_perms = [
479 [x, list(y)] for x, y in
487 [x, list(y)] for x, y in
480 itertools.groupby(user_perms_from_users_groups,
488 itertools.groupby(user_perms_from_users_groups,
481 lambda _x: _x.users_group)]
489 lambda _x: _x.users_group)]
482
490
483 for gr, perms in _explicit_grouped_perms:
491 for gr, perms in _explicit_grouped_perms:
484 # since user can be in multiple groups iterate over them and
492 # since user can be in multiple groups iterate over them and
485 # select the lowest permissions first (more explicit)
493 # select the lowest permissions first (more explicit)
486 # TODO: marcink: do this^^
494 # TODO: marcink: do this^^
487
495
488 # group doesn't inherit default permissions so we actually set them
496 # group doesn't inherit default permissions so we actually set them
489 if not gr.inherit_default_permissions:
497 if not gr.inherit_default_permissions:
490 # NEED TO IGNORE all previously set configurable permissions
498 # NEED TO IGNORE all previously set configurable permissions
491 # and replace them with explicitly set from this user
499 # and replace them with explicitly set from this user
492 # group permissions
500 # group permissions
493 self.permissions_global = self.permissions_global.difference(
501 self.permissions_global = self.permissions_global.difference(
494 _configurable)
502 _configurable)
495 for perm in perms:
503 for perm in perms:
496 self.permissions_global.add(perm.permission.permission_name)
504 self.permissions_global.add(perm.permission.permission_name)
497
505
498 # user explicit global permissions
506 # user explicit global permissions
499 user_perms = Session().query(UserToPerm)\
507 user_perms = Session().query(UserToPerm)\
500 .options(joinedload(UserToPerm.permission))\
508 .options(joinedload(UserToPerm.permission))\
501 .filter(UserToPerm.user_id == self.user_id).all()
509 .filter(UserToPerm.user_id == self.user_id).all()
502
510
503 if not self.inherit_default_permissions:
511 if not self.inherit_default_permissions:
504 # NEED TO IGNORE all configurable permissions and
512 # NEED TO IGNORE all configurable permissions and
505 # replace them with explicitly set from this user permissions
513 # replace them with explicitly set from this user permissions
506 self.permissions_global = self.permissions_global.difference(
514 self.permissions_global = self.permissions_global.difference(
507 _configurable)
515 _configurable)
508 for perm in user_perms:
516 for perm in user_perms:
509 self.permissions_global.add(perm.permission.permission_name)
517 self.permissions_global.add(perm.permission.permission_name)
510
518
511 def _calculate_default_permissions(self):
519 def _calculate_default_permissions(self):
512 """
520 """
513 Set default user permissions for repositories, repository groups
521 Set default user permissions for repositories, repository groups
514 taken from the default user.
522 taken from the default user.
515
523
516 Calculate inheritance of object permissions based on what we have now
524 Calculate inheritance of object permissions based on what we have now
517 in GLOBAL permissions. We check if .false is in GLOBAL since this is
525 in GLOBAL permissions. We check if .false is in GLOBAL since this is
518 explicitly set. Inherit is the opposite of .false being there.
526 explicitly set. Inherit is the opposite of .false being there.
519
527
520 .. note::
528 .. note::
521
529
522 the syntax is little bit odd but what we need to check here is
530 the syntax is little bit odd but what we need to check here is
523 the opposite of .false permission being in the list so even for
531 the opposite of .false permission being in the list so even for
524 inconsistent state when both .true/.false is there
532 inconsistent state when both .true/.false is there
525 .false is more important
533 .false is more important
526
534
527 """
535 """
528 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
536 user_inherit_object_permissions = not ('hg.inherit_default_perms.false'
529 in self.permissions_global)
537 in self.permissions_global)
530
538
531 # defaults for repositories, taken from `default` user permissions
539 # defaults for repositories, taken from `default` user permissions
532 # on given repo
540 # on given repo
533 for perm in self.default_repo_perms:
541 for perm in self.default_repo_perms:
534 r_k = perm.UserRepoToPerm.repository.repo_name
542 r_k = perm.UserRepoToPerm.repository.repo_name
535 p = perm.Permission.permission_name
543 p = perm.Permission.permission_name
536 o = PermOrigin.REPO_DEFAULT
544 o = PermOrigin.REPO_DEFAULT
537 self.permissions_repositories[r_k] = p, o
545 self.permissions_repositories[r_k] = p, o
538
546
539 # if we decide this user isn't inheriting permissions from
547 # if we decide this user isn't inheriting permissions from
540 # default user we set him to .none so only explicit
548 # default user we set him to .none so only explicit
541 # permissions work
549 # permissions work
542 if not user_inherit_object_permissions:
550 if not user_inherit_object_permissions:
543 p = 'repository.none'
551 p = 'repository.none'
544 o = PermOrigin.REPO_DEFAULT_NO_INHERIT
552 o = PermOrigin.REPO_DEFAULT_NO_INHERIT
545
553
546 self.permissions_repositories[r_k] = p, o
554 self.permissions_repositories[r_k] = p, o
547
555
548 if perm.Repository.private and not (
556 if perm.Repository.private and not (
549 perm.Repository.user_id == self.user_id):
557 perm.Repository.user_id == self.user_id):
550 # disable defaults for private repos,
558 # disable defaults for private repos,
551 p = 'repository.none'
559 p = 'repository.none'
552 o = PermOrigin.REPO_PRIVATE
560 o = PermOrigin.REPO_PRIVATE
553 self.permissions_repositories[r_k] = p, o
561 self.permissions_repositories[r_k] = p, o
554
562
555 elif perm.Repository.user_id == self.user_id:
563 elif perm.Repository.user_id == self.user_id:
556 # set admin if owner
564 # set admin if owner
557 p = 'repository.admin'
565 p = 'repository.admin'
558 o = PermOrigin.REPO_OWNER
566 o = PermOrigin.REPO_OWNER
559 self.permissions_repositories[r_k] = p, o
567 self.permissions_repositories[r_k] = p, o
560
568
569 if self.user_is_admin:
570 p = 'repository.admin'
571 o = PermOrigin.SUPER_ADMIN
572 self.permissions_repositories[r_k] = p, o
573
561 # defaults for repository groups taken from `default` user permission
574 # defaults for repository groups taken from `default` user permission
562 # on given group
575 # on given group
563 for perm in self.default_repo_groups_perms:
576 for perm in self.default_repo_groups_perms:
564 rg_k = perm.UserRepoGroupToPerm.group.group_name
577 rg_k = perm.UserRepoGroupToPerm.group.group_name
565 p = perm.Permission.permission_name
578 p = perm.Permission.permission_name
566 o = PermOrigin.REPOGROUP_DEFAULT
579 o = PermOrigin.REPOGROUP_DEFAULT
567 self.permissions_repository_groups[rg_k] = p, o
580 self.permissions_repository_groups[rg_k] = p, o
568
581
569 # if we decide this user isn't inheriting permissions from default
582 # if we decide this user isn't inheriting permissions from default
570 # user we set him to .none so only explicit permissions work
583 # user we set him to .none so only explicit permissions work
571 if not user_inherit_object_permissions:
584 if not user_inherit_object_permissions:
572 p = 'group.none'
585 p = 'group.none'
573 o = PermOrigin.REPOGROUP_DEFAULT_NO_INHERIT
586 o = PermOrigin.REPOGROUP_DEFAULT_NO_INHERIT
574 self.permissions_repository_groups[rg_k] = p, o
587 self.permissions_repository_groups[rg_k] = p, o
575
588
576 if perm.RepoGroup.user_id == self.user_id:
589 if perm.RepoGroup.user_id == self.user_id:
577 # set admin if owner
590 # set admin if owner
578 p = 'group.admin'
591 p = 'group.admin'
579 o = PermOrigin.REPOGROUP_OWNER
592 o = PermOrigin.REPOGROUP_OWNER
580 self.permissions_repository_groups[rg_k] = p, o
593 self.permissions_repository_groups[rg_k] = p, o
581
594
595 if self.user_is_admin:
596 p = 'group.admin'
597 o = PermOrigin.SUPER_ADMIN
598 self.permissions_repository_groups[rg_k] = p, o
599
582 # defaults for user groups taken from `default` user permission
600 # defaults for user groups taken from `default` user permission
583 # on given user group
601 # on given user group
584 for perm in self.default_user_group_perms:
602 for perm in self.default_user_group_perms:
585 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
603 u_k = perm.UserUserGroupToPerm.user_group.users_group_name
586 p = perm.Permission.permission_name
604 p = perm.Permission.permission_name
587 o = PermOrigin.USERGROUP_DEFAULT
605 o = PermOrigin.USERGROUP_DEFAULT
588 self.permissions_user_groups[u_k] = p, o
606 self.permissions_user_groups[u_k] = p, o
589
607
590 # if we decide this user isn't inheriting permissions from default
608 # if we decide this user isn't inheriting permissions from default
591 # user we set him to .none so only explicit permissions work
609 # user we set him to .none so only explicit permissions work
592 if not user_inherit_object_permissions:
610 if not user_inherit_object_permissions:
593 p = 'usergroup.none'
611 p = 'usergroup.none'
594 o = PermOrigin.USERGROUP_DEFAULT_NO_INHERIT
612 o = PermOrigin.USERGROUP_DEFAULT_NO_INHERIT
595 self.permissions_user_groups[u_k] = p, o
613 self.permissions_user_groups[u_k] = p, o
596
614
597 if perm.UserGroup.user_id == self.user_id:
615 if perm.UserGroup.user_id == self.user_id:
598 # set admin if owner
616 # set admin if owner
599 p = 'usergroup.admin'
617 p = 'usergroup.admin'
600 o = PermOrigin.USERGROUP_OWNER
618 o = PermOrigin.USERGROUP_OWNER
601 self.permissions_user_groups[u_k] = p, o
619 self.permissions_user_groups[u_k] = p, o
602
620
621 if self.user_is_admin:
622 p = 'usergroup.admin'
623 o = PermOrigin.SUPER_ADMIN
624 self.permissions_user_groups[u_k] = p, o
625
603 def _calculate_repository_permissions(self):
626 def _calculate_repository_permissions(self):
604 """
627 """
605 Repository permissions for the current user.
628 Repository permissions for the current user.
606
629
607 Check if the user is part of user groups for this repository and
630 Check if the user is part of user groups for this repository and
608 fill in the permission from it. `_choose_permission` decides of which
631 fill in the permission from it. `_choose_permission` decides of which
609 permission should be selected based on selected method.
632 permission should be selected based on selected method.
610 """
633 """
611
634
612 # user group for repositories permissions
635 # user group for repositories permissions
613 user_repo_perms_from_user_group = Permission\
636 user_repo_perms_from_user_group = Permission\
614 .get_default_repo_perms_from_user_group(
637 .get_default_repo_perms_from_user_group(
615 self.user_id, self.scope_repo_id)
638 self.user_id, self.scope_repo_id)
616
639
617 multiple_counter = collections.defaultdict(int)
640 multiple_counter = collections.defaultdict(int)
618 for perm in user_repo_perms_from_user_group:
641 for perm in user_repo_perms_from_user_group:
619 r_k = perm.UserGroupRepoToPerm.repository.repo_name
642 r_k = perm.UserGroupRepoToPerm.repository.repo_name
620 multiple_counter[r_k] += 1
643 multiple_counter[r_k] += 1
621 p = perm.Permission.permission_name
644 p = perm.Permission.permission_name
622 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
645 o = PermOrigin.REPO_USERGROUP % perm.UserGroupRepoToPerm\
623 .users_group.users_group_name
646 .users_group.users_group_name
624
647
625 if multiple_counter[r_k] > 1:
648 if multiple_counter[r_k] > 1:
626 cur_perm = self.permissions_repositories[r_k]
649 cur_perm = self.permissions_repositories[r_k]
627 p = self._choose_permission(p, cur_perm)
650 p = self._choose_permission(p, cur_perm)
628
651
629 self.permissions_repositories[r_k] = p, o
652 self.permissions_repositories[r_k] = p, o
630
653
631 if perm.Repository.user_id == self.user_id:
654 if perm.Repository.user_id == self.user_id:
632 # set admin if owner
655 # set admin if owner
633 p = 'repository.admin'
656 p = 'repository.admin'
634 o = PermOrigin.REPO_OWNER
657 o = PermOrigin.REPO_OWNER
635 self.permissions_repositories[r_k] = p, o
658 self.permissions_repositories[r_k] = p, o
636
659
660 if self.user_is_admin:
661 p = 'repository.admin'
662 o = PermOrigin.SUPER_ADMIN
663 self.permissions_repositories[r_k] = p, o
664
637 # user explicit permissions for repositories, overrides any specified
665 # user explicit permissions for repositories, overrides any specified
638 # by the group permission
666 # by the group permission
639 user_repo_perms = Permission.get_default_repo_perms(
667 user_repo_perms = Permission.get_default_repo_perms(
640 self.user_id, self.scope_repo_id)
668 self.user_id, self.scope_repo_id)
641 for perm in user_repo_perms:
669 for perm in user_repo_perms:
642 r_k = perm.UserRepoToPerm.repository.repo_name
670 r_k = perm.UserRepoToPerm.repository.repo_name
643 p = perm.Permission.permission_name
671 p = perm.Permission.permission_name
644 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
672 o = PermOrigin.REPO_USER % perm.UserRepoToPerm.user.username
645
673
646 if not self.explicit:
674 if not self.explicit:
647 cur_perm = self.permissions_repositories.get(
675 cur_perm = self.permissions_repositories.get(
648 r_k, 'repository.none')
676 r_k, 'repository.none')
649 p = self._choose_permission(p, cur_perm)
677 p = self._choose_permission(p, cur_perm)
650
678
651 self.permissions_repositories[r_k] = p, o
679 self.permissions_repositories[r_k] = p, o
652
680
653 if perm.Repository.user_id == self.user_id:
681 if perm.Repository.user_id == self.user_id:
654 # set admin if owner
682 # set admin if owner
655 p = 'repository.admin'
683 p = 'repository.admin'
656 o = PermOrigin.REPO_OWNER
684 o = PermOrigin.REPO_OWNER
657 self.permissions_repositories[r_k] = p, o
685 self.permissions_repositories[r_k] = p, o
658
686
687 if self.user_is_admin:
688 p = 'repository.admin'
689 o = PermOrigin.SUPER_ADMIN
690 self.permissions_repositories[r_k] = p, o
691
659 def _calculate_repository_group_permissions(self):
692 def _calculate_repository_group_permissions(self):
660 """
693 """
661 Repository group permissions for the current user.
694 Repository group permissions for the current user.
662
695
663 Check if the user is part of user groups for repository groups and
696 Check if the user is part of user groups for repository groups and
664 fill in the permissions from it. `_choose_permission` decides of which
697 fill in the permissions from it. `_choose_permission` decides of which
665 permission should be selected based on selected method.
698 permission should be selected based on selected method.
666 """
699 """
667 # user group for repo groups permissions
700 # user group for repo groups permissions
668 user_repo_group_perms_from_user_group = Permission\
701 user_repo_group_perms_from_user_group = Permission\
669 .get_default_group_perms_from_user_group(
702 .get_default_group_perms_from_user_group(
670 self.user_id, self.scope_repo_group_id)
703 self.user_id, self.scope_repo_group_id)
671
704
672 multiple_counter = collections.defaultdict(int)
705 multiple_counter = collections.defaultdict(int)
673 for perm in user_repo_group_perms_from_user_group:
706 for perm in user_repo_group_perms_from_user_group:
674 rg_k = perm.UserGroupRepoGroupToPerm.group.group_name
707 rg_k = perm.UserGroupRepoGroupToPerm.group.group_name
675 multiple_counter[rg_k] += 1
708 multiple_counter[rg_k] += 1
676 o = PermOrigin.REPOGROUP_USERGROUP % perm.UserGroupRepoGroupToPerm\
709 o = PermOrigin.REPOGROUP_USERGROUP % perm.UserGroupRepoGroupToPerm\
677 .users_group.users_group_name
710 .users_group.users_group_name
678 p = perm.Permission.permission_name
711 p = perm.Permission.permission_name
679
712
680 if multiple_counter[rg_k] > 1:
713 if multiple_counter[rg_k] > 1:
681 cur_perm = self.permissions_repository_groups[rg_k]
714 cur_perm = self.permissions_repository_groups[rg_k]
682 p = self._choose_permission(p, cur_perm)
715 p = self._choose_permission(p, cur_perm)
683 self.permissions_repository_groups[rg_k] = p, o
716 self.permissions_repository_groups[rg_k] = p, o
684
717
685 if perm.RepoGroup.user_id == self.user_id:
718 if perm.RepoGroup.user_id == self.user_id:
686 # set admin if owner, even for member of other user group
719 # set admin if owner, even for member of other user group
687 p = 'group.admin'
720 p = 'group.admin'
688 o = PermOrigin.REPOGROUP_OWNER
721 o = PermOrigin.REPOGROUP_OWNER
689 self.permissions_repository_groups[rg_k] = p, o
722 self.permissions_repository_groups[rg_k] = p, o
690
723
724 if self.user_is_admin:
725 p = 'group.admin'
726 o = PermOrigin.SUPER_ADMIN
727 self.permissions_repository_groups[rg_k] = p, o
728
691 # user explicit permissions for repository groups
729 # user explicit permissions for repository groups
692 user_repo_groups_perms = Permission.get_default_group_perms(
730 user_repo_groups_perms = Permission.get_default_group_perms(
693 self.user_id, self.scope_repo_group_id)
731 self.user_id, self.scope_repo_group_id)
694 for perm in user_repo_groups_perms:
732 for perm in user_repo_groups_perms:
695 rg_k = perm.UserRepoGroupToPerm.group.group_name
733 rg_k = perm.UserRepoGroupToPerm.group.group_name
696 o = PermOrigin.REPOGROUP_USER % perm.UserRepoGroupToPerm\
734 o = PermOrigin.REPOGROUP_USER % perm.UserRepoGroupToPerm\
697 .user.username
735 .user.username
698 p = perm.Permission.permission_name
736 p = perm.Permission.permission_name
699
737
700 if not self.explicit:
738 if not self.explicit:
701 cur_perm = self.permissions_repository_groups.get(
739 cur_perm = self.permissions_repository_groups.get(
702 rg_k, 'group.none')
740 rg_k, 'group.none')
703 p = self._choose_permission(p, cur_perm)
741 p = self._choose_permission(p, cur_perm)
704
742
705 self.permissions_repository_groups[rg_k] = p, o
743 self.permissions_repository_groups[rg_k] = p, o
706
744
707 if perm.RepoGroup.user_id == self.user_id:
745 if perm.RepoGroup.user_id == self.user_id:
708 # set admin if owner
746 # set admin if owner
709 p = 'group.admin'
747 p = 'group.admin'
710 o = PermOrigin.REPOGROUP_OWNER
748 o = PermOrigin.REPOGROUP_OWNER
711 self.permissions_repository_groups[rg_k] = p, o
749 self.permissions_repository_groups[rg_k] = p, o
712
750
751 if self.user_is_admin:
752 p = 'group.admin'
753 o = PermOrigin.SUPER_ADMIN
754 self.permissions_repository_groups[rg_k] = p, o
755
713 def _calculate_user_group_permissions(self):
756 def _calculate_user_group_permissions(self):
714 """
757 """
715 User group permissions for the current user.
758 User group permissions for the current user.
716 """
759 """
717 # user group for user group permissions
760 # user group for user group permissions
718 user_group_from_user_group = Permission\
761 user_group_from_user_group = Permission\
719 .get_default_user_group_perms_from_user_group(
762 .get_default_user_group_perms_from_user_group(
720 self.user_id, self.scope_user_group_id)
763 self.user_id, self.scope_user_group_id)
721
764
722 multiple_counter = collections.defaultdict(int)
765 multiple_counter = collections.defaultdict(int)
723 for perm in user_group_from_user_group:
766 for perm in user_group_from_user_group:
724 ug_k = perm.UserGroupUserGroupToPerm\
767 ug_k = perm.UserGroupUserGroupToPerm\
725 .target_user_group.users_group_name
768 .target_user_group.users_group_name
726 multiple_counter[ug_k] += 1
769 multiple_counter[ug_k] += 1
727 o = PermOrigin.USERGROUP_USERGROUP % perm.UserGroupUserGroupToPerm\
770 o = PermOrigin.USERGROUP_USERGROUP % perm.UserGroupUserGroupToPerm\
728 .user_group.users_group_name
771 .user_group.users_group_name
729 p = perm.Permission.permission_name
772 p = perm.Permission.permission_name
730
773
731 if multiple_counter[ug_k] > 1:
774 if multiple_counter[ug_k] > 1:
732 cur_perm = self.permissions_user_groups[ug_k]
775 cur_perm = self.permissions_user_groups[ug_k]
733 p = self._choose_permission(p, cur_perm)
776 p = self._choose_permission(p, cur_perm)
734
777
735 self.permissions_user_groups[ug_k] = p, o
778 self.permissions_user_groups[ug_k] = p, o
736
779
737 if perm.UserGroup.user_id == self.user_id:
780 if perm.UserGroup.user_id == self.user_id:
738 # set admin if owner, even for member of other user group
781 # set admin if owner, even for member of other user group
739 p = 'usergroup.admin'
782 p = 'usergroup.admin'
740 o = PermOrigin.USERGROUP_OWNER
783 o = PermOrigin.USERGROUP_OWNER
741 self.permissions_user_groups[ug_k] = p, o
784 self.permissions_user_groups[ug_k] = p, o
742
785
786 if self.user_is_admin:
787 p = 'usergroup.admin'
788 o = PermOrigin.SUPER_ADMIN
789 self.permissions_user_groups[ug_k] = p, o
790
743 # user explicit permission for user groups
791 # user explicit permission for user groups
744 user_user_groups_perms = Permission.get_default_user_group_perms(
792 user_user_groups_perms = Permission.get_default_user_group_perms(
745 self.user_id, self.scope_user_group_id)
793 self.user_id, self.scope_user_group_id)
746 for perm in user_user_groups_perms:
794 for perm in user_user_groups_perms:
747 ug_k = perm.UserUserGroupToPerm.user_group.users_group_name
795 ug_k = perm.UserUserGroupToPerm.user_group.users_group_name
748 o = PermOrigin.USERGROUP_USER % perm.UserUserGroupToPerm\
796 o = PermOrigin.USERGROUP_USER % perm.UserUserGroupToPerm\
749 .user.username
797 .user.username
750 p = perm.Permission.permission_name
798 p = perm.Permission.permission_name
751
799
752 if not self.explicit:
800 if not self.explicit:
753 cur_perm = self.permissions_user_groups.get(
801 cur_perm = self.permissions_user_groups.get(
754 ug_k, 'usergroup.none')
802 ug_k, 'usergroup.none')
755 p = self._choose_permission(p, cur_perm)
803 p = self._choose_permission(p, cur_perm)
756
804
757 self.permissions_user_groups[ug_k] = p, o
805 self.permissions_user_groups[ug_k] = p, o
758
806
759 if perm.UserGroup.user_id == self.user_id:
807 if perm.UserGroup.user_id == self.user_id:
760 # set admin if owner
808 # set admin if owner
761 p = 'usergroup.admin'
809 p = 'usergroup.admin'
762 o = PermOrigin.USERGROUP_OWNER
810 o = PermOrigin.USERGROUP_OWNER
763 self.permissions_user_groups[ug_k] = p, o
811 self.permissions_user_groups[ug_k] = p, o
764
812
813 if self.user_is_admin:
814 p = 'usergroup.admin'
815 o = PermOrigin.SUPER_ADMIN
816 self.permissions_user_groups[ug_k] = p, o
817
765 def _choose_permission(self, new_perm, cur_perm):
818 def _choose_permission(self, new_perm, cur_perm):
766 new_perm_val = Permission.PERM_WEIGHTS[new_perm]
819 new_perm_val = Permission.PERM_WEIGHTS[new_perm]
767 cur_perm_val = Permission.PERM_WEIGHTS[cur_perm]
820 cur_perm_val = Permission.PERM_WEIGHTS[cur_perm]
768 if self.algo == 'higherwin':
821 if self.algo == 'higherwin':
769 if new_perm_val > cur_perm_val:
822 if new_perm_val > cur_perm_val:
770 return new_perm
823 return new_perm
771 return cur_perm
824 return cur_perm
772 elif self.algo == 'lowerwin':
825 elif self.algo == 'lowerwin':
773 if new_perm_val < cur_perm_val:
826 if new_perm_val < cur_perm_val:
774 return new_perm
827 return new_perm
775 return cur_perm
828 return cur_perm
776
829
777 def _permission_structure(self):
830 def _permission_structure(self):
778 return {
831 return {
779 'global': self.permissions_global,
832 'global': self.permissions_global,
780 'repositories': self.permissions_repositories,
833 'repositories': self.permissions_repositories,
781 'repositories_groups': self.permissions_repository_groups,
834 'repositories_groups': self.permissions_repository_groups,
782 'user_groups': self.permissions_user_groups,
835 'user_groups': self.permissions_user_groups,
783 }
836 }
784
837
785
838
786 def allowed_auth_token_access(view_name, auth_token, whitelist=None):
839 def allowed_auth_token_access(view_name, auth_token, whitelist=None):
787 """
840 """
788 Check if given controller_name is in whitelist of auth token access
841 Check if given controller_name is in whitelist of auth token access
789 """
842 """
790 if not whitelist:
843 if not whitelist:
791 from rhodecode import CONFIG
844 from rhodecode import CONFIG
792 whitelist = aslist(
845 whitelist = aslist(
793 CONFIG.get('api_access_controllers_whitelist'), sep=',')
846 CONFIG.get('api_access_controllers_whitelist'), sep=',')
794 # backward compat translation
847 # backward compat translation
795 compat = {
848 compat = {
796 # old controller, new VIEW
849 # old controller, new VIEW
797 'ChangesetController:*': 'RepoCommitsView:*',
850 'ChangesetController:*': 'RepoCommitsView:*',
798 'ChangesetController:changeset_patch': 'RepoCommitsView:repo_commit_patch',
851 'ChangesetController:changeset_patch': 'RepoCommitsView:repo_commit_patch',
799 'ChangesetController:changeset_raw': 'RepoCommitsView:repo_commit_raw',
852 'ChangesetController:changeset_raw': 'RepoCommitsView:repo_commit_raw',
800 'FilesController:raw': 'RepoCommitsView:repo_commit_raw',
853 'FilesController:raw': 'RepoCommitsView:repo_commit_raw',
801 'FilesController:archivefile': 'RepoFilesView:repo_archivefile',
854 'FilesController:archivefile': 'RepoFilesView:repo_archivefile',
802 'GistsController:*': 'GistView:*',
855 'GistsController:*': 'GistView:*',
803 }
856 }
804
857
805 log.debug(
858 log.debug(
806 'Allowed views for AUTH TOKEN access: %s' % (whitelist,))
859 'Allowed views for AUTH TOKEN access: %s' % (whitelist,))
807 auth_token_access_valid = False
860 auth_token_access_valid = False
808
861
809 for entry in whitelist:
862 for entry in whitelist:
810 token_match = True
863 token_match = True
811 if entry in compat:
864 if entry in compat:
812 # translate from old Controllers to Pyramid Views
865 # translate from old Controllers to Pyramid Views
813 entry = compat[entry]
866 entry = compat[entry]
814
867
815 if '@' in entry:
868 if '@' in entry:
816 # specific AuthToken
869 # specific AuthToken
817 entry, allowed_token = entry.split('@', 1)
870 entry, allowed_token = entry.split('@', 1)
818 token_match = auth_token == allowed_token
871 token_match = auth_token == allowed_token
819
872
820 if fnmatch.fnmatch(view_name, entry) and token_match:
873 if fnmatch.fnmatch(view_name, entry) and token_match:
821 auth_token_access_valid = True
874 auth_token_access_valid = True
822 break
875 break
823
876
824 if auth_token_access_valid:
877 if auth_token_access_valid:
825 log.debug('view: `%s` matches entry in whitelist: %s'
878 log.debug('view: `%s` matches entry in whitelist: %s'
826 % (view_name, whitelist))
879 % (view_name, whitelist))
827 else:
880 else:
828 msg = ('view: `%s` does *NOT* match any entry in whitelist: %s'
881 msg = ('view: `%s` does *NOT* match any entry in whitelist: %s'
829 % (view_name, whitelist))
882 % (view_name, whitelist))
830 if auth_token:
883 if auth_token:
831 # if we use auth token key and don't have access it's a warning
884 # if we use auth token key and don't have access it's a warning
832 log.warning(msg)
885 log.warning(msg)
833 else:
886 else:
834 log.debug(msg)
887 log.debug(msg)
835
888
836 return auth_token_access_valid
889 return auth_token_access_valid
837
890
838
891
839 class AuthUser(object):
892 class AuthUser(object):
840 """
893 """
841 A simple object that handles all attributes of user in RhodeCode
894 A simple object that handles all attributes of user in RhodeCode
842
895
843 It does lookup based on API key,given user, or user present in session
896 It does lookup based on API key,given user, or user present in session
844 Then it fills all required information for such user. It also checks if
897 Then it fills all required information for such user. It also checks if
845 anonymous access is enabled and if so, it returns default user as logged in
898 anonymous access is enabled and if so, it returns default user as logged in
846 """
899 """
847 GLOBAL_PERMS = [x[0] for x in Permission.PERMS]
900 GLOBAL_PERMS = [x[0] for x in Permission.PERMS]
848
901
849 def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):
902 def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None):
850
903
851 self.user_id = user_id
904 self.user_id = user_id
852 self._api_key = api_key
905 self._api_key = api_key
853
906
854 self.api_key = None
907 self.api_key = None
855 self.feed_token = ''
908 self.feed_token = ''
856 self.username = username
909 self.username = username
857 self.ip_addr = ip_addr
910 self.ip_addr = ip_addr
858 self.name = ''
911 self.name = ''
859 self.lastname = ''
912 self.lastname = ''
860 self.first_name = ''
913 self.first_name = ''
861 self.last_name = ''
914 self.last_name = ''
862 self.email = ''
915 self.email = ''
863 self.is_authenticated = False
916 self.is_authenticated = False
864 self.admin = False
917 self.admin = False
865 self.inherit_default_permissions = False
918 self.inherit_default_permissions = False
866 self.password = ''
919 self.password = ''
867
920
868 self.anonymous_user = None # propagated on propagate_data
921 self.anonymous_user = None # propagated on propagate_data
869 self.propagate_data()
922 self.propagate_data()
870 self._instance = None
923 self._instance = None
871 self._permissions_scoped_cache = {} # used to bind scoped calculation
924 self._permissions_scoped_cache = {} # used to bind scoped calculation
872
925
873 @LazyProperty
926 @LazyProperty
874 def permissions(self):
927 def permissions(self):
875 return self.get_perms(user=self, cache=False)
928 return self.get_perms(user=self, cache=False)
876
929
930 @LazyProperty
931 def permissions_full_details(self):
932 return self.get_perms(
933 user=self, cache=False, calculate_super_admin=True)
934
877 def permissions_with_scope(self, scope):
935 def permissions_with_scope(self, scope):
878 """
936 """
879 Call the get_perms function with scoped data. The scope in that function
937 Call the get_perms function with scoped data. The scope in that function
880 narrows the SQL calls to the given ID of objects resulting in fetching
938 narrows the SQL calls to the given ID of objects resulting in fetching
881 Just particular permission we want to obtain. If scope is an empty dict
939 Just particular permission we want to obtain. If scope is an empty dict
882 then it basically narrows the scope to GLOBAL permissions only.
940 then it basically narrows the scope to GLOBAL permissions only.
883
941
884 :param scope: dict
942 :param scope: dict
885 """
943 """
886 if 'repo_name' in scope:
944 if 'repo_name' in scope:
887 obj = Repository.get_by_repo_name(scope['repo_name'])
945 obj = Repository.get_by_repo_name(scope['repo_name'])
888 if obj:
946 if obj:
889 scope['repo_id'] = obj.repo_id
947 scope['repo_id'] = obj.repo_id
890 _scope = {
948 _scope = {
891 'repo_id': -1,
949 'repo_id': -1,
892 'user_group_id': -1,
950 'user_group_id': -1,
893 'repo_group_id': -1,
951 'repo_group_id': -1,
894 }
952 }
895 _scope.update(scope)
953 _scope.update(scope)
896 cache_key = "_".join(map(safe_str, reduce(lambda a, b: a+b,
954 cache_key = "_".join(map(safe_str, reduce(lambda a, b: a+b,
897 _scope.items())))
955 _scope.items())))
898 if cache_key not in self._permissions_scoped_cache:
956 if cache_key not in self._permissions_scoped_cache:
899 # store in cache to mimic how the @LazyProperty works,
957 # store in cache to mimic how the @LazyProperty works,
900 # the difference here is that we use the unique key calculated
958 # the difference here is that we use the unique key calculated
901 # from params and values
959 # from params and values
902 res = self.get_perms(user=self, cache=False, scope=_scope)
960 res = self.get_perms(user=self, cache=False, scope=_scope)
903 self._permissions_scoped_cache[cache_key] = res
961 self._permissions_scoped_cache[cache_key] = res
904 return self._permissions_scoped_cache[cache_key]
962 return self._permissions_scoped_cache[cache_key]
905
963
906 def get_instance(self):
964 def get_instance(self):
907 return User.get(self.user_id)
965 return User.get(self.user_id)
908
966
909 def update_lastactivity(self):
967 def update_lastactivity(self):
910 if self.user_id:
968 if self.user_id:
911 User.get(self.user_id).update_lastactivity()
969 User.get(self.user_id).update_lastactivity()
912
970
913 def propagate_data(self):
971 def propagate_data(self):
914 """
972 """
915 Fills in user data and propagates values to this instance. Maps fetched
973 Fills in user data and propagates values to this instance. Maps fetched
916 user attributes to this class instance attributes
974 user attributes to this class instance attributes
917 """
975 """
918 log.debug('AuthUser: starting data propagation for new potential user')
976 log.debug('AuthUser: starting data propagation for new potential user')
919 user_model = UserModel()
977 user_model = UserModel()
920 anon_user = self.anonymous_user = User.get_default_user(cache=True)
978 anon_user = self.anonymous_user = User.get_default_user(cache=True)
921 is_user_loaded = False
979 is_user_loaded = False
922
980
923 # lookup by userid
981 # lookup by userid
924 if self.user_id is not None and self.user_id != anon_user.user_id:
982 if self.user_id is not None and self.user_id != anon_user.user_id:
925 log.debug('Trying Auth User lookup by USER ID: `%s`', self.user_id)
983 log.debug('Trying Auth User lookup by USER ID: `%s`', self.user_id)
926 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
984 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
927
985
928 # try go get user by api key
986 # try go get user by api key
929 elif self._api_key and self._api_key != anon_user.api_key:
987 elif self._api_key and self._api_key != anon_user.api_key:
930 log.debug('Trying Auth User lookup by API KEY: `%s`', self._api_key)
988 log.debug('Trying Auth User lookup by API KEY: `%s`', self._api_key)
931 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
989 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
932
990
933 # lookup by username
991 # lookup by username
934 elif self.username:
992 elif self.username:
935 log.debug('Trying Auth User lookup by USER NAME: `%s`', self.username)
993 log.debug('Trying Auth User lookup by USER NAME: `%s`', self.username)
936 is_user_loaded = user_model.fill_data(self, username=self.username)
994 is_user_loaded = user_model.fill_data(self, username=self.username)
937 else:
995 else:
938 log.debug('No data in %s that could been used to log in', self)
996 log.debug('No data in %s that could been used to log in', self)
939
997
940 if not is_user_loaded:
998 if not is_user_loaded:
941 log.debug('Failed to load user. Fallback to default user')
999 log.debug('Failed to load user. Fallback to default user')
942 # if we cannot authenticate user try anonymous
1000 # if we cannot authenticate user try anonymous
943 if anon_user.active:
1001 if anon_user.active:
944 user_model.fill_data(self, user_id=anon_user.user_id)
1002 user_model.fill_data(self, user_id=anon_user.user_id)
945 # then we set this user is logged in
1003 # then we set this user is logged in
946 self.is_authenticated = True
1004 self.is_authenticated = True
947 else:
1005 else:
948 # in case of disabled anonymous user we reset some of the
1006 # in case of disabled anonymous user we reset some of the
949 # parameters so such user is "corrupted", skipping the fill_data
1007 # parameters so such user is "corrupted", skipping the fill_data
950 for attr in ['user_id', 'username', 'admin', 'active']:
1008 for attr in ['user_id', 'username', 'admin', 'active']:
951 setattr(self, attr, None)
1009 setattr(self, attr, None)
952 self.is_authenticated = False
1010 self.is_authenticated = False
953
1011
954 if not self.username:
1012 if not self.username:
955 self.username = 'None'
1013 self.username = 'None'
956
1014
957 log.debug('AuthUser: propagated user is now %s', self)
1015 log.debug('AuthUser: propagated user is now %s', self)
958
1016
959 def get_perms(self, user, scope=None, explicit=True, algo='higherwin',
1017 def get_perms(self, user, scope=None, explicit=True, algo='higherwin',
960 cache=False):
1018 calculate_super_admin=False, cache=False):
961 """
1019 """
962 Fills user permission attribute with permissions taken from database
1020 Fills user permission attribute with permissions taken from database
963 works for permissions given for repositories, and for permissions that
1021 works for permissions given for repositories, and for permissions that
964 are granted to groups
1022 are granted to groups
965
1023
966 :param user: instance of User object from database
1024 :param user: instance of User object from database
967 :param explicit: In case there are permissions both for user and a group
1025 :param explicit: In case there are permissions both for user and a group
968 that user is part of, explicit flag will defiine if user will
1026 that user is part of, explicit flag will defiine if user will
969 explicitly override permissions from group, if it's False it will
1027 explicitly override permissions from group, if it's False it will
970 make decision based on the algo
1028 make decision based on the algo
971 :param algo: algorithm to decide what permission should be choose if
1029 :param algo: algorithm to decide what permission should be choose if
972 it's multiple defined, eg user in two different groups. It also
1030 it's multiple defined, eg user in two different groups. It also
973 decides if explicit flag is turned off how to specify the permission
1031 decides if explicit flag is turned off how to specify the permission
974 for case when user is in a group + have defined separate permission
1032 for case when user is in a group + have defined separate permission
975 """
1033 """
976 user_id = user.user_id
1034 user_id = user.user_id
977 user_is_admin = user.is_admin
1035 user_is_admin = user.is_admin
978
1036
979 # inheritance of global permissions like create repo/fork repo etc
1037 # inheritance of global permissions like create repo/fork repo etc
980 user_inherit_default_permissions = user.inherit_default_permissions
1038 user_inherit_default_permissions = user.inherit_default_permissions
981
1039
982 log.debug('Computing PERMISSION tree for scope %s' % (scope, ))
1040 log.debug('Computing PERMISSION tree for scope %s' % (scope, ))
983 compute = caches.conditional_cache(
1041 compute = caches.conditional_cache(
984 'short_term', 'cache_desc',
1042 'short_term', 'cache_desc',
985 condition=cache, func=_cached_perms_data)
1043 condition=cache, func=_cached_perms_data)
986 result = compute(user_id, scope, user_is_admin,
1044 result = compute(user_id, scope, user_is_admin,
987 user_inherit_default_permissions, explicit, algo)
1045 user_inherit_default_permissions, explicit, algo,
1046 calculate_super_admin)
988
1047
989 result_repr = []
1048 result_repr = []
990 for k in result:
1049 for k in result:
991 result_repr.append((k, len(result[k])))
1050 result_repr.append((k, len(result[k])))
992
1051
993 log.debug('PERMISSION tree computed %s' % (result_repr,))
1052 log.debug('PERMISSION tree computed %s' % (result_repr,))
994 return result
1053 return result
995
1054
996 @property
1055 @property
997 def is_default(self):
1056 def is_default(self):
998 return self.username == User.DEFAULT_USER
1057 return self.username == User.DEFAULT_USER
999
1058
1000 @property
1059 @property
1001 def is_admin(self):
1060 def is_admin(self):
1002 return self.admin
1061 return self.admin
1003
1062
1004 @property
1063 @property
1005 def is_user_object(self):
1064 def is_user_object(self):
1006 return self.user_id is not None
1065 return self.user_id is not None
1007
1066
1008 @property
1067 @property
1009 def repositories_admin(self):
1068 def repositories_admin(self):
1010 """
1069 """
1011 Returns list of repositories you're an admin of
1070 Returns list of repositories you're an admin of
1012 """
1071 """
1013 return [
1072 return [
1014 x[0] for x in self.permissions['repositories'].iteritems()
1073 x[0] for x in self.permissions['repositories'].iteritems()
1015 if x[1] == 'repository.admin']
1074 if x[1] == 'repository.admin']
1016
1075
1017 @property
1076 @property
1018 def repository_groups_admin(self):
1077 def repository_groups_admin(self):
1019 """
1078 """
1020 Returns list of repository groups you're an admin of
1079 Returns list of repository groups you're an admin of
1021 """
1080 """
1022 return [
1081 return [
1023 x[0] for x in self.permissions['repositories_groups'].iteritems()
1082 x[0] for x in self.permissions['repositories_groups'].iteritems()
1024 if x[1] == 'group.admin']
1083 if x[1] == 'group.admin']
1025
1084
1026 @property
1085 @property
1027 def user_groups_admin(self):
1086 def user_groups_admin(self):
1028 """
1087 """
1029 Returns list of user groups you're an admin of
1088 Returns list of user groups you're an admin of
1030 """
1089 """
1031 return [
1090 return [
1032 x[0] for x in self.permissions['user_groups'].iteritems()
1091 x[0] for x in self.permissions['user_groups'].iteritems()
1033 if x[1] == 'usergroup.admin']
1092 if x[1] == 'usergroup.admin']
1034
1093
1035 def repo_acl_ids(self, perms=None, name_filter=None, cache=False):
1094 def repo_acl_ids(self, perms=None, name_filter=None, cache=False):
1036 """
1095 """
1037 Returns list of repository ids that user have access to based on given
1096 Returns list of repository ids that user have access to based on given
1038 perms. The cache flag should be only used in cases that are used for
1097 perms. The cache flag should be only used in cases that are used for
1039 display purposes, NOT IN ANY CASE for permission checks.
1098 display purposes, NOT IN ANY CASE for permission checks.
1040 """
1099 """
1041 from rhodecode.model.scm import RepoList
1100 from rhodecode.model.scm import RepoList
1042 if not perms:
1101 if not perms:
1043 perms = [
1102 perms = [
1044 'repository.read', 'repository.write', 'repository.admin']
1103 'repository.read', 'repository.write', 'repository.admin']
1045
1104
1046 def _cached_repo_acl(user_id, perm_def, name_filter):
1105 def _cached_repo_acl(user_id, perm_def, name_filter):
1047 qry = Repository.query()
1106 qry = Repository.query()
1048 if name_filter:
1107 if name_filter:
1049 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1108 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1050 qry = qry.filter(
1109 qry = qry.filter(
1051 Repository.repo_name.ilike(ilike_expression))
1110 Repository.repo_name.ilike(ilike_expression))
1052
1111
1053 return [x.repo_id for x in
1112 return [x.repo_id for x in
1054 RepoList(qry, perm_set=perm_def)]
1113 RepoList(qry, perm_set=perm_def)]
1055
1114
1056 compute = caches.conditional_cache(
1115 compute = caches.conditional_cache(
1057 'long_term', 'repo_acl_ids',
1116 'long_term', 'repo_acl_ids',
1058 condition=cache, func=_cached_repo_acl)
1117 condition=cache, func=_cached_repo_acl)
1059 return compute(self.user_id, perms, name_filter)
1118 return compute(self.user_id, perms, name_filter)
1060
1119
1061 def repo_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1120 def repo_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1062 """
1121 """
1063 Returns list of repository group ids that user have access to based on given
1122 Returns list of repository group ids that user have access to based on given
1064 perms. The cache flag should be only used in cases that are used for
1123 perms. The cache flag should be only used in cases that are used for
1065 display purposes, NOT IN ANY CASE for permission checks.
1124 display purposes, NOT IN ANY CASE for permission checks.
1066 """
1125 """
1067 from rhodecode.model.scm import RepoGroupList
1126 from rhodecode.model.scm import RepoGroupList
1068 if not perms:
1127 if not perms:
1069 perms = [
1128 perms = [
1070 'group.read', 'group.write', 'group.admin']
1129 'group.read', 'group.write', 'group.admin']
1071
1130
1072 def _cached_repo_group_acl(user_id, perm_def, name_filter):
1131 def _cached_repo_group_acl(user_id, perm_def, name_filter):
1073 qry = RepoGroup.query()
1132 qry = RepoGroup.query()
1074 if name_filter:
1133 if name_filter:
1075 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1134 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1076 qry = qry.filter(
1135 qry = qry.filter(
1077 RepoGroup.group_name.ilike(ilike_expression))
1136 RepoGroup.group_name.ilike(ilike_expression))
1078
1137
1079 return [x.group_id for x in
1138 return [x.group_id for x in
1080 RepoGroupList(qry, perm_set=perm_def)]
1139 RepoGroupList(qry, perm_set=perm_def)]
1081
1140
1082 compute = caches.conditional_cache(
1141 compute = caches.conditional_cache(
1083 'long_term', 'repo_group_acl_ids',
1142 'long_term', 'repo_group_acl_ids',
1084 condition=cache, func=_cached_repo_group_acl)
1143 condition=cache, func=_cached_repo_group_acl)
1085 return compute(self.user_id, perms, name_filter)
1144 return compute(self.user_id, perms, name_filter)
1086
1145
1087 def user_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1146 def user_group_acl_ids(self, perms=None, name_filter=None, cache=False):
1088 """
1147 """
1089 Returns list of user group ids that user have access to based on given
1148 Returns list of user group ids that user have access to based on given
1090 perms. The cache flag should be only used in cases that are used for
1149 perms. The cache flag should be only used in cases that are used for
1091 display purposes, NOT IN ANY CASE for permission checks.
1150 display purposes, NOT IN ANY CASE for permission checks.
1092 """
1151 """
1093 from rhodecode.model.scm import UserGroupList
1152 from rhodecode.model.scm import UserGroupList
1094 if not perms:
1153 if not perms:
1095 perms = [
1154 perms = [
1096 'usergroup.read', 'usergroup.write', 'usergroup.admin']
1155 'usergroup.read', 'usergroup.write', 'usergroup.admin']
1097
1156
1098 def _cached_user_group_acl(user_id, perm_def, name_filter):
1157 def _cached_user_group_acl(user_id, perm_def, name_filter):
1099 qry = UserGroup.query()
1158 qry = UserGroup.query()
1100 if name_filter:
1159 if name_filter:
1101 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1160 ilike_expression = u'%{}%'.format(safe_unicode(name_filter))
1102 qry = qry.filter(
1161 qry = qry.filter(
1103 UserGroup.users_group_name.ilike(ilike_expression))
1162 UserGroup.users_group_name.ilike(ilike_expression))
1104
1163
1105 return [x.users_group_id for x in
1164 return [x.users_group_id for x in
1106 UserGroupList(qry, perm_set=perm_def)]
1165 UserGroupList(qry, perm_set=perm_def)]
1107
1166
1108 compute = caches.conditional_cache(
1167 compute = caches.conditional_cache(
1109 'long_term', 'user_group_acl_ids',
1168 'long_term', 'user_group_acl_ids',
1110 condition=cache, func=_cached_user_group_acl)
1169 condition=cache, func=_cached_user_group_acl)
1111 return compute(self.user_id, perms, name_filter)
1170 return compute(self.user_id, perms, name_filter)
1112
1171
1113 @property
1172 @property
1114 def ip_allowed(self):
1173 def ip_allowed(self):
1115 """
1174 """
1116 Checks if ip_addr used in constructor is allowed from defined list of
1175 Checks if ip_addr used in constructor is allowed from defined list of
1117 allowed ip_addresses for user
1176 allowed ip_addresses for user
1118
1177
1119 :returns: boolean, True if ip is in allowed ip range
1178 :returns: boolean, True if ip is in allowed ip range
1120 """
1179 """
1121 # check IP
1180 # check IP
1122 inherit = self.inherit_default_permissions
1181 inherit = self.inherit_default_permissions
1123 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
1182 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
1124 inherit_from_default=inherit)
1183 inherit_from_default=inherit)
1125 @property
1184 @property
1126 def personal_repo_group(self):
1185 def personal_repo_group(self):
1127 return RepoGroup.get_user_personal_repo_group(self.user_id)
1186 return RepoGroup.get_user_personal_repo_group(self.user_id)
1128
1187
1129 @classmethod
1188 @classmethod
1130 def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default):
1189 def check_ip_allowed(cls, user_id, ip_addr, inherit_from_default):
1131 allowed_ips = AuthUser.get_allowed_ips(
1190 allowed_ips = AuthUser.get_allowed_ips(
1132 user_id, cache=True, inherit_from_default=inherit_from_default)
1191 user_id, cache=True, inherit_from_default=inherit_from_default)
1133 if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
1192 if check_ip_access(source_ip=ip_addr, allowed_ips=allowed_ips):
1134 log.debug('IP:%s is in range of %s' % (ip_addr, allowed_ips))
1193 log.debug('IP:%s is in range of %s' % (ip_addr, allowed_ips))
1135 return True
1194 return True
1136 else:
1195 else:
1137 log.info('Access for IP:%s forbidden, '
1196 log.info('Access for IP:%s forbidden, '
1138 'not in %s' % (ip_addr, allowed_ips))
1197 'not in %s' % (ip_addr, allowed_ips))
1139 return False
1198 return False
1140
1199
1141 def __repr__(self):
1200 def __repr__(self):
1142 return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
1201 return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
1143 % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
1202 % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
1144
1203
1145 def set_authenticated(self, authenticated=True):
1204 def set_authenticated(self, authenticated=True):
1146 if self.user_id != self.anonymous_user.user_id:
1205 if self.user_id != self.anonymous_user.user_id:
1147 self.is_authenticated = authenticated
1206 self.is_authenticated = authenticated
1148
1207
1149 def get_cookie_store(self):
1208 def get_cookie_store(self):
1150 return {
1209 return {
1151 'username': self.username,
1210 'username': self.username,
1152 'password': md5(self.password),
1211 'password': md5(self.password),
1153 'user_id': self.user_id,
1212 'user_id': self.user_id,
1154 'is_authenticated': self.is_authenticated
1213 'is_authenticated': self.is_authenticated
1155 }
1214 }
1156
1215
1157 @classmethod
1216 @classmethod
1158 def from_cookie_store(cls, cookie_store):
1217 def from_cookie_store(cls, cookie_store):
1159 """
1218 """
1160 Creates AuthUser from a cookie store
1219 Creates AuthUser from a cookie store
1161
1220
1162 :param cls:
1221 :param cls:
1163 :param cookie_store:
1222 :param cookie_store:
1164 """
1223 """
1165 user_id = cookie_store.get('user_id')
1224 user_id = cookie_store.get('user_id')
1166 username = cookie_store.get('username')
1225 username = cookie_store.get('username')
1167 api_key = cookie_store.get('api_key')
1226 api_key = cookie_store.get('api_key')
1168 return AuthUser(user_id, api_key, username)
1227 return AuthUser(user_id, api_key, username)
1169
1228
1170 @classmethod
1229 @classmethod
1171 def get_allowed_ips(cls, user_id, cache=False, inherit_from_default=False):
1230 def get_allowed_ips(cls, user_id, cache=False, inherit_from_default=False):
1172 _set = set()
1231 _set = set()
1173
1232
1174 if inherit_from_default:
1233 if inherit_from_default:
1175 default_ips = UserIpMap.query().filter(
1234 default_ips = UserIpMap.query().filter(
1176 UserIpMap.user == User.get_default_user(cache=True))
1235 UserIpMap.user == User.get_default_user(cache=True))
1177 if cache:
1236 if cache:
1178 default_ips = default_ips.options(
1237 default_ips = default_ips.options(
1179 FromCache("sql_cache_short", "get_user_ips_default"))
1238 FromCache("sql_cache_short", "get_user_ips_default"))
1180
1239
1181 # populate from default user
1240 # populate from default user
1182 for ip in default_ips:
1241 for ip in default_ips:
1183 try:
1242 try:
1184 _set.add(ip.ip_addr)
1243 _set.add(ip.ip_addr)
1185 except ObjectDeletedError:
1244 except ObjectDeletedError:
1186 # since we use heavy caching sometimes it happens that
1245 # since we use heavy caching sometimes it happens that
1187 # we get deleted objects here, we just skip them
1246 # we get deleted objects here, we just skip them
1188 pass
1247 pass
1189
1248
1190 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
1249 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
1191 if cache:
1250 if cache:
1192 user_ips = user_ips.options(
1251 user_ips = user_ips.options(
1193 FromCache("sql_cache_short", "get_user_ips_%s" % user_id))
1252 FromCache("sql_cache_short", "get_user_ips_%s" % user_id))
1194
1253
1195 for ip in user_ips:
1254 for ip in user_ips:
1196 try:
1255 try:
1197 _set.add(ip.ip_addr)
1256 _set.add(ip.ip_addr)
1198 except ObjectDeletedError:
1257 except ObjectDeletedError:
1199 # since we use heavy caching sometimes it happens that we get
1258 # since we use heavy caching sometimes it happens that we get
1200 # deleted objects here, we just skip them
1259 # deleted objects here, we just skip them
1201 pass
1260 pass
1202 return _set or set(['0.0.0.0/0', '::/0'])
1261 return _set or set(['0.0.0.0/0', '::/0'])
1203
1262
1204
1263
1205 def set_available_permissions(config):
1264 def set_available_permissions(config):
1206 """
1265 """
1207 This function will propagate pylons globals with all available defined
1266 This function will propagate pylons globals with all available defined
1208 permission given in db. We don't want to check each time from db for new
1267 permission given in db. We don't want to check each time from db for new
1209 permissions since adding a new permission also requires application restart
1268 permissions since adding a new permission also requires application restart
1210 ie. to decorate new views with the newly created permission
1269 ie. to decorate new views with the newly created permission
1211
1270
1212 :param config: current pylons config instance
1271 :param config: current pylons config instance
1213
1272
1214 """
1273 """
1215 log.info('getting information about all available permissions')
1274 log.info('getting information about all available permissions')
1216 try:
1275 try:
1217 sa = meta.Session
1276 sa = meta.Session
1218 all_perms = sa.query(Permission).all()
1277 all_perms = sa.query(Permission).all()
1219 config['available_permissions'] = [x.permission_name for x in all_perms]
1278 config['available_permissions'] = [x.permission_name for x in all_perms]
1220 except Exception:
1279 except Exception:
1221 log.error(traceback.format_exc())
1280 log.error(traceback.format_exc())
1222 finally:
1281 finally:
1223 meta.Session.remove()
1282 meta.Session.remove()
1224
1283
1225
1284
1226 def get_csrf_token(session=None, force_new=False, save_if_missing=True):
1285 def get_csrf_token(session=None, force_new=False, save_if_missing=True):
1227 """
1286 """
1228 Return the current authentication token, creating one if one doesn't
1287 Return the current authentication token, creating one if one doesn't
1229 already exist and the save_if_missing flag is present.
1288 already exist and the save_if_missing flag is present.
1230
1289
1231 :param session: pass in the pylons session, else we use the global ones
1290 :param session: pass in the pylons session, else we use the global ones
1232 :param force_new: force to re-generate the token and store it in session
1291 :param force_new: force to re-generate the token and store it in session
1233 :param save_if_missing: save the newly generated token if it's missing in
1292 :param save_if_missing: save the newly generated token if it's missing in
1234 session
1293 session
1235 """
1294 """
1236 # NOTE(marcink): probably should be replaced with below one from pyramid 1.9
1295 # NOTE(marcink): probably should be replaced with below one from pyramid 1.9
1237 # from pyramid.csrf import get_csrf_token
1296 # from pyramid.csrf import get_csrf_token
1238
1297
1239 if not session:
1298 if not session:
1240 from pylons import session
1299 from pylons import session
1241
1300
1242 if (csrf_token_key not in session and save_if_missing) or force_new:
1301 if (csrf_token_key not in session and save_if_missing) or force_new:
1243 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
1302 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
1244 session[csrf_token_key] = token
1303 session[csrf_token_key] = token
1245 if hasattr(session, 'save'):
1304 if hasattr(session, 'save'):
1246 session.save()
1305 session.save()
1247 return session.get(csrf_token_key)
1306 return session.get(csrf_token_key)
1248
1307
1249
1308
1250 def get_request(perm_class):
1309 def get_request(perm_class):
1251 from pyramid.threadlocal import get_current_request
1310 from pyramid.threadlocal import get_current_request
1252 pyramid_request = get_current_request()
1311 pyramid_request = get_current_request()
1253 if not pyramid_request:
1312 if not pyramid_request:
1254 # return global request of pylons in case pyramid isn't available
1313 # return global request of pylons in case pyramid isn't available
1255 # NOTE(marcink): this should be removed after migration to pyramid
1314 # NOTE(marcink): this should be removed after migration to pyramid
1256 from pylons import request
1315 from pylons import request
1257 return request
1316 return request
1258 return pyramid_request
1317 return pyramid_request
1259
1318
1260
1319
1261 # CHECK DECORATORS
1320 # CHECK DECORATORS
1262 class CSRFRequired(object):
1321 class CSRFRequired(object):
1263 """
1322 """
1264 Decorator for authenticating a form
1323 Decorator for authenticating a form
1265
1324
1266 This decorator uses an authorization token stored in the client's
1325 This decorator uses an authorization token stored in the client's
1267 session for prevention of certain Cross-site request forgery (CSRF)
1326 session for prevention of certain Cross-site request forgery (CSRF)
1268 attacks (See
1327 attacks (See
1269 http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
1328 http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
1270 information).
1329 information).
1271
1330
1272 For use with the ``webhelpers.secure_form`` helper functions.
1331 For use with the ``webhelpers.secure_form`` helper functions.
1273
1332
1274 """
1333 """
1275 def __init__(self, token=csrf_token_key, header='X-CSRF-Token',
1334 def __init__(self, token=csrf_token_key, header='X-CSRF-Token',
1276 except_methods=None):
1335 except_methods=None):
1277 self.token = token
1336 self.token = token
1278 self.header = header
1337 self.header = header
1279 self.except_methods = except_methods or []
1338 self.except_methods = except_methods or []
1280
1339
1281 def __call__(self, func):
1340 def __call__(self, func):
1282 return get_cython_compat_decorator(self.__wrapper, func)
1341 return get_cython_compat_decorator(self.__wrapper, func)
1283
1342
1284 def _get_csrf(self, _request):
1343 def _get_csrf(self, _request):
1285 return _request.POST.get(self.token, _request.headers.get(self.header))
1344 return _request.POST.get(self.token, _request.headers.get(self.header))
1286
1345
1287 def check_csrf(self, _request, cur_token):
1346 def check_csrf(self, _request, cur_token):
1288 supplied_token = self._get_csrf(_request)
1347 supplied_token = self._get_csrf(_request)
1289 return supplied_token and supplied_token == cur_token
1348 return supplied_token and supplied_token == cur_token
1290
1349
1291 def _get_request(self):
1350 def _get_request(self):
1292 return get_request(self)
1351 return get_request(self)
1293
1352
1294 def __wrapper(self, func, *fargs, **fkwargs):
1353 def __wrapper(self, func, *fargs, **fkwargs):
1295 request = self._get_request()
1354 request = self._get_request()
1296
1355
1297 if request.method in self.except_methods:
1356 if request.method in self.except_methods:
1298 return func(*fargs, **fkwargs)
1357 return func(*fargs, **fkwargs)
1299
1358
1300 cur_token = get_csrf_token(save_if_missing=False)
1359 cur_token = get_csrf_token(save_if_missing=False)
1301 if self.check_csrf(request, cur_token):
1360 if self.check_csrf(request, cur_token):
1302 if request.POST.get(self.token):
1361 if request.POST.get(self.token):
1303 del request.POST[self.token]
1362 del request.POST[self.token]
1304 return func(*fargs, **fkwargs)
1363 return func(*fargs, **fkwargs)
1305 else:
1364 else:
1306 reason = 'token-missing'
1365 reason = 'token-missing'
1307 supplied_token = self._get_csrf(request)
1366 supplied_token = self._get_csrf(request)
1308 if supplied_token and cur_token != supplied_token:
1367 if supplied_token and cur_token != supplied_token:
1309 reason = 'token-mismatch [%s:%s]' % (
1368 reason = 'token-mismatch [%s:%s]' % (
1310 cur_token or ''[:6], supplied_token or ''[:6])
1369 cur_token or ''[:6], supplied_token or ''[:6])
1311
1370
1312 csrf_message = \
1371 csrf_message = \
1313 ("Cross-site request forgery detected, request denied. See "
1372 ("Cross-site request forgery detected, request denied. See "
1314 "http://en.wikipedia.org/wiki/Cross-site_request_forgery for "
1373 "http://en.wikipedia.org/wiki/Cross-site_request_forgery for "
1315 "more information.")
1374 "more information.")
1316 log.warn('Cross-site request forgery detected, request %r DENIED: %s '
1375 log.warn('Cross-site request forgery detected, request %r DENIED: %s '
1317 'REMOTE_ADDR:%s, HEADERS:%s' % (
1376 'REMOTE_ADDR:%s, HEADERS:%s' % (
1318 request, reason, request.remote_addr, request.headers))
1377 request, reason, request.remote_addr, request.headers))
1319
1378
1320 raise HTTPForbidden(explanation=csrf_message)
1379 raise HTTPForbidden(explanation=csrf_message)
1321
1380
1322
1381
1323 class LoginRequired(object):
1382 class LoginRequired(object):
1324 """
1383 """
1325 Must be logged in to execute this function else
1384 Must be logged in to execute this function else
1326 redirect to login page
1385 redirect to login page
1327
1386
1328 :param api_access: if enabled this checks only for valid auth token
1387 :param api_access: if enabled this checks only for valid auth token
1329 and grants access based on valid token
1388 and grants access based on valid token
1330 """
1389 """
1331 def __init__(self, auth_token_access=None):
1390 def __init__(self, auth_token_access=None):
1332 self.auth_token_access = auth_token_access
1391 self.auth_token_access = auth_token_access
1333
1392
1334 def __call__(self, func):
1393 def __call__(self, func):
1335 return get_cython_compat_decorator(self.__wrapper, func)
1394 return get_cython_compat_decorator(self.__wrapper, func)
1336
1395
1337 def _get_request(self):
1396 def _get_request(self):
1338 return get_request(self)
1397 return get_request(self)
1339
1398
1340 def __wrapper(self, func, *fargs, **fkwargs):
1399 def __wrapper(self, func, *fargs, **fkwargs):
1341 from rhodecode.lib import helpers as h
1400 from rhodecode.lib import helpers as h
1342 cls = fargs[0]
1401 cls = fargs[0]
1343 user = cls._rhodecode_user
1402 user = cls._rhodecode_user
1344 request = self._get_request()
1403 request = self._get_request()
1345
1404
1346 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
1405 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
1347 log.debug('Starting login restriction checks for user: %s' % (user,))
1406 log.debug('Starting login restriction checks for user: %s' % (user,))
1348 # check if our IP is allowed
1407 # check if our IP is allowed
1349 ip_access_valid = True
1408 ip_access_valid = True
1350 if not user.ip_allowed:
1409 if not user.ip_allowed:
1351 h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr,))),
1410 h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr,))),
1352 category='warning')
1411 category='warning')
1353 ip_access_valid = False
1412 ip_access_valid = False
1354
1413
1355 # check if we used an APIKEY and it's a valid one
1414 # check if we used an APIKEY and it's a valid one
1356 # defined white-list of controllers which API access will be enabled
1415 # defined white-list of controllers which API access will be enabled
1357 _auth_token = request.GET.get(
1416 _auth_token = request.GET.get(
1358 'auth_token', '') or request.GET.get('api_key', '')
1417 'auth_token', '') or request.GET.get('api_key', '')
1359 auth_token_access_valid = allowed_auth_token_access(
1418 auth_token_access_valid = allowed_auth_token_access(
1360 loc, auth_token=_auth_token)
1419 loc, auth_token=_auth_token)
1361
1420
1362 # explicit controller is enabled or API is in our whitelist
1421 # explicit controller is enabled or API is in our whitelist
1363 if self.auth_token_access or auth_token_access_valid:
1422 if self.auth_token_access or auth_token_access_valid:
1364 log.debug('Checking AUTH TOKEN access for %s' % (cls,))
1423 log.debug('Checking AUTH TOKEN access for %s' % (cls,))
1365 db_user = user.get_instance()
1424 db_user = user.get_instance()
1366
1425
1367 if db_user:
1426 if db_user:
1368 if self.auth_token_access:
1427 if self.auth_token_access:
1369 roles = self.auth_token_access
1428 roles = self.auth_token_access
1370 else:
1429 else:
1371 roles = [UserApiKeys.ROLE_HTTP]
1430 roles = [UserApiKeys.ROLE_HTTP]
1372 token_match = db_user.authenticate_by_token(
1431 token_match = db_user.authenticate_by_token(
1373 _auth_token, roles=roles)
1432 _auth_token, roles=roles)
1374 else:
1433 else:
1375 log.debug('Unable to fetch db instance for auth user: %s', user)
1434 log.debug('Unable to fetch db instance for auth user: %s', user)
1376 token_match = False
1435 token_match = False
1377
1436
1378 if _auth_token and token_match:
1437 if _auth_token and token_match:
1379 auth_token_access_valid = True
1438 auth_token_access_valid = True
1380 log.debug('AUTH TOKEN ****%s is VALID' % (_auth_token[-4:],))
1439 log.debug('AUTH TOKEN ****%s is VALID' % (_auth_token[-4:],))
1381 else:
1440 else:
1382 auth_token_access_valid = False
1441 auth_token_access_valid = False
1383 if not _auth_token:
1442 if not _auth_token:
1384 log.debug("AUTH TOKEN *NOT* present in request")
1443 log.debug("AUTH TOKEN *NOT* present in request")
1385 else:
1444 else:
1386 log.warning(
1445 log.warning(
1387 "AUTH TOKEN ****%s *NOT* valid" % _auth_token[-4:])
1446 "AUTH TOKEN ****%s *NOT* valid" % _auth_token[-4:])
1388
1447
1389 log.debug('Checking if %s is authenticated @ %s' % (user.username, loc))
1448 log.debug('Checking if %s is authenticated @ %s' % (user.username, loc))
1390 reason = 'RHODECODE_AUTH' if user.is_authenticated \
1449 reason = 'RHODECODE_AUTH' if user.is_authenticated \
1391 else 'AUTH_TOKEN_AUTH'
1450 else 'AUTH_TOKEN_AUTH'
1392
1451
1393 if ip_access_valid and (
1452 if ip_access_valid and (
1394 user.is_authenticated or auth_token_access_valid):
1453 user.is_authenticated or auth_token_access_valid):
1395 log.info(
1454 log.info(
1396 'user %s authenticating with:%s IS authenticated on func %s'
1455 'user %s authenticating with:%s IS authenticated on func %s'
1397 % (user, reason, loc))
1456 % (user, reason, loc))
1398
1457
1399 # update user data to check last activity
1458 # update user data to check last activity
1400 user.update_lastactivity()
1459 user.update_lastactivity()
1401 Session().commit()
1460 Session().commit()
1402 return func(*fargs, **fkwargs)
1461 return func(*fargs, **fkwargs)
1403 else:
1462 else:
1404 log.warning(
1463 log.warning(
1405 'user %s authenticating with:%s NOT authenticated on '
1464 'user %s authenticating with:%s NOT authenticated on '
1406 'func: %s: IP_ACCESS:%s AUTH_TOKEN_ACCESS:%s'
1465 'func: %s: IP_ACCESS:%s AUTH_TOKEN_ACCESS:%s'
1407 % (user, reason, loc, ip_access_valid,
1466 % (user, reason, loc, ip_access_valid,
1408 auth_token_access_valid))
1467 auth_token_access_valid))
1409 # we preserve the get PARAM
1468 # we preserve the get PARAM
1410 came_from = request.path_qs
1469 came_from = request.path_qs
1411 log.debug('redirecting to login page with %s' % (came_from,))
1470 log.debug('redirecting to login page with %s' % (came_from,))
1412 raise HTTPFound(
1471 raise HTTPFound(
1413 h.route_path('login', _query={'came_from': came_from}))
1472 h.route_path('login', _query={'came_from': came_from}))
1414
1473
1415
1474
1416 class NotAnonymous(object):
1475 class NotAnonymous(object):
1417 """
1476 """
1418 Must be logged in to execute this function else
1477 Must be logged in to execute this function else
1419 redirect to login page
1478 redirect to login page
1420 """
1479 """
1421
1480
1422 def __call__(self, func):
1481 def __call__(self, func):
1423 return get_cython_compat_decorator(self.__wrapper, func)
1482 return get_cython_compat_decorator(self.__wrapper, func)
1424
1483
1425 def _get_request(self):
1484 def _get_request(self):
1426 return get_request(self)
1485 return get_request(self)
1427
1486
1428 def __wrapper(self, func, *fargs, **fkwargs):
1487 def __wrapper(self, func, *fargs, **fkwargs):
1429 import rhodecode.lib.helpers as h
1488 import rhodecode.lib.helpers as h
1430 cls = fargs[0]
1489 cls = fargs[0]
1431 self.user = cls._rhodecode_user
1490 self.user = cls._rhodecode_user
1432 request = self._get_request()
1491 request = self._get_request()
1433
1492
1434 log.debug('Checking if user is not anonymous @%s' % cls)
1493 log.debug('Checking if user is not anonymous @%s' % cls)
1435
1494
1436 anonymous = self.user.username == User.DEFAULT_USER
1495 anonymous = self.user.username == User.DEFAULT_USER
1437
1496
1438 if anonymous:
1497 if anonymous:
1439 came_from = request.path_qs
1498 came_from = request.path_qs
1440 h.flash(_('You need to be a registered user to '
1499 h.flash(_('You need to be a registered user to '
1441 'perform this action'),
1500 'perform this action'),
1442 category='warning')
1501 category='warning')
1443 raise HTTPFound(
1502 raise HTTPFound(
1444 h.route_path('login', _query={'came_from': came_from}))
1503 h.route_path('login', _query={'came_from': came_from}))
1445 else:
1504 else:
1446 return func(*fargs, **fkwargs)
1505 return func(*fargs, **fkwargs)
1447
1506
1448
1507
1449 class PermsDecorator(object):
1508 class PermsDecorator(object):
1450 """
1509 """
1451 Base class for controller decorators, we extract the current user from
1510 Base class for controller decorators, we extract the current user from
1452 the class itself, which has it stored in base controllers
1511 the class itself, which has it stored in base controllers
1453 """
1512 """
1454
1513
1455 def __init__(self, *required_perms):
1514 def __init__(self, *required_perms):
1456 self.required_perms = set(required_perms)
1515 self.required_perms = set(required_perms)
1457
1516
1458 def __call__(self, func):
1517 def __call__(self, func):
1459 return get_cython_compat_decorator(self.__wrapper, func)
1518 return get_cython_compat_decorator(self.__wrapper, func)
1460
1519
1461 def _get_request(self):
1520 def _get_request(self):
1462 return get_request(self)
1521 return get_request(self)
1463
1522
1464 def _get_came_from(self):
1523 def _get_came_from(self):
1465 _request = self._get_request()
1524 _request = self._get_request()
1466
1525
1467 # both pylons/pyramid has this attribute
1526 # both pylons/pyramid has this attribute
1468 return _request.path_qs
1527 return _request.path_qs
1469
1528
1470 def __wrapper(self, func, *fargs, **fkwargs):
1529 def __wrapper(self, func, *fargs, **fkwargs):
1471 import rhodecode.lib.helpers as h
1530 import rhodecode.lib.helpers as h
1472 cls = fargs[0]
1531 cls = fargs[0]
1473 _user = cls._rhodecode_user
1532 _user = cls._rhodecode_user
1474
1533
1475 log.debug('checking %s permissions %s for %s %s',
1534 log.debug('checking %s permissions %s for %s %s',
1476 self.__class__.__name__, self.required_perms, cls, _user)
1535 self.__class__.__name__, self.required_perms, cls, _user)
1477
1536
1478 if self.check_permissions(_user):
1537 if self.check_permissions(_user):
1479 log.debug('Permission granted for %s %s', cls, _user)
1538 log.debug('Permission granted for %s %s', cls, _user)
1480 return func(*fargs, **fkwargs)
1539 return func(*fargs, **fkwargs)
1481
1540
1482 else:
1541 else:
1483 log.debug('Permission denied for %s %s', cls, _user)
1542 log.debug('Permission denied for %s %s', cls, _user)
1484 anonymous = _user.username == User.DEFAULT_USER
1543 anonymous = _user.username == User.DEFAULT_USER
1485
1544
1486 if anonymous:
1545 if anonymous:
1487 came_from = self._get_came_from()
1546 came_from = self._get_came_from()
1488 h.flash(_('You need to be signed in to view this page'),
1547 h.flash(_('You need to be signed in to view this page'),
1489 category='warning')
1548 category='warning')
1490 raise HTTPFound(
1549 raise HTTPFound(
1491 h.route_path('login', _query={'came_from': came_from}))
1550 h.route_path('login', _query={'came_from': came_from}))
1492
1551
1493 else:
1552 else:
1494 # redirect with 404 to prevent resource discovery
1553 # redirect with 404 to prevent resource discovery
1495 raise HTTPNotFound()
1554 raise HTTPNotFound()
1496
1555
1497 def check_permissions(self, user):
1556 def check_permissions(self, user):
1498 """Dummy function for overriding"""
1557 """Dummy function for overriding"""
1499 raise NotImplementedError(
1558 raise NotImplementedError(
1500 'You have to write this function in child class')
1559 'You have to write this function in child class')
1501
1560
1502
1561
1503 class HasPermissionAllDecorator(PermsDecorator):
1562 class HasPermissionAllDecorator(PermsDecorator):
1504 """
1563 """
1505 Checks for access permission for all given predicates. All of them
1564 Checks for access permission for all given predicates. All of them
1506 have to be meet in order to fulfill the request
1565 have to be meet in order to fulfill the request
1507 """
1566 """
1508
1567
1509 def check_permissions(self, user):
1568 def check_permissions(self, user):
1510 perms = user.permissions_with_scope({})
1569 perms = user.permissions_with_scope({})
1511 if self.required_perms.issubset(perms['global']):
1570 if self.required_perms.issubset(perms['global']):
1512 return True
1571 return True
1513 return False
1572 return False
1514
1573
1515
1574
1516 class HasPermissionAnyDecorator(PermsDecorator):
1575 class HasPermissionAnyDecorator(PermsDecorator):
1517 """
1576 """
1518 Checks for access permission for any of given predicates. In order to
1577 Checks for access permission for any of given predicates. In order to
1519 fulfill the request any of predicates must be meet
1578 fulfill the request any of predicates must be meet
1520 """
1579 """
1521
1580
1522 def check_permissions(self, user):
1581 def check_permissions(self, user):
1523 perms = user.permissions_with_scope({})
1582 perms = user.permissions_with_scope({})
1524 if self.required_perms.intersection(perms['global']):
1583 if self.required_perms.intersection(perms['global']):
1525 return True
1584 return True
1526 return False
1585 return False
1527
1586
1528
1587
1529 class HasRepoPermissionAllDecorator(PermsDecorator):
1588 class HasRepoPermissionAllDecorator(PermsDecorator):
1530 """
1589 """
1531 Checks for access permission for all given predicates for specific
1590 Checks for access permission for all given predicates for specific
1532 repository. All of them have to be meet in order to fulfill the request
1591 repository. All of them have to be meet in order to fulfill the request
1533 """
1592 """
1534 def _get_repo_name(self):
1593 def _get_repo_name(self):
1535 _request = self._get_request()
1594 _request = self._get_request()
1536 return get_repo_slug(_request)
1595 return get_repo_slug(_request)
1537
1596
1538 def check_permissions(self, user):
1597 def check_permissions(self, user):
1539 perms = user.permissions
1598 perms = user.permissions
1540 repo_name = self._get_repo_name()
1599 repo_name = self._get_repo_name()
1541
1600
1542 try:
1601 try:
1543 user_perms = set([perms['repositories'][repo_name]])
1602 user_perms = set([perms['repositories'][repo_name]])
1544 except KeyError:
1603 except KeyError:
1545 log.debug('cannot locate repo with name: `%s` in permissions defs',
1604 log.debug('cannot locate repo with name: `%s` in permissions defs',
1546 repo_name)
1605 repo_name)
1547 return False
1606 return False
1548
1607
1549 log.debug('checking `%s` permissions for repo `%s`',
1608 log.debug('checking `%s` permissions for repo `%s`',
1550 user_perms, repo_name)
1609 user_perms, repo_name)
1551 if self.required_perms.issubset(user_perms):
1610 if self.required_perms.issubset(user_perms):
1552 return True
1611 return True
1553 return False
1612 return False
1554
1613
1555
1614
1556 class HasRepoPermissionAnyDecorator(PermsDecorator):
1615 class HasRepoPermissionAnyDecorator(PermsDecorator):
1557 """
1616 """
1558 Checks for access permission for any of given predicates for specific
1617 Checks for access permission for any of given predicates for specific
1559 repository. In order to fulfill the request any of predicates must be meet
1618 repository. In order to fulfill the request any of predicates must be meet
1560 """
1619 """
1561 def _get_repo_name(self):
1620 def _get_repo_name(self):
1562 _request = self._get_request()
1621 _request = self._get_request()
1563 return get_repo_slug(_request)
1622 return get_repo_slug(_request)
1564
1623
1565 def check_permissions(self, user):
1624 def check_permissions(self, user):
1566 perms = user.permissions
1625 perms = user.permissions
1567 repo_name = self._get_repo_name()
1626 repo_name = self._get_repo_name()
1568
1627
1569 try:
1628 try:
1570 user_perms = set([perms['repositories'][repo_name]])
1629 user_perms = set([perms['repositories'][repo_name]])
1571 except KeyError:
1630 except KeyError:
1572 log.debug(
1631 log.debug(
1573 'cannot locate repo with name: `%s` in permissions defs',
1632 'cannot locate repo with name: `%s` in permissions defs',
1574 repo_name)
1633 repo_name)
1575 return False
1634 return False
1576
1635
1577 log.debug('checking `%s` permissions for repo `%s`',
1636 log.debug('checking `%s` permissions for repo `%s`',
1578 user_perms, repo_name)
1637 user_perms, repo_name)
1579 if self.required_perms.intersection(user_perms):
1638 if self.required_perms.intersection(user_perms):
1580 return True
1639 return True
1581 return False
1640 return False
1582
1641
1583
1642
1584 class HasRepoGroupPermissionAllDecorator(PermsDecorator):
1643 class HasRepoGroupPermissionAllDecorator(PermsDecorator):
1585 """
1644 """
1586 Checks for access permission for all given predicates for specific
1645 Checks for access permission for all given predicates for specific
1587 repository group. All of them have to be meet in order to
1646 repository group. All of them have to be meet in order to
1588 fulfill the request
1647 fulfill the request
1589 """
1648 """
1590 def _get_repo_group_name(self):
1649 def _get_repo_group_name(self):
1591 _request = self._get_request()
1650 _request = self._get_request()
1592 return get_repo_group_slug(_request)
1651 return get_repo_group_slug(_request)
1593
1652
1594 def check_permissions(self, user):
1653 def check_permissions(self, user):
1595 perms = user.permissions
1654 perms = user.permissions
1596 group_name = self._get_repo_group_name()
1655 group_name = self._get_repo_group_name()
1597 try:
1656 try:
1598 user_perms = set([perms['repositories_groups'][group_name]])
1657 user_perms = set([perms['repositories_groups'][group_name]])
1599 except KeyError:
1658 except KeyError:
1600 log.debug(
1659 log.debug(
1601 'cannot locate repo group with name: `%s` in permissions defs',
1660 'cannot locate repo group with name: `%s` in permissions defs',
1602 group_name)
1661 group_name)
1603 return False
1662 return False
1604
1663
1605 log.debug('checking `%s` permissions for repo group `%s`',
1664 log.debug('checking `%s` permissions for repo group `%s`',
1606 user_perms, group_name)
1665 user_perms, group_name)
1607 if self.required_perms.issubset(user_perms):
1666 if self.required_perms.issubset(user_perms):
1608 return True
1667 return True
1609 return False
1668 return False
1610
1669
1611
1670
1612 class HasRepoGroupPermissionAnyDecorator(PermsDecorator):
1671 class HasRepoGroupPermissionAnyDecorator(PermsDecorator):
1613 """
1672 """
1614 Checks for access permission for any of given predicates for specific
1673 Checks for access permission for any of given predicates for specific
1615 repository group. In order to fulfill the request any
1674 repository group. In order to fulfill the request any
1616 of predicates must be met
1675 of predicates must be met
1617 """
1676 """
1618 def _get_repo_group_name(self):
1677 def _get_repo_group_name(self):
1619 _request = self._get_request()
1678 _request = self._get_request()
1620 return get_repo_group_slug(_request)
1679 return get_repo_group_slug(_request)
1621
1680
1622 def check_permissions(self, user):
1681 def check_permissions(self, user):
1623 perms = user.permissions
1682 perms = user.permissions
1624 group_name = self._get_repo_group_name()
1683 group_name = self._get_repo_group_name()
1625
1684
1626 try:
1685 try:
1627 user_perms = set([perms['repositories_groups'][group_name]])
1686 user_perms = set([perms['repositories_groups'][group_name]])
1628 except KeyError:
1687 except KeyError:
1629 log.debug(
1688 log.debug(
1630 'cannot locate repo group with name: `%s` in permissions defs',
1689 'cannot locate repo group with name: `%s` in permissions defs',
1631 group_name)
1690 group_name)
1632 return False
1691 return False
1633
1692
1634 log.debug('checking `%s` permissions for repo group `%s`',
1693 log.debug('checking `%s` permissions for repo group `%s`',
1635 user_perms, group_name)
1694 user_perms, group_name)
1636 if self.required_perms.intersection(user_perms):
1695 if self.required_perms.intersection(user_perms):
1637 return True
1696 return True
1638 return False
1697 return False
1639
1698
1640
1699
1641 class HasUserGroupPermissionAllDecorator(PermsDecorator):
1700 class HasUserGroupPermissionAllDecorator(PermsDecorator):
1642 """
1701 """
1643 Checks for access permission for all given predicates for specific
1702 Checks for access permission for all given predicates for specific
1644 user group. All of them have to be meet in order to fulfill the request
1703 user group. All of them have to be meet in order to fulfill the request
1645 """
1704 """
1646 def _get_user_group_name(self):
1705 def _get_user_group_name(self):
1647 _request = self._get_request()
1706 _request = self._get_request()
1648 return get_user_group_slug(_request)
1707 return get_user_group_slug(_request)
1649
1708
1650 def check_permissions(self, user):
1709 def check_permissions(self, user):
1651 perms = user.permissions
1710 perms = user.permissions
1652 group_name = self._get_user_group_name()
1711 group_name = self._get_user_group_name()
1653 try:
1712 try:
1654 user_perms = set([perms['user_groups'][group_name]])
1713 user_perms = set([perms['user_groups'][group_name]])
1655 except KeyError:
1714 except KeyError:
1656 return False
1715 return False
1657
1716
1658 if self.required_perms.issubset(user_perms):
1717 if self.required_perms.issubset(user_perms):
1659 return True
1718 return True
1660 return False
1719 return False
1661
1720
1662
1721
1663 class HasUserGroupPermissionAnyDecorator(PermsDecorator):
1722 class HasUserGroupPermissionAnyDecorator(PermsDecorator):
1664 """
1723 """
1665 Checks for access permission for any of given predicates for specific
1724 Checks for access permission for any of given predicates for specific
1666 user group. In order to fulfill the request any of predicates must be meet
1725 user group. In order to fulfill the request any of predicates must be meet
1667 """
1726 """
1668 def _get_user_group_name(self):
1727 def _get_user_group_name(self):
1669 _request = self._get_request()
1728 _request = self._get_request()
1670 return get_user_group_slug(_request)
1729 return get_user_group_slug(_request)
1671
1730
1672 def check_permissions(self, user):
1731 def check_permissions(self, user):
1673 perms = user.permissions
1732 perms = user.permissions
1674 group_name = self._get_user_group_name()
1733 group_name = self._get_user_group_name()
1675 try:
1734 try:
1676 user_perms = set([perms['user_groups'][group_name]])
1735 user_perms = set([perms['user_groups'][group_name]])
1677 except KeyError:
1736 except KeyError:
1678 return False
1737 return False
1679
1738
1680 if self.required_perms.intersection(user_perms):
1739 if self.required_perms.intersection(user_perms):
1681 return True
1740 return True
1682 return False
1741 return False
1683
1742
1684
1743
1685 # CHECK FUNCTIONS
1744 # CHECK FUNCTIONS
1686 class PermsFunction(object):
1745 class PermsFunction(object):
1687 """Base function for other check functions"""
1746 """Base function for other check functions"""
1688
1747
1689 def __init__(self, *perms):
1748 def __init__(self, *perms):
1690 self.required_perms = set(perms)
1749 self.required_perms = set(perms)
1691 self.repo_name = None
1750 self.repo_name = None
1692 self.repo_group_name = None
1751 self.repo_group_name = None
1693 self.user_group_name = None
1752 self.user_group_name = None
1694
1753
1695 def __bool__(self):
1754 def __bool__(self):
1696 frame = inspect.currentframe()
1755 frame = inspect.currentframe()
1697 stack_trace = traceback.format_stack(frame)
1756 stack_trace = traceback.format_stack(frame)
1698 log.error('Checking bool value on a class instance of perm '
1757 log.error('Checking bool value on a class instance of perm '
1699 'function is not allowed: %s' % ''.join(stack_trace))
1758 'function is not allowed: %s' % ''.join(stack_trace))
1700 # rather than throwing errors, here we always return False so if by
1759 # rather than throwing errors, here we always return False so if by
1701 # accident someone checks truth for just an instance it will always end
1760 # accident someone checks truth for just an instance it will always end
1702 # up in returning False
1761 # up in returning False
1703 return False
1762 return False
1704 __nonzero__ = __bool__
1763 __nonzero__ = __bool__
1705
1764
1706 def __call__(self, check_location='', user=None):
1765 def __call__(self, check_location='', user=None):
1707 if not user:
1766 if not user:
1708 log.debug('Using user attribute from global request')
1767 log.debug('Using user attribute from global request')
1709 # TODO: remove this someday,put as user as attribute here
1768 # TODO: remove this someday,put as user as attribute here
1710 request = self._get_request()
1769 request = self._get_request()
1711 user = request.user
1770 user = request.user
1712
1771
1713 # init auth user if not already given
1772 # init auth user if not already given
1714 if not isinstance(user, AuthUser):
1773 if not isinstance(user, AuthUser):
1715 log.debug('Wrapping user %s into AuthUser', user)
1774 log.debug('Wrapping user %s into AuthUser', user)
1716 user = AuthUser(user.user_id)
1775 user = AuthUser(user.user_id)
1717
1776
1718 cls_name = self.__class__.__name__
1777 cls_name = self.__class__.__name__
1719 check_scope = self._get_check_scope(cls_name)
1778 check_scope = self._get_check_scope(cls_name)
1720 check_location = check_location or 'unspecified location'
1779 check_location = check_location or 'unspecified location'
1721
1780
1722 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
1781 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
1723 self.required_perms, user, check_scope, check_location)
1782 self.required_perms, user, check_scope, check_location)
1724 if not user:
1783 if not user:
1725 log.warning('Empty user given for permission check')
1784 log.warning('Empty user given for permission check')
1726 return False
1785 return False
1727
1786
1728 if self.check_permissions(user):
1787 if self.check_permissions(user):
1729 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1788 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1730 check_scope, user, check_location)
1789 check_scope, user, check_location)
1731 return True
1790 return True
1732
1791
1733 else:
1792 else:
1734 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1793 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1735 check_scope, user, check_location)
1794 check_scope, user, check_location)
1736 return False
1795 return False
1737
1796
1738 def _get_request(self):
1797 def _get_request(self):
1739 return get_request(self)
1798 return get_request(self)
1740
1799
1741 def _get_check_scope(self, cls_name):
1800 def _get_check_scope(self, cls_name):
1742 return {
1801 return {
1743 'HasPermissionAll': 'GLOBAL',
1802 'HasPermissionAll': 'GLOBAL',
1744 'HasPermissionAny': 'GLOBAL',
1803 'HasPermissionAny': 'GLOBAL',
1745 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
1804 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
1746 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
1805 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
1747 'HasRepoGroupPermissionAll': 'repo_group:%s' % self.repo_group_name,
1806 'HasRepoGroupPermissionAll': 'repo_group:%s' % self.repo_group_name,
1748 'HasRepoGroupPermissionAny': 'repo_group:%s' % self.repo_group_name,
1807 'HasRepoGroupPermissionAny': 'repo_group:%s' % self.repo_group_name,
1749 'HasUserGroupPermissionAll': 'user_group:%s' % self.user_group_name,
1808 'HasUserGroupPermissionAll': 'user_group:%s' % self.user_group_name,
1750 'HasUserGroupPermissionAny': 'user_group:%s' % self.user_group_name,
1809 'HasUserGroupPermissionAny': 'user_group:%s' % self.user_group_name,
1751 }.get(cls_name, '?:%s' % cls_name)
1810 }.get(cls_name, '?:%s' % cls_name)
1752
1811
1753 def check_permissions(self, user):
1812 def check_permissions(self, user):
1754 """Dummy function for overriding"""
1813 """Dummy function for overriding"""
1755 raise Exception('You have to write this function in child class')
1814 raise Exception('You have to write this function in child class')
1756
1815
1757
1816
1758 class HasPermissionAll(PermsFunction):
1817 class HasPermissionAll(PermsFunction):
1759 def check_permissions(self, user):
1818 def check_permissions(self, user):
1760 perms = user.permissions_with_scope({})
1819 perms = user.permissions_with_scope({})
1761 if self.required_perms.issubset(perms.get('global')):
1820 if self.required_perms.issubset(perms.get('global')):
1762 return True
1821 return True
1763 return False
1822 return False
1764
1823
1765
1824
1766 class HasPermissionAny(PermsFunction):
1825 class HasPermissionAny(PermsFunction):
1767 def check_permissions(self, user):
1826 def check_permissions(self, user):
1768 perms = user.permissions_with_scope({})
1827 perms = user.permissions_with_scope({})
1769 if self.required_perms.intersection(perms.get('global')):
1828 if self.required_perms.intersection(perms.get('global')):
1770 return True
1829 return True
1771 return False
1830 return False
1772
1831
1773
1832
1774 class HasRepoPermissionAll(PermsFunction):
1833 class HasRepoPermissionAll(PermsFunction):
1775 def __call__(self, repo_name=None, check_location='', user=None):
1834 def __call__(self, repo_name=None, check_location='', user=None):
1776 self.repo_name = repo_name
1835 self.repo_name = repo_name
1777 return super(HasRepoPermissionAll, self).__call__(check_location, user)
1836 return super(HasRepoPermissionAll, self).__call__(check_location, user)
1778
1837
1779 def _get_repo_name(self):
1838 def _get_repo_name(self):
1780 if not self.repo_name:
1839 if not self.repo_name:
1781 _request = self._get_request()
1840 _request = self._get_request()
1782 self.repo_name = get_repo_slug(_request)
1841 self.repo_name = get_repo_slug(_request)
1783 return self.repo_name
1842 return self.repo_name
1784
1843
1785 def check_permissions(self, user):
1844 def check_permissions(self, user):
1786 self.repo_name = self._get_repo_name()
1845 self.repo_name = self._get_repo_name()
1787 perms = user.permissions
1846 perms = user.permissions
1788 try:
1847 try:
1789 user_perms = set([perms['repositories'][self.repo_name]])
1848 user_perms = set([perms['repositories'][self.repo_name]])
1790 except KeyError:
1849 except KeyError:
1791 return False
1850 return False
1792 if self.required_perms.issubset(user_perms):
1851 if self.required_perms.issubset(user_perms):
1793 return True
1852 return True
1794 return False
1853 return False
1795
1854
1796
1855
1797 class HasRepoPermissionAny(PermsFunction):
1856 class HasRepoPermissionAny(PermsFunction):
1798 def __call__(self, repo_name=None, check_location='', user=None):
1857 def __call__(self, repo_name=None, check_location='', user=None):
1799 self.repo_name = repo_name
1858 self.repo_name = repo_name
1800 return super(HasRepoPermissionAny, self).__call__(check_location, user)
1859 return super(HasRepoPermissionAny, self).__call__(check_location, user)
1801
1860
1802 def _get_repo_name(self):
1861 def _get_repo_name(self):
1803 if not self.repo_name:
1862 if not self.repo_name:
1804 _request = self._get_request()
1863 _request = self._get_request()
1805 self.repo_name = get_repo_slug(_request)
1864 self.repo_name = get_repo_slug(_request)
1806 return self.repo_name
1865 return self.repo_name
1807
1866
1808 def check_permissions(self, user):
1867 def check_permissions(self, user):
1809 self.repo_name = self._get_repo_name()
1868 self.repo_name = self._get_repo_name()
1810 perms = user.permissions
1869 perms = user.permissions
1811 try:
1870 try:
1812 user_perms = set([perms['repositories'][self.repo_name]])
1871 user_perms = set([perms['repositories'][self.repo_name]])
1813 except KeyError:
1872 except KeyError:
1814 return False
1873 return False
1815 if self.required_perms.intersection(user_perms):
1874 if self.required_perms.intersection(user_perms):
1816 return True
1875 return True
1817 return False
1876 return False
1818
1877
1819
1878
1820 class HasRepoGroupPermissionAny(PermsFunction):
1879 class HasRepoGroupPermissionAny(PermsFunction):
1821 def __call__(self, group_name=None, check_location='', user=None):
1880 def __call__(self, group_name=None, check_location='', user=None):
1822 self.repo_group_name = group_name
1881 self.repo_group_name = group_name
1823 return super(HasRepoGroupPermissionAny, self).__call__(
1882 return super(HasRepoGroupPermissionAny, self).__call__(
1824 check_location, user)
1883 check_location, user)
1825
1884
1826 def check_permissions(self, user):
1885 def check_permissions(self, user):
1827 perms = user.permissions
1886 perms = user.permissions
1828 try:
1887 try:
1829 user_perms = set(
1888 user_perms = set(
1830 [perms['repositories_groups'][self.repo_group_name]])
1889 [perms['repositories_groups'][self.repo_group_name]])
1831 except KeyError:
1890 except KeyError:
1832 return False
1891 return False
1833 if self.required_perms.intersection(user_perms):
1892 if self.required_perms.intersection(user_perms):
1834 return True
1893 return True
1835 return False
1894 return False
1836
1895
1837
1896
1838 class HasRepoGroupPermissionAll(PermsFunction):
1897 class HasRepoGroupPermissionAll(PermsFunction):
1839 def __call__(self, group_name=None, check_location='', user=None):
1898 def __call__(self, group_name=None, check_location='', user=None):
1840 self.repo_group_name = group_name
1899 self.repo_group_name = group_name
1841 return super(HasRepoGroupPermissionAll, self).__call__(
1900 return super(HasRepoGroupPermissionAll, self).__call__(
1842 check_location, user)
1901 check_location, user)
1843
1902
1844 def check_permissions(self, user):
1903 def check_permissions(self, user):
1845 perms = user.permissions
1904 perms = user.permissions
1846 try:
1905 try:
1847 user_perms = set(
1906 user_perms = set(
1848 [perms['repositories_groups'][self.repo_group_name]])
1907 [perms['repositories_groups'][self.repo_group_name]])
1849 except KeyError:
1908 except KeyError:
1850 return False
1909 return False
1851 if self.required_perms.issubset(user_perms):
1910 if self.required_perms.issubset(user_perms):
1852 return True
1911 return True
1853 return False
1912 return False
1854
1913
1855
1914
1856 class HasUserGroupPermissionAny(PermsFunction):
1915 class HasUserGroupPermissionAny(PermsFunction):
1857 def __call__(self, user_group_name=None, check_location='', user=None):
1916 def __call__(self, user_group_name=None, check_location='', user=None):
1858 self.user_group_name = user_group_name
1917 self.user_group_name = user_group_name
1859 return super(HasUserGroupPermissionAny, self).__call__(
1918 return super(HasUserGroupPermissionAny, self).__call__(
1860 check_location, user)
1919 check_location, user)
1861
1920
1862 def check_permissions(self, user):
1921 def check_permissions(self, user):
1863 perms = user.permissions
1922 perms = user.permissions
1864 try:
1923 try:
1865 user_perms = set([perms['user_groups'][self.user_group_name]])
1924 user_perms = set([perms['user_groups'][self.user_group_name]])
1866 except KeyError:
1925 except KeyError:
1867 return False
1926 return False
1868 if self.required_perms.intersection(user_perms):
1927 if self.required_perms.intersection(user_perms):
1869 return True
1928 return True
1870 return False
1929 return False
1871
1930
1872
1931
1873 class HasUserGroupPermissionAll(PermsFunction):
1932 class HasUserGroupPermissionAll(PermsFunction):
1874 def __call__(self, user_group_name=None, check_location='', user=None):
1933 def __call__(self, user_group_name=None, check_location='', user=None):
1875 self.user_group_name = user_group_name
1934 self.user_group_name = user_group_name
1876 return super(HasUserGroupPermissionAll, self).__call__(
1935 return super(HasUserGroupPermissionAll, self).__call__(
1877 check_location, user)
1936 check_location, user)
1878
1937
1879 def check_permissions(self, user):
1938 def check_permissions(self, user):
1880 perms = user.permissions
1939 perms = user.permissions
1881 try:
1940 try:
1882 user_perms = set([perms['user_groups'][self.user_group_name]])
1941 user_perms = set([perms['user_groups'][self.user_group_name]])
1883 except KeyError:
1942 except KeyError:
1884 return False
1943 return False
1885 if self.required_perms.issubset(user_perms):
1944 if self.required_perms.issubset(user_perms):
1886 return True
1945 return True
1887 return False
1946 return False
1888
1947
1889
1948
1890 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
1949 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
1891 class HasPermissionAnyMiddleware(object):
1950 class HasPermissionAnyMiddleware(object):
1892 def __init__(self, *perms):
1951 def __init__(self, *perms):
1893 self.required_perms = set(perms)
1952 self.required_perms = set(perms)
1894
1953
1895 def __call__(self, user, repo_name):
1954 def __call__(self, user, repo_name):
1896 # repo_name MUST be unicode, since we handle keys in permission
1955 # repo_name MUST be unicode, since we handle keys in permission
1897 # dict by unicode
1956 # dict by unicode
1898 repo_name = safe_unicode(repo_name)
1957 repo_name = safe_unicode(repo_name)
1899 user = AuthUser(user.user_id)
1958 user = AuthUser(user.user_id)
1900 log.debug(
1959 log.debug(
1901 'Checking VCS protocol permissions %s for user:%s repo:`%s`',
1960 'Checking VCS protocol permissions %s for user:%s repo:`%s`',
1902 self.required_perms, user, repo_name)
1961 self.required_perms, user, repo_name)
1903
1962
1904 if self.check_permissions(user, repo_name):
1963 if self.check_permissions(user, repo_name):
1905 log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s',
1964 log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s',
1906 repo_name, user, 'PermissionMiddleware')
1965 repo_name, user, 'PermissionMiddleware')
1907 return True
1966 return True
1908
1967
1909 else:
1968 else:
1910 log.debug('Permission to repo:`%s` DENIED for user:%s @ %s',
1969 log.debug('Permission to repo:`%s` DENIED for user:%s @ %s',
1911 repo_name, user, 'PermissionMiddleware')
1970 repo_name, user, 'PermissionMiddleware')
1912 return False
1971 return False
1913
1972
1914 def check_permissions(self, user, repo_name):
1973 def check_permissions(self, user, repo_name):
1915 perms = user.permissions_with_scope({'repo_name': repo_name})
1974 perms = user.permissions_with_scope({'repo_name': repo_name})
1916
1975
1917 try:
1976 try:
1918 user_perms = set([perms['repositories'][repo_name]])
1977 user_perms = set([perms['repositories'][repo_name]])
1919 except Exception:
1978 except Exception:
1920 log.exception('Error while accessing user permissions')
1979 log.exception('Error while accessing user permissions')
1921 return False
1980 return False
1922
1981
1923 if self.required_perms.intersection(user_perms):
1982 if self.required_perms.intersection(user_perms):
1924 return True
1983 return True
1925 return False
1984 return False
1926
1985
1927
1986
1928 # SPECIAL VERSION TO HANDLE API AUTH
1987 # SPECIAL VERSION TO HANDLE API AUTH
1929 class _BaseApiPerm(object):
1988 class _BaseApiPerm(object):
1930 def __init__(self, *perms):
1989 def __init__(self, *perms):
1931 self.required_perms = set(perms)
1990 self.required_perms = set(perms)
1932
1991
1933 def __call__(self, check_location=None, user=None, repo_name=None,
1992 def __call__(self, check_location=None, user=None, repo_name=None,
1934 group_name=None, user_group_name=None):
1993 group_name=None, user_group_name=None):
1935 cls_name = self.__class__.__name__
1994 cls_name = self.__class__.__name__
1936 check_scope = 'global:%s' % (self.required_perms,)
1995 check_scope = 'global:%s' % (self.required_perms,)
1937 if repo_name:
1996 if repo_name:
1938 check_scope += ', repo_name:%s' % (repo_name,)
1997 check_scope += ', repo_name:%s' % (repo_name,)
1939
1998
1940 if group_name:
1999 if group_name:
1941 check_scope += ', repo_group_name:%s' % (group_name,)
2000 check_scope += ', repo_group_name:%s' % (group_name,)
1942
2001
1943 if user_group_name:
2002 if user_group_name:
1944 check_scope += ', user_group_name:%s' % (user_group_name,)
2003 check_scope += ', user_group_name:%s' % (user_group_name,)
1945
2004
1946 log.debug(
2005 log.debug(
1947 'checking cls:%s %s %s @ %s'
2006 'checking cls:%s %s %s @ %s'
1948 % (cls_name, self.required_perms, check_scope, check_location))
2007 % (cls_name, self.required_perms, check_scope, check_location))
1949 if not user:
2008 if not user:
1950 log.debug('Empty User passed into arguments')
2009 log.debug('Empty User passed into arguments')
1951 return False
2010 return False
1952
2011
1953 # process user
2012 # process user
1954 if not isinstance(user, AuthUser):
2013 if not isinstance(user, AuthUser):
1955 user = AuthUser(user.user_id)
2014 user = AuthUser(user.user_id)
1956 if not check_location:
2015 if not check_location:
1957 check_location = 'unspecified'
2016 check_location = 'unspecified'
1958 if self.check_permissions(user.permissions, repo_name, group_name,
2017 if self.check_permissions(user.permissions, repo_name, group_name,
1959 user_group_name):
2018 user_group_name):
1960 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
2019 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1961 check_scope, user, check_location)
2020 check_scope, user, check_location)
1962 return True
2021 return True
1963
2022
1964 else:
2023 else:
1965 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
2024 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1966 check_scope, user, check_location)
2025 check_scope, user, check_location)
1967 return False
2026 return False
1968
2027
1969 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2028 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1970 user_group_name=None):
2029 user_group_name=None):
1971 """
2030 """
1972 implement in child class should return True if permissions are ok,
2031 implement in child class should return True if permissions are ok,
1973 False otherwise
2032 False otherwise
1974
2033
1975 :param perm_defs: dict with permission definitions
2034 :param perm_defs: dict with permission definitions
1976 :param repo_name: repo name
2035 :param repo_name: repo name
1977 """
2036 """
1978 raise NotImplementedError()
2037 raise NotImplementedError()
1979
2038
1980
2039
1981 class HasPermissionAllApi(_BaseApiPerm):
2040 class HasPermissionAllApi(_BaseApiPerm):
1982 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2041 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1983 user_group_name=None):
2042 user_group_name=None):
1984 if self.required_perms.issubset(perm_defs.get('global')):
2043 if self.required_perms.issubset(perm_defs.get('global')):
1985 return True
2044 return True
1986 return False
2045 return False
1987
2046
1988
2047
1989 class HasPermissionAnyApi(_BaseApiPerm):
2048 class HasPermissionAnyApi(_BaseApiPerm):
1990 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2049 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1991 user_group_name=None):
2050 user_group_name=None):
1992 if self.required_perms.intersection(perm_defs.get('global')):
2051 if self.required_perms.intersection(perm_defs.get('global')):
1993 return True
2052 return True
1994 return False
2053 return False
1995
2054
1996
2055
1997 class HasRepoPermissionAllApi(_BaseApiPerm):
2056 class HasRepoPermissionAllApi(_BaseApiPerm):
1998 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2057 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1999 user_group_name=None):
2058 user_group_name=None):
2000 try:
2059 try:
2001 _user_perms = set([perm_defs['repositories'][repo_name]])
2060 _user_perms = set([perm_defs['repositories'][repo_name]])
2002 except KeyError:
2061 except KeyError:
2003 log.warning(traceback.format_exc())
2062 log.warning(traceback.format_exc())
2004 return False
2063 return False
2005 if self.required_perms.issubset(_user_perms):
2064 if self.required_perms.issubset(_user_perms):
2006 return True
2065 return True
2007 return False
2066 return False
2008
2067
2009
2068
2010 class HasRepoPermissionAnyApi(_BaseApiPerm):
2069 class HasRepoPermissionAnyApi(_BaseApiPerm):
2011 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2070 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2012 user_group_name=None):
2071 user_group_name=None):
2013 try:
2072 try:
2014 _user_perms = set([perm_defs['repositories'][repo_name]])
2073 _user_perms = set([perm_defs['repositories'][repo_name]])
2015 except KeyError:
2074 except KeyError:
2016 log.warning(traceback.format_exc())
2075 log.warning(traceback.format_exc())
2017 return False
2076 return False
2018 if self.required_perms.intersection(_user_perms):
2077 if self.required_perms.intersection(_user_perms):
2019 return True
2078 return True
2020 return False
2079 return False
2021
2080
2022
2081
2023 class HasRepoGroupPermissionAnyApi(_BaseApiPerm):
2082 class HasRepoGroupPermissionAnyApi(_BaseApiPerm):
2024 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2083 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2025 user_group_name=None):
2084 user_group_name=None):
2026 try:
2085 try:
2027 _user_perms = set([perm_defs['repositories_groups'][group_name]])
2086 _user_perms = set([perm_defs['repositories_groups'][group_name]])
2028 except KeyError:
2087 except KeyError:
2029 log.warning(traceback.format_exc())
2088 log.warning(traceback.format_exc())
2030 return False
2089 return False
2031 if self.required_perms.intersection(_user_perms):
2090 if self.required_perms.intersection(_user_perms):
2032 return True
2091 return True
2033 return False
2092 return False
2034
2093
2035
2094
2036 class HasRepoGroupPermissionAllApi(_BaseApiPerm):
2095 class HasRepoGroupPermissionAllApi(_BaseApiPerm):
2037 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2096 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2038 user_group_name=None):
2097 user_group_name=None):
2039 try:
2098 try:
2040 _user_perms = set([perm_defs['repositories_groups'][group_name]])
2099 _user_perms = set([perm_defs['repositories_groups'][group_name]])
2041 except KeyError:
2100 except KeyError:
2042 log.warning(traceback.format_exc())
2101 log.warning(traceback.format_exc())
2043 return False
2102 return False
2044 if self.required_perms.issubset(_user_perms):
2103 if self.required_perms.issubset(_user_perms):
2045 return True
2104 return True
2046 return False
2105 return False
2047
2106
2048
2107
2049 class HasUserGroupPermissionAnyApi(_BaseApiPerm):
2108 class HasUserGroupPermissionAnyApi(_BaseApiPerm):
2050 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2109 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
2051 user_group_name=None):
2110 user_group_name=None):
2052 try:
2111 try:
2053 _user_perms = set([perm_defs['user_groups'][user_group_name]])
2112 _user_perms = set([perm_defs['user_groups'][user_group_name]])
2054 except KeyError:
2113 except KeyError:
2055 log.warning(traceback.format_exc())
2114 log.warning(traceback.format_exc())
2056 return False
2115 return False
2057 if self.required_perms.intersection(_user_perms):
2116 if self.required_perms.intersection(_user_perms):
2058 return True
2117 return True
2059 return False
2118 return False
2060
2119
2061
2120
2062 def check_ip_access(source_ip, allowed_ips=None):
2121 def check_ip_access(source_ip, allowed_ips=None):
2063 """
2122 """
2064 Checks if source_ip is a subnet of any of allowed_ips.
2123 Checks if source_ip is a subnet of any of allowed_ips.
2065
2124
2066 :param source_ip:
2125 :param source_ip:
2067 :param allowed_ips: list of allowed ips together with mask
2126 :param allowed_ips: list of allowed ips together with mask
2068 """
2127 """
2069 log.debug('checking if ip:%s is subnet of %s' % (source_ip, allowed_ips))
2128 log.debug('checking if ip:%s is subnet of %s' % (source_ip, allowed_ips))
2070 source_ip_address = ipaddress.ip_address(safe_unicode(source_ip))
2129 source_ip_address = ipaddress.ip_address(safe_unicode(source_ip))
2071 if isinstance(allowed_ips, (tuple, list, set)):
2130 if isinstance(allowed_ips, (tuple, list, set)):
2072 for ip in allowed_ips:
2131 for ip in allowed_ips:
2073 ip = safe_unicode(ip)
2132 ip = safe_unicode(ip)
2074 try:
2133 try:
2075 network_address = ipaddress.ip_network(ip, strict=False)
2134 network_address = ipaddress.ip_network(ip, strict=False)
2076 if source_ip_address in network_address:
2135 if source_ip_address in network_address:
2077 log.debug('IP %s is network %s' %
2136 log.debug('IP %s is network %s' %
2078 (source_ip_address, network_address))
2137 (source_ip_address, network_address))
2079 return True
2138 return True
2080 # for any case we cannot determine the IP, don't crash just
2139 # for any case we cannot determine the IP, don't crash just
2081 # skip it and log as error, we want to say forbidden still when
2140 # skip it and log as error, we want to say forbidden still when
2082 # sending bad IP
2141 # sending bad IP
2083 except Exception:
2142 except Exception:
2084 log.error(traceback.format_exc())
2143 log.error(traceback.format_exc())
2085 continue
2144 continue
2086 return False
2145 return False
2087
2146
2088
2147
2089 def get_cython_compat_decorator(wrapper, func):
2148 def get_cython_compat_decorator(wrapper, func):
2090 """
2149 """
2091 Creates a cython compatible decorator. The previously used
2150 Creates a cython compatible decorator. The previously used
2092 decorator.decorator() function seems to be incompatible with cython.
2151 decorator.decorator() function seems to be incompatible with cython.
2093
2152
2094 :param wrapper: __wrapper method of the decorator class
2153 :param wrapper: __wrapper method of the decorator class
2095 :param func: decorated function
2154 :param func: decorated function
2096 """
2155 """
2097 @wraps(func)
2156 @wraps(func)
2098 def local_wrapper(*args, **kwds):
2157 def local_wrapper(*args, **kwds):
2099 return wrapper(func, *args, **kwds)
2158 return wrapper(func, *args, **kwds)
2100 local_wrapper.__wrapped__ = func
2159 local_wrapper.__wrapped__ = func
2101 return local_wrapper
2160 return local_wrapper
2102
2161
2103
2162
@@ -1,5 +1,5 b''
1 ## permissions overview
1 ## permissions overview
2 <div id="perms_container">
2 <div id="perms_container">
3 <%namespace name="p" file="/base/perms_summary.mako"/>
3 <%namespace name="p" file="/base/perms_summary.mako"/>
4 ${p.perms_summary(c.perm_user.permissions, actions=False)}
4 ${p.perms_summary(c.perm_user.permissions_full_details, actions=False)}
5 </div>
5 </div>
@@ -1,5 +1,5 b''
1 <h2>${_('Default User Permissions Overview')}</h2>
1 <h2>${_('Default User Permissions Overview')}</h2>
2
2
3 ## permissions overview
3 ## permissions overview
4 <%namespace name="p" file="/base/perms_summary.mako"/>
4 <%namespace name="p" file="/base/perms_summary.mako"/>
5 ${p.perms_summary(c.perm_user.permissions, show_all=True)}
5 ${p.perms_summary(c.perm_user.permissions_full_details, show_all=True)}
@@ -1,3 +1,3 b''
1 ## permissions overview
1 ## permissions overview
2 <%namespace name="p" file="/base/perms_summary.mako"/>
2 <%namespace name="p" file="/base/perms_summary.mako"/>
3 ${p.perms_summary(c.perm_user.permissions, show_all=True, side_link=h.route_path('edit_user_perms_summary_json', user_id=c.user.user_id))}
3 ${p.perms_summary(c.perm_user.permissions_full_details, show_all=True, side_link=h.route_path('edit_user_perms_summary_json', user_id=c.user.user_id))}
@@ -1,608 +1,617 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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.auth_token import AuthTokenModel
29 from rhodecode.model.auth_token import AuthTokenModel
30 from rhodecode.model.db import User
30 from rhodecode.model.db import User
31 from rhodecode.model.repo import RepoModel
31 from rhodecode.model.repo import RepoModel
32 from rhodecode.model.user import UserModel
32 from rhodecode.model.user import UserModel
33 from rhodecode.model.user_group import UserGroupModel
33 from rhodecode.model.user_group import UserGroupModel
34
34
35
35
36 def test_perm_origin_dict():
36 def test_perm_origin_dict():
37 pod = auth.PermOriginDict()
37 pod = auth.PermOriginDict()
38 pod['thing'] = 'read', 'default'
38 pod['thing'] = 'read', 'default'
39 assert pod['thing'] == 'read'
39 assert pod['thing'] == 'read'
40
40
41 assert pod.perm_origin_stack == {
41 assert pod.perm_origin_stack == {
42 'thing': [('read', 'default')]}
42 'thing': [('read', 'default')]}
43
43
44 pod['thing'] = 'write', 'admin'
44 pod['thing'] = 'write', 'admin'
45 assert pod['thing'] == 'write'
45 assert pod['thing'] == 'write'
46
46
47 assert pod.perm_origin_stack == {
47 assert pod.perm_origin_stack == {
48 'thing': [('read', 'default'), ('write', 'admin')]}
48 'thing': [('read', 'default'), ('write', 'admin')]}
49
49
50 pod['other'] = 'write', 'default'
50 pod['other'] = 'write', 'default'
51
51
52 assert pod.perm_origin_stack == {
52 assert pod.perm_origin_stack == {
53 'other': [('write', 'default')],
53 'other': [('write', 'default')],
54 'thing': [('read', 'default'), ('write', 'admin')]}
54 'thing': [('read', 'default'), ('write', 'admin')]}
55
55
56 pod['other'] = 'none', 'override'
56 pod['other'] = 'none', 'override'
57
57
58 assert pod.perm_origin_stack == {
58 assert pod.perm_origin_stack == {
59 'other': [('write', 'default'), ('none', 'override')],
59 'other': [('write', 'default'), ('none', 'override')],
60 'thing': [('read', 'default'), ('write', 'admin')]}
60 'thing': [('read', 'default'), ('write', 'admin')]}
61
61
62 with pytest.raises(ValueError):
62 with pytest.raises(ValueError):
63 pod['thing'] = 'read'
63 pod['thing'] = 'read'
64
64
65
65
66 def test_cached_perms_data(user_regular, backend_random):
66 def test_cached_perms_data(user_regular, backend_random):
67 permissions = get_permissions(user_regular)
67 permissions = get_permissions(user_regular)
68 repo_name = backend_random.repo.repo_name
68 repo_name = backend_random.repo.repo_name
69 expected_global_permissions = {
69 expected_global_permissions = {
70 'repository.read', 'group.read', 'usergroup.read'}
70 'repository.read', 'group.read', 'usergroup.read'}
71 assert expected_global_permissions.issubset(permissions['global'])
71 assert expected_global_permissions.issubset(permissions['global'])
72 assert permissions['repositories'][repo_name] == 'repository.read'
72 assert permissions['repositories'][repo_name] == 'repository.read'
73
73
74
74
75 def test_cached_perms_data_with_admin_user(user_regular, backend_random):
75 def test_cached_perms_data_with_admin_user(user_regular, backend_random):
76 permissions = get_permissions(user_regular, user_is_admin=True)
76 permissions = get_permissions(user_regular, user_is_admin=True)
77 repo_name = backend_random.repo.repo_name
77 repo_name = backend_random.repo.repo_name
78 assert 'hg.admin' in permissions['global']
78 assert 'hg.admin' in permissions['global']
79 assert permissions['repositories'][repo_name] == 'repository.admin'
79 assert permissions['repositories'][repo_name] == 'repository.admin'
80
80
81
81
82 def test_cached_perms_data_with_admin_user_extended_calculation(user_regular, backend_random):
83 permissions = get_permissions(user_regular, user_is_admin=True,
84 calculate_super_admin=True)
85 repo_name = backend_random.repo.repo_name
86 assert 'hg.admin' in permissions['global']
87 assert permissions['repositories'][repo_name] == 'repository.admin'
88
89
82 def test_cached_perms_data_user_group_global_permissions(user_util):
90 def test_cached_perms_data_user_group_global_permissions(user_util):
83 user, user_group = user_util.create_user_with_group()
91 user, user_group = user_util.create_user_with_group()
84 user_group.inherit_default_permissions = False
92 user_group.inherit_default_permissions = False
85
93
86 granted_permission = 'repository.write'
94 granted_permission = 'repository.write'
87 UserGroupModel().grant_perm(user_group, granted_permission)
95 UserGroupModel().grant_perm(user_group, granted_permission)
88
96
89 permissions = get_permissions(user)
97 permissions = get_permissions(user)
90 assert granted_permission in permissions['global']
98 assert granted_permission in permissions['global']
91
99
92
100
93 @pytest.mark.xfail(reason="Not implemented, see TODO note")
101 @pytest.mark.xfail(reason="Not implemented, see TODO note")
94 def test_cached_perms_data_user_group_global_permissions_(user_util):
102 def test_cached_perms_data_user_group_global_permissions_(user_util):
95 user, user_group = user_util.create_user_with_group()
103 user, user_group = user_util.create_user_with_group()
96
104
97 granted_permission = 'repository.write'
105 granted_permission = 'repository.write'
98 UserGroupModel().grant_perm(user_group, granted_permission)
106 UserGroupModel().grant_perm(user_group, granted_permission)
99
107
100 permissions = get_permissions(user)
108 permissions = get_permissions(user)
101 assert granted_permission in permissions['global']
109 assert granted_permission in permissions['global']
102
110
103
111
104 def test_cached_perms_data_user_global_permissions(user_util):
112 def test_cached_perms_data_user_global_permissions(user_util):
105 user = user_util.create_user()
113 user = user_util.create_user()
106 UserModel().grant_perm(user, 'repository.none')
114 UserModel().grant_perm(user, 'repository.none')
107
115
108 permissions = get_permissions(user, user_inherit_default_permissions=True)
116 permissions = get_permissions(user, user_inherit_default_permissions=True)
109 assert 'repository.read' in permissions['global']
117 assert 'repository.read' in permissions['global']
110
118
111
119
112 def test_cached_perms_data_repository_permissions_on_private_repository(
120 def test_cached_perms_data_repository_permissions_on_private_repository(
113 backend_random, user_util):
121 backend_random, user_util):
114 user, user_group = user_util.create_user_with_group()
122 user, user_group = user_util.create_user_with_group()
115
123
116 repo = backend_random.create_repo()
124 repo = backend_random.create_repo()
117 repo.private = True
125 repo.private = True
118
126
119 granted_permission = 'repository.write'
127 granted_permission = 'repository.write'
120 RepoModel().grant_user_group_permission(
128 RepoModel().grant_user_group_permission(
121 repo, user_group.users_group_name, granted_permission)
129 repo, user_group.users_group_name, granted_permission)
122
130
123 permissions = get_permissions(user)
131 permissions = get_permissions(user)
124 assert permissions['repositories'][repo.repo_name] == granted_permission
132 assert permissions['repositories'][repo.repo_name] == granted_permission
125
133
126
134
127 def test_cached_perms_data_repository_permissions_for_owner(
135 def test_cached_perms_data_repository_permissions_for_owner(
128 backend_random, user_util):
136 backend_random, user_util):
129 user = user_util.create_user()
137 user = user_util.create_user()
130
138
131 repo = backend_random.create_repo()
139 repo = backend_random.create_repo()
132 repo.user_id = user.user_id
140 repo.user_id = user.user_id
133
141
134 permissions = get_permissions(user)
142 permissions = get_permissions(user)
135 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
143 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
136
144
137 # TODO: johbo: Make cleanup in UserUtility smarter, then remove this hack
145 # TODO: johbo: Make cleanup in UserUtility smarter, then remove this hack
138 repo.user_id = User.get_default_user().user_id
146 repo.user_id = User.get_default_user().user_id
139
147
140
148
141 def test_cached_perms_data_repository_permissions_not_inheriting_defaults(
149 def test_cached_perms_data_repository_permissions_not_inheriting_defaults(
142 backend_random, user_util):
150 backend_random, user_util):
143 user = user_util.create_user()
151 user = user_util.create_user()
144 repo = backend_random.create_repo()
152 repo = backend_random.create_repo()
145
153
146 # Don't inherit default object permissions
154 # Don't inherit default object permissions
147 UserModel().grant_perm(user, 'hg.inherit_default_perms.false')
155 UserModel().grant_perm(user, 'hg.inherit_default_perms.false')
148
156
149 permissions = get_permissions(user)
157 permissions = get_permissions(user)
150 assert permissions['repositories'][repo.repo_name] == 'repository.none'
158 assert permissions['repositories'][repo.repo_name] == 'repository.none'
151
159
152
160
153 def test_cached_perms_data_default_permissions_on_repository_group(user_util):
161 def test_cached_perms_data_default_permissions_on_repository_group(user_util):
154 # Have a repository group with default permissions set
162 # Have a repository group with default permissions set
155 repo_group = user_util.create_repo_group()
163 repo_group = user_util.create_repo_group()
156 default_user = User.get_default_user()
164 default_user = User.get_default_user()
157 user_util.grant_user_permission_to_repo_group(
165 user_util.grant_user_permission_to_repo_group(
158 repo_group, default_user, 'repository.write')
166 repo_group, default_user, 'repository.write')
159 user = user_util.create_user()
167 user = user_util.create_user()
160
168
161 permissions = get_permissions(user)
169 permissions = get_permissions(user)
162 assert permissions['repositories_groups'][repo_group.group_name] == \
170 assert permissions['repositories_groups'][repo_group.group_name] == \
163 'repository.write'
171 'repository.write'
164
172
165
173
166 def test_cached_perms_data_default_permissions_on_repository_group_owner(
174 def test_cached_perms_data_default_permissions_on_repository_group_owner(
167 user_util):
175 user_util):
168 # Have a repository group
176 # Have a repository group
169 repo_group = user_util.create_repo_group()
177 repo_group = user_util.create_repo_group()
170 default_user = User.get_default_user()
178 default_user = User.get_default_user()
171
179
172 # Add a permission for the default user to hit the code path
180 # Add a permission for the default user to hit the code path
173 user_util.grant_user_permission_to_repo_group(
181 user_util.grant_user_permission_to_repo_group(
174 repo_group, default_user, 'repository.write')
182 repo_group, default_user, 'repository.write')
175
183
176 # Have an owner of the group
184 # Have an owner of the group
177 user = user_util.create_user()
185 user = user_util.create_user()
178 repo_group.user_id = user.user_id
186 repo_group.user_id = user.user_id
179
187
180 permissions = get_permissions(user)
188 permissions = get_permissions(user)
181 assert permissions['repositories_groups'][repo_group.group_name] == \
189 assert permissions['repositories_groups'][repo_group.group_name] == \
182 'group.admin'
190 'group.admin'
183
191
184
192
185 def test_cached_perms_data_default_permissions_on_repository_group_no_inherit(
193 def test_cached_perms_data_default_permissions_on_repository_group_no_inherit(
186 user_util):
194 user_util):
187 # Have a repository group
195 # Have a repository group
188 repo_group = user_util.create_repo_group()
196 repo_group = user_util.create_repo_group()
189 default_user = User.get_default_user()
197 default_user = User.get_default_user()
190
198
191 # Add a permission for the default user to hit the code path
199 # Add a permission for the default user to hit the code path
192 user_util.grant_user_permission_to_repo_group(
200 user_util.grant_user_permission_to_repo_group(
193 repo_group, default_user, 'repository.write')
201 repo_group, default_user, 'repository.write')
194
202
195 # Don't inherit default object permissions
203 # Don't inherit default object permissions
196 user = user_util.create_user()
204 user = user_util.create_user()
197 UserModel().grant_perm(user, 'hg.inherit_default_perms.false')
205 UserModel().grant_perm(user, 'hg.inherit_default_perms.false')
198
206
199 permissions = get_permissions(user)
207 permissions = get_permissions(user)
200 assert permissions['repositories_groups'][repo_group.group_name] == \
208 assert permissions['repositories_groups'][repo_group.group_name] == \
201 'group.none'
209 'group.none'
202
210
203
211
204 def test_cached_perms_data_repository_permissions_from_user_group(
212 def test_cached_perms_data_repository_permissions_from_user_group(
205 user_util, backend_random):
213 user_util, backend_random):
206 user, user_group = user_util.create_user_with_group()
214 user, user_group = user_util.create_user_with_group()
207
215
208 # Needs a second user group to make sure that we select the right
216 # Needs a second user group to make sure that we select the right
209 # permissions.
217 # permissions.
210 user_group2 = user_util.create_user_group()
218 user_group2 = user_util.create_user_group()
211 UserGroupModel().add_user_to_group(user_group2, user)
219 UserGroupModel().add_user_to_group(user_group2, user)
212
220
213 repo = backend_random.create_repo()
221 repo = backend_random.create_repo()
214
222
215 RepoModel().grant_user_group_permission(
223 RepoModel().grant_user_group_permission(
216 repo, user_group.users_group_name, 'repository.read')
224 repo, user_group.users_group_name, 'repository.read')
217 RepoModel().grant_user_group_permission(
225 RepoModel().grant_user_group_permission(
218 repo, user_group2.users_group_name, 'repository.write')
226 repo, user_group2.users_group_name, 'repository.write')
219
227
220 permissions = get_permissions(user)
228 permissions = get_permissions(user)
221 assert permissions['repositories'][repo.repo_name] == 'repository.write'
229 assert permissions['repositories'][repo.repo_name] == 'repository.write'
222
230
223
231
224 def test_cached_perms_data_repository_permissions_from_user_group_owner(
232 def test_cached_perms_data_repository_permissions_from_user_group_owner(
225 user_util, backend_random):
233 user_util, backend_random):
226 user, user_group = user_util.create_user_with_group()
234 user, user_group = user_util.create_user_with_group()
227
235
228 repo = backend_random.create_repo()
236 repo = backend_random.create_repo()
229 repo.user_id = user.user_id
237 repo.user_id = user.user_id
230
238
231 RepoModel().grant_user_group_permission(
239 RepoModel().grant_user_group_permission(
232 repo, user_group.users_group_name, 'repository.write')
240 repo, user_group.users_group_name, 'repository.write')
233
241
234 permissions = get_permissions(user)
242 permissions = get_permissions(user)
235 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
243 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
236
244
237
245
238 def test_cached_perms_data_user_repository_permissions(
246 def test_cached_perms_data_user_repository_permissions(
239 user_util, backend_random):
247 user_util, backend_random):
240 user = user_util.create_user()
248 user = user_util.create_user()
241 repo = backend_random.create_repo()
249 repo = backend_random.create_repo()
242 granted_permission = 'repository.write'
250 granted_permission = 'repository.write'
243 RepoModel().grant_user_permission(repo, user, granted_permission)
251 RepoModel().grant_user_permission(repo, user, granted_permission)
244
252
245 permissions = get_permissions(user)
253 permissions = get_permissions(user)
246 assert permissions['repositories'][repo.repo_name] == granted_permission
254 assert permissions['repositories'][repo.repo_name] == granted_permission
247
255
248
256
249 def test_cached_perms_data_user_repository_permissions_explicit(
257 def test_cached_perms_data_user_repository_permissions_explicit(
250 user_util, backend_random):
258 user_util, backend_random):
251 user = user_util.create_user()
259 user = user_util.create_user()
252 repo = backend_random.create_repo()
260 repo = backend_random.create_repo()
253 granted_permission = 'repository.none'
261 granted_permission = 'repository.none'
254 RepoModel().grant_user_permission(repo, user, granted_permission)
262 RepoModel().grant_user_permission(repo, user, granted_permission)
255
263
256 permissions = get_permissions(user, explicit=True)
264 permissions = get_permissions(user, explicit=True)
257 assert permissions['repositories'][repo.repo_name] == granted_permission
265 assert permissions['repositories'][repo.repo_name] == granted_permission
258
266
259
267
260 def test_cached_perms_data_user_repository_permissions_owner(
268 def test_cached_perms_data_user_repository_permissions_owner(
261 user_util, backend_random):
269 user_util, backend_random):
262 user = user_util.create_user()
270 user = user_util.create_user()
263 repo = backend_random.create_repo()
271 repo = backend_random.create_repo()
264 repo.user_id = user.user_id
272 repo.user_id = user.user_id
265 RepoModel().grant_user_permission(repo, user, 'repository.write')
273 RepoModel().grant_user_permission(repo, user, 'repository.write')
266
274
267 permissions = get_permissions(user)
275 permissions = get_permissions(user)
268 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
276 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
269
277
270
278
271 def test_cached_perms_data_repository_groups_permissions_inherited(
279 def test_cached_perms_data_repository_groups_permissions_inherited(
272 user_util, backend_random):
280 user_util, backend_random):
273 user, user_group = user_util.create_user_with_group()
281 user, user_group = user_util.create_user_with_group()
274
282
275 # Needs a second group to hit the last condition
283 # Needs a second group to hit the last condition
276 user_group2 = user_util.create_user_group()
284 user_group2 = user_util.create_user_group()
277 UserGroupModel().add_user_to_group(user_group2, user)
285 UserGroupModel().add_user_to_group(user_group2, user)
278
286
279 repo_group = user_util.create_repo_group()
287 repo_group = user_util.create_repo_group()
280
288
281 user_util.grant_user_group_permission_to_repo_group(
289 user_util.grant_user_group_permission_to_repo_group(
282 repo_group, user_group, 'group.read')
290 repo_group, user_group, 'group.read')
283 user_util.grant_user_group_permission_to_repo_group(
291 user_util.grant_user_group_permission_to_repo_group(
284 repo_group, user_group2, 'group.write')
292 repo_group, user_group2, 'group.write')
285
293
286 permissions = get_permissions(user)
294 permissions = get_permissions(user)
287 assert permissions['repositories_groups'][repo_group.group_name] == \
295 assert permissions['repositories_groups'][repo_group.group_name] == \
288 'group.write'
296 'group.write'
289
297
290
298
291 def test_cached_perms_data_repository_groups_permissions_inherited_owner(
299 def test_cached_perms_data_repository_groups_permissions_inherited_owner(
292 user_util, backend_random):
300 user_util, backend_random):
293 user, user_group = user_util.create_user_with_group()
301 user, user_group = user_util.create_user_with_group()
294 repo_group = user_util.create_repo_group()
302 repo_group = user_util.create_repo_group()
295 repo_group.user_id = user.user_id
303 repo_group.user_id = user.user_id
296
304
297 granted_permission = 'group.write'
305 granted_permission = 'group.write'
298 user_util.grant_user_group_permission_to_repo_group(
306 user_util.grant_user_group_permission_to_repo_group(
299 repo_group, user_group, granted_permission)
307 repo_group, user_group, granted_permission)
300
308
301 permissions = get_permissions(user)
309 permissions = get_permissions(user)
302 assert permissions['repositories_groups'][repo_group.group_name] == \
310 assert permissions['repositories_groups'][repo_group.group_name] == \
303 'group.admin'
311 'group.admin'
304
312
305
313
306 def test_cached_perms_data_repository_groups_permissions(
314 def test_cached_perms_data_repository_groups_permissions(
307 user_util, backend_random):
315 user_util, backend_random):
308 user = user_util.create_user()
316 user = user_util.create_user()
309
317
310 repo_group = user_util.create_repo_group()
318 repo_group = user_util.create_repo_group()
311
319
312 granted_permission = 'group.write'
320 granted_permission = 'group.write'
313 user_util.grant_user_permission_to_repo_group(
321 user_util.grant_user_permission_to_repo_group(
314 repo_group, user, granted_permission)
322 repo_group, user, granted_permission)
315
323
316 permissions = get_permissions(user)
324 permissions = get_permissions(user)
317 assert permissions['repositories_groups'][repo_group.group_name] == \
325 assert permissions['repositories_groups'][repo_group.group_name] == \
318 'group.write'
326 'group.write'
319
327
320
328
321 def test_cached_perms_data_repository_groups_permissions_explicit(
329 def test_cached_perms_data_repository_groups_permissions_explicit(
322 user_util, backend_random):
330 user_util, backend_random):
323 user = user_util.create_user()
331 user = user_util.create_user()
324
332
325 repo_group = user_util.create_repo_group()
333 repo_group = user_util.create_repo_group()
326
334
327 granted_permission = 'group.none'
335 granted_permission = 'group.none'
328 user_util.grant_user_permission_to_repo_group(
336 user_util.grant_user_permission_to_repo_group(
329 repo_group, user, granted_permission)
337 repo_group, user, granted_permission)
330
338
331 permissions = get_permissions(user, explicit=True)
339 permissions = get_permissions(user, explicit=True)
332 assert permissions['repositories_groups'][repo_group.group_name] == \
340 assert permissions['repositories_groups'][repo_group.group_name] == \
333 'group.none'
341 'group.none'
334
342
335
343
336 def test_cached_perms_data_repository_groups_permissions_owner(
344 def test_cached_perms_data_repository_groups_permissions_owner(
337 user_util, backend_random):
345 user_util, backend_random):
338 user = user_util.create_user()
346 user = user_util.create_user()
339
347
340 repo_group = user_util.create_repo_group()
348 repo_group = user_util.create_repo_group()
341 repo_group.user_id = user.user_id
349 repo_group.user_id = user.user_id
342
350
343 granted_permission = 'group.write'
351 granted_permission = 'group.write'
344 user_util.grant_user_permission_to_repo_group(
352 user_util.grant_user_permission_to_repo_group(
345 repo_group, user, granted_permission)
353 repo_group, user, granted_permission)
346
354
347 permissions = get_permissions(user)
355 permissions = get_permissions(user)
348 assert permissions['repositories_groups'][repo_group.group_name] == \
356 assert permissions['repositories_groups'][repo_group.group_name] == \
349 'group.admin'
357 'group.admin'
350
358
351
359
352 def test_cached_perms_data_user_group_permissions_inherited(
360 def test_cached_perms_data_user_group_permissions_inherited(
353 user_util, backend_random):
361 user_util, backend_random):
354 user, user_group = user_util.create_user_with_group()
362 user, user_group = user_util.create_user_with_group()
355 user_group2 = user_util.create_user_group()
363 user_group2 = user_util.create_user_group()
356 UserGroupModel().add_user_to_group(user_group2, user)
364 UserGroupModel().add_user_to_group(user_group2, user)
357
365
358 target_user_group = user_util.create_user_group()
366 target_user_group = user_util.create_user_group()
359
367
360 user_util.grant_user_group_permission_to_user_group(
368 user_util.grant_user_group_permission_to_user_group(
361 target_user_group, user_group, 'usergroup.read')
369 target_user_group, user_group, 'usergroup.read')
362 user_util.grant_user_group_permission_to_user_group(
370 user_util.grant_user_group_permission_to_user_group(
363 target_user_group, user_group2, 'usergroup.write')
371 target_user_group, user_group2, 'usergroup.write')
364
372
365 permissions = get_permissions(user)
373 permissions = get_permissions(user)
366 assert permissions['user_groups'][target_user_group.users_group_name] == \
374 assert permissions['user_groups'][target_user_group.users_group_name] == \
367 'usergroup.write'
375 'usergroup.write'
368
376
369
377
370 def test_cached_perms_data_user_group_permissions(
378 def test_cached_perms_data_user_group_permissions(
371 user_util, backend_random):
379 user_util, backend_random):
372 user = user_util.create_user()
380 user = user_util.create_user()
373 user_group = user_util.create_user_group()
381 user_group = user_util.create_user_group()
374 UserGroupModel().grant_user_permission(user_group, user, 'usergroup.write')
382 UserGroupModel().grant_user_permission(user_group, user, 'usergroup.write')
375
383
376 permissions = get_permissions(user)
384 permissions = get_permissions(user)
377 assert permissions['user_groups'][user_group.users_group_name] == \
385 assert permissions['user_groups'][user_group.users_group_name] == \
378 'usergroup.write'
386 'usergroup.write'
379
387
380
388
381 def test_cached_perms_data_user_group_permissions_explicit(
389 def test_cached_perms_data_user_group_permissions_explicit(
382 user_util, backend_random):
390 user_util, backend_random):
383 user = user_util.create_user()
391 user = user_util.create_user()
384 user_group = user_util.create_user_group()
392 user_group = user_util.create_user_group()
385 UserGroupModel().grant_user_permission(user_group, user, 'usergroup.none')
393 UserGroupModel().grant_user_permission(user_group, user, 'usergroup.none')
386
394
387 permissions = get_permissions(user, explicit=True)
395 permissions = get_permissions(user, explicit=True)
388 assert permissions['user_groups'][user_group.users_group_name] == \
396 assert permissions['user_groups'][user_group.users_group_name] == \
389 'usergroup.none'
397 'usergroup.none'
390
398
391
399
392 def test_cached_perms_data_user_group_permissions_not_inheriting_defaults(
400 def test_cached_perms_data_user_group_permissions_not_inheriting_defaults(
393 user_util, backend_random):
401 user_util, backend_random):
394 user = user_util.create_user()
402 user = user_util.create_user()
395 user_group = user_util.create_user_group()
403 user_group = user_util.create_user_group()
396
404
397 # Don't inherit default object permissions
405 # Don't inherit default object permissions
398 UserModel().grant_perm(user, 'hg.inherit_default_perms.false')
406 UserModel().grant_perm(user, 'hg.inherit_default_perms.false')
399
407
400 permissions = get_permissions(user)
408 permissions = get_permissions(user)
401 assert permissions['user_groups'][user_group.users_group_name] == \
409 assert permissions['user_groups'][user_group.users_group_name] == \
402 'usergroup.none'
410 'usergroup.none'
403
411
404
412
405 def test_permission_calculator_admin_permissions(
413 def test_permission_calculator_admin_permissions(
406 user_util, backend_random):
414 user_util, backend_random):
407 user = user_util.create_user()
415 user = user_util.create_user()
408 user_group = user_util.create_user_group()
416 user_group = user_util.create_user_group()
409 repo = backend_random.repo
417 repo = backend_random.repo
410 repo_group = user_util.create_repo_group()
418 repo_group = user_util.create_repo_group()
411
419
412 calculator = auth.PermissionCalculator(
420 calculator = auth.PermissionCalculator(
413 user.user_id, {}, False, False, True, 'higherwin')
421 user.user_id, {}, False, False, True, 'higherwin')
414 permissions = calculator._admin_permissions()
422 permissions = calculator._admin_permissions()
415
423
416 assert permissions['repositories_groups'][repo_group.group_name] == \
424 assert permissions['repositories_groups'][repo_group.group_name] == \
417 'group.admin'
425 'group.admin'
418 assert permissions['user_groups'][user_group.users_group_name] == \
426 assert permissions['user_groups'][user_group.users_group_name] == \
419 'usergroup.admin'
427 'usergroup.admin'
420 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
428 assert permissions['repositories'][repo.repo_name] == 'repository.admin'
421 assert 'hg.admin' in permissions['global']
429 assert 'hg.admin' in permissions['global']
422
430
423
431
424 def test_permission_calculator_repository_permissions_robustness_from_group(
432 def test_permission_calculator_repository_permissions_robustness_from_group(
425 user_util, backend_random):
433 user_util, backend_random):
426 user, user_group = user_util.create_user_with_group()
434 user, user_group = user_util.create_user_with_group()
427
435
428 RepoModel().grant_user_group_permission(
436 RepoModel().grant_user_group_permission(
429 backend_random.repo, user_group.users_group_name, 'repository.write')
437 backend_random.repo, user_group.users_group_name, 'repository.write')
430
438
431 calculator = auth.PermissionCalculator(
439 calculator = auth.PermissionCalculator(
432 user.user_id, {}, False, False, False, 'higherwin')
440 user.user_id, {}, False, False, False, 'higherwin')
433 calculator._calculate_repository_permissions()
441 calculator._calculate_repository_permissions()
434
442
435
443
436 def test_permission_calculator_repository_permissions_robustness_from_user(
444 def test_permission_calculator_repository_permissions_robustness_from_user(
437 user_util, backend_random):
445 user_util, backend_random):
438 user = user_util.create_user()
446 user = user_util.create_user()
439
447
440 RepoModel().grant_user_permission(
448 RepoModel().grant_user_permission(
441 backend_random.repo, user, 'repository.write')
449 backend_random.repo, user, 'repository.write')
442
450
443 calculator = auth.PermissionCalculator(
451 calculator = auth.PermissionCalculator(
444 user.user_id, {}, False, False, False, 'higherwin')
452 user.user_id, {}, False, False, False, 'higherwin')
445 calculator._calculate_repository_permissions()
453 calculator._calculate_repository_permissions()
446
454
447
455
448 def test_permission_calculator_repo_group_permissions_robustness_from_group(
456 def test_permission_calculator_repo_group_permissions_robustness_from_group(
449 user_util, backend_random):
457 user_util, backend_random):
450 user, user_group = user_util.create_user_with_group()
458 user, user_group = user_util.create_user_with_group()
451 repo_group = user_util.create_repo_group()
459 repo_group = user_util.create_repo_group()
452
460
453 user_util.grant_user_group_permission_to_repo_group(
461 user_util.grant_user_group_permission_to_repo_group(
454 repo_group, user_group, 'group.write')
462 repo_group, user_group, 'group.write')
455
463
456 calculator = auth.PermissionCalculator(
464 calculator = auth.PermissionCalculator(
457 user.user_id, {}, False, False, False, 'higherwin')
465 user.user_id, {}, False, False, False, 'higherwin')
458 calculator._calculate_repository_group_permissions()
466 calculator._calculate_repository_group_permissions()
459
467
460
468
461 def test_permission_calculator_repo_group_permissions_robustness_from_user(
469 def test_permission_calculator_repo_group_permissions_robustness_from_user(
462 user_util, backend_random):
470 user_util, backend_random):
463 user = user_util.create_user()
471 user = user_util.create_user()
464 repo_group = user_util.create_repo_group()
472 repo_group = user_util.create_repo_group()
465
473
466 user_util.grant_user_permission_to_repo_group(
474 user_util.grant_user_permission_to_repo_group(
467 repo_group, user, 'group.write')
475 repo_group, user, 'group.write')
468
476
469 calculator = auth.PermissionCalculator(
477 calculator = auth.PermissionCalculator(
470 user.user_id, {}, False, False, False, 'higherwin')
478 user.user_id, {}, False, False, False, 'higherwin')
471 calculator._calculate_repository_group_permissions()
479 calculator._calculate_repository_group_permissions()
472
480
473
481
474 def test_permission_calculator_user_group_permissions_robustness_from_group(
482 def test_permission_calculator_user_group_permissions_robustness_from_group(
475 user_util, backend_random):
483 user_util, backend_random):
476 user, user_group = user_util.create_user_with_group()
484 user, user_group = user_util.create_user_with_group()
477 target_user_group = user_util.create_user_group()
485 target_user_group = user_util.create_user_group()
478
486
479 user_util.grant_user_group_permission_to_user_group(
487 user_util.grant_user_group_permission_to_user_group(
480 target_user_group, user_group, 'usergroup.write')
488 target_user_group, user_group, 'usergroup.write')
481
489
482 calculator = auth.PermissionCalculator(
490 calculator = auth.PermissionCalculator(
483 user.user_id, {}, False, False, False, 'higherwin')
491 user.user_id, {}, False, False, False, 'higherwin')
484 calculator._calculate_user_group_permissions()
492 calculator._calculate_user_group_permissions()
485
493
486
494
487 def test_permission_calculator_user_group_permissions_robustness_from_user(
495 def test_permission_calculator_user_group_permissions_robustness_from_user(
488 user_util, backend_random):
496 user_util, backend_random):
489 user = user_util.create_user()
497 user = user_util.create_user()
490 target_user_group = user_util.create_user_group()
498 target_user_group = user_util.create_user_group()
491
499
492 user_util.grant_user_permission_to_user_group(
500 user_util.grant_user_permission_to_user_group(
493 target_user_group, user, 'usergroup.write')
501 target_user_group, user, 'usergroup.write')
494
502
495 calculator = auth.PermissionCalculator(
503 calculator = auth.PermissionCalculator(
496 user.user_id, {}, False, False, False, 'higherwin')
504 user.user_id, {}, False, False, False, 'higherwin')
497 calculator._calculate_user_group_permissions()
505 calculator._calculate_user_group_permissions()
498
506
499
507
500 @pytest.mark.parametrize("algo, new_permission, old_permission, expected", [
508 @pytest.mark.parametrize("algo, new_permission, old_permission, expected", [
501 ('higherwin', 'repository.none', 'repository.none', 'repository.none'),
509 ('higherwin', 'repository.none', 'repository.none', 'repository.none'),
502 ('higherwin', 'repository.read', 'repository.none', 'repository.read'),
510 ('higherwin', 'repository.read', 'repository.none', 'repository.read'),
503 ('lowerwin', 'repository.write', 'repository.write', 'repository.write'),
511 ('lowerwin', 'repository.write', 'repository.write', 'repository.write'),
504 ('lowerwin', 'repository.read', 'repository.write', 'repository.read'),
512 ('lowerwin', 'repository.read', 'repository.write', 'repository.read'),
505 ])
513 ])
506 def test_permission_calculator_choose_permission(
514 def test_permission_calculator_choose_permission(
507 user_regular, algo, new_permission, old_permission, expected):
515 user_regular, algo, new_permission, old_permission, expected):
508 calculator = auth.PermissionCalculator(
516 calculator = auth.PermissionCalculator(
509 user_regular.user_id, {}, False, False, False, algo)
517 user_regular.user_id, {}, False, False, False, algo)
510 result = calculator._choose_permission(new_permission, old_permission)
518 result = calculator._choose_permission(new_permission, old_permission)
511 assert result == expected
519 assert result == expected
512
520
513
521
514 def test_permission_calculator_choose_permission_raises_on_wrong_algo(
522 def test_permission_calculator_choose_permission_raises_on_wrong_algo(
515 user_regular):
523 user_regular):
516 calculator = auth.PermissionCalculator(
524 calculator = auth.PermissionCalculator(
517 user_regular.user_id, {}, False, False, False, 'invalid')
525 user_regular.user_id, {}, False, False, False, 'invalid')
518 result = calculator._choose_permission(
526 result = calculator._choose_permission(
519 'repository.read', 'repository.read')
527 'repository.read', 'repository.read')
520 # TODO: johbo: This documents the existing behavior. Think of an
528 # TODO: johbo: This documents the existing behavior. Think of an
521 # improvement.
529 # improvement.
522 assert result is None
530 assert result is None
523
531
524
532
525 def test_auth_user_get_cookie_store_for_normal_user(user_util):
533 def test_auth_user_get_cookie_store_for_normal_user(user_util):
526 user = user_util.create_user()
534 user = user_util.create_user()
527 auth_user = auth.AuthUser(user_id=user.user_id)
535 auth_user = auth.AuthUser(user_id=user.user_id)
528 expected_data = {
536 expected_data = {
529 'username': user.username,
537 'username': user.username,
530 'user_id': user.user_id,
538 'user_id': user.user_id,
531 'password': md5(user.password),
539 'password': md5(user.password),
532 'is_authenticated': False
540 'is_authenticated': False
533 }
541 }
534 assert auth_user.get_cookie_store() == expected_data
542 assert auth_user.get_cookie_store() == expected_data
535
543
536
544
537 def test_auth_user_get_cookie_store_for_default_user():
545 def test_auth_user_get_cookie_store_for_default_user():
538 default_user = User.get_default_user()
546 default_user = User.get_default_user()
539 auth_user = auth.AuthUser()
547 auth_user = auth.AuthUser()
540 expected_data = {
548 expected_data = {
541 'username': User.DEFAULT_USER,
549 'username': User.DEFAULT_USER,
542 'user_id': default_user.user_id,
550 'user_id': default_user.user_id,
543 'password': md5(default_user.password),
551 'password': md5(default_user.password),
544 'is_authenticated': True
552 'is_authenticated': True
545 }
553 }
546 assert auth_user.get_cookie_store() == expected_data
554 assert auth_user.get_cookie_store() == expected_data
547
555
548
556
549 def get_permissions(user, **kwargs):
557 def get_permissions(user, **kwargs):
550 """
558 """
551 Utility filling in useful defaults into the call to `_cached_perms_data`.
559 Utility filling in useful defaults into the call to `_cached_perms_data`.
552
560
553 Fill in `**kwargs` if specific values are needed for a test.
561 Fill in `**kwargs` if specific values are needed for a test.
554 """
562 """
555 call_args = {
563 call_args = {
556 'user_id': user.user_id,
564 'user_id': user.user_id,
557 'scope': {},
565 'scope': {},
558 'user_is_admin': False,
566 'user_is_admin': False,
559 'user_inherit_default_permissions': False,
567 'user_inherit_default_permissions': False,
560 'explicit': False,
568 'explicit': False,
561 'algo': 'higherwin',
569 'algo': 'higherwin',
570 'calculate_super_admin': False,
562 }
571 }
563 call_args.update(kwargs)
572 call_args.update(kwargs)
564 permissions = auth._cached_perms_data(**call_args)
573 permissions = auth._cached_perms_data(**call_args)
565 return permissions
574 return permissions
566
575
567
576
568 class TestGenerateAuthToken(object):
577 class TestGenerateAuthToken(object):
569 def test_salt_is_used_when_specified(self):
578 def test_salt_is_used_when_specified(self):
570 salt = 'abcde'
579 salt = 'abcde'
571 user_name = 'test_user'
580 user_name = 'test_user'
572 result = auth.generate_auth_token(user_name, salt)
581 result = auth.generate_auth_token(user_name, salt)
573 expected_result = sha1(user_name + salt).hexdigest()
582 expected_result = sha1(user_name + salt).hexdigest()
574 assert result == expected_result
583 assert result == expected_result
575
584
576 def test_salt_is_geneated_when_not_specified(self):
585 def test_salt_is_geneated_when_not_specified(self):
577 user_name = 'test_user'
586 user_name = 'test_user'
578 random_salt = os.urandom(16)
587 random_salt = os.urandom(16)
579 with patch.object(auth, 'os') as os_mock:
588 with patch.object(auth, 'os') as os_mock:
580 os_mock.urandom.return_value = random_salt
589 os_mock.urandom.return_value = random_salt
581 result = auth.generate_auth_token(user_name)
590 result = auth.generate_auth_token(user_name)
582 expected_result = sha1(user_name + random_salt).hexdigest()
591 expected_result = sha1(user_name + random_salt).hexdigest()
583 assert result == expected_result
592 assert result == expected_result
584
593
585
594
586 @pytest.mark.parametrize("test_token, test_roles, auth_result, expected_tokens", [
595 @pytest.mark.parametrize("test_token, test_roles, auth_result, expected_tokens", [
587 ('', None, False,
596 ('', None, False,
588 []),
597 []),
589 ('wrongtoken', None, False,
598 ('wrongtoken', None, False,
590 []),
599 []),
591 ('abracadabra_vcs', [AuthTokenModel.cls.ROLE_API], False,
600 ('abracadabra_vcs', [AuthTokenModel.cls.ROLE_API], False,
592 [('abracadabra_api', AuthTokenModel.cls.ROLE_API, -1)]),
601 [('abracadabra_api', AuthTokenModel.cls.ROLE_API, -1)]),
593 ('abracadabra_api', [AuthTokenModel.cls.ROLE_API], True,
602 ('abracadabra_api', [AuthTokenModel.cls.ROLE_API], True,
594 [('abracadabra_api', AuthTokenModel.cls.ROLE_API, -1)]),
603 [('abracadabra_api', AuthTokenModel.cls.ROLE_API, -1)]),
595 ('abracadabra_api', [AuthTokenModel.cls.ROLE_API], True,
604 ('abracadabra_api', [AuthTokenModel.cls.ROLE_API], True,
596 [('abracadabra_api', AuthTokenModel.cls.ROLE_API, -1),
605 [('abracadabra_api', AuthTokenModel.cls.ROLE_API, -1),
597 ('abracadabra_http', AuthTokenModel.cls.ROLE_HTTP, -1)]),
606 ('abracadabra_http', AuthTokenModel.cls.ROLE_HTTP, -1)]),
598 ])
607 ])
599 def test_auth_by_token(test_token, test_roles, auth_result, expected_tokens,
608 def test_auth_by_token(test_token, test_roles, auth_result, expected_tokens,
600 user_util):
609 user_util):
601 user = user_util.create_user()
610 user = user_util.create_user()
602 user_id = user.user_id
611 user_id = user.user_id
603 for token, role, expires in expected_tokens:
612 for token, role, expires in expected_tokens:
604 new_token = AuthTokenModel().create(user_id, 'test-token', expires, role)
613 new_token = AuthTokenModel().create(user_id, 'test-token', expires, role)
605 new_token.api_key = token # inject known name for testing...
614 new_token.api_key = token # inject known name for testing...
606
615
607 assert auth_result == user.authenticate_by_token(
616 assert auth_result == user.authenticate_by_token(
608 test_token, roles=test_roles)
617 test_token, roles=test_roles)
General Comments 0
You need to be logged in to leave comments. Login now