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