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