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