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