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