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