##// END OF EJS Templates
auth: Change login url generation in auth decorators....
johbo -
r35:3c60da43 default
parent child Browse files
Show More
@@ -1,1826 +1,1828 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):
868 def is_default(self):
869 return self.username == User.DEFAULT_USER
869 return self.username == User.DEFAULT_USER
870
870
871 @property
871 @property
872 def is_admin(self):
872 def is_admin(self):
873 return self.admin
873 return self.admin
874
874
875 @property
875 @property
876 def is_user_object(self):
876 def is_user_object(self):
877 return self.user_id is not None
877 return self.user_id is not None
878
878
879 @property
879 @property
880 def repositories_admin(self):
880 def repositories_admin(self):
881 """
881 """
882 Returns list of repositories you're an admin of
882 Returns list of repositories you're an admin of
883 """
883 """
884 return [x[0] for x in self.permissions['repositories'].iteritems()
884 return [x[0] for x in self.permissions['repositories'].iteritems()
885 if x[1] == 'repository.admin']
885 if x[1] == 'repository.admin']
886
886
887 @property
887 @property
888 def repository_groups_admin(self):
888 def repository_groups_admin(self):
889 """
889 """
890 Returns list of repository groups you're an admin of
890 Returns list of repository groups you're an admin of
891 """
891 """
892 return [x[0]
892 return [x[0]
893 for x in self.permissions['repositories_groups'].iteritems()
893 for x in self.permissions['repositories_groups'].iteritems()
894 if x[1] == 'group.admin']
894 if x[1] == 'group.admin']
895
895
896 @property
896 @property
897 def user_groups_admin(self):
897 def user_groups_admin(self):
898 """
898 """
899 Returns list of user groups you're an admin of
899 Returns list of user groups you're an admin of
900 """
900 """
901 return [x[0] for x in self.permissions['user_groups'].iteritems()
901 return [x[0] for x in self.permissions['user_groups'].iteritems()
902 if x[1] == 'usergroup.admin']
902 if x[1] == 'usergroup.admin']
903
903
904 @property
904 @property
905 def ip_allowed(self):
905 def ip_allowed(self):
906 """
906 """
907 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
908 allowed ip_addresses for user
908 allowed ip_addresses for user
909
909
910 :returns: boolean, True if ip is in allowed ip range
910 :returns: boolean, True if ip is in allowed ip range
911 """
911 """
912 # check IP
912 # check IP
913 inherit = self.inherit_default_permissions
913 inherit = self.inherit_default_permissions
914 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
914 return AuthUser.check_ip_allowed(self.user_id, self.ip_addr,
915 inherit_from_default=inherit)
915 inherit_from_default=inherit)
916
916
917 @classmethod
917 @classmethod
918 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):
919 allowed_ips = AuthUser.get_allowed_ips(
919 allowed_ips = AuthUser.get_allowed_ips(
920 user_id, cache=True, inherit_from_default=inherit_from_default)
920 user_id, cache=True, inherit_from_default=inherit_from_default)
921 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):
922 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))
923 return True
923 return True
924 else:
924 else:
925 log.info('Access for IP:%s forbidden, '
925 log.info('Access for IP:%s forbidden, '
926 'not in %s' % (ip_addr, allowed_ips))
926 'not in %s' % (ip_addr, allowed_ips))
927 return False
927 return False
928
928
929 def __repr__(self):
929 def __repr__(self):
930 return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
930 return "<AuthUser('id:%s[%s] ip:%s auth:%s')>"\
931 % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
931 % (self.user_id, self.username, self.ip_addr, self.is_authenticated)
932
932
933 def set_authenticated(self, authenticated=True):
933 def set_authenticated(self, authenticated=True):
934 if self.user_id != self.anonymous_user.user_id:
934 if self.user_id != self.anonymous_user.user_id:
935 self.is_authenticated = authenticated
935 self.is_authenticated = authenticated
936
936
937 def get_cookie_store(self):
937 def get_cookie_store(self):
938 return {
938 return {
939 'username': self.username,
939 'username': self.username,
940 'password': md5(self.password),
940 'password': md5(self.password),
941 'user_id': self.user_id,
941 'user_id': self.user_id,
942 'is_authenticated': self.is_authenticated
942 'is_authenticated': self.is_authenticated
943 }
943 }
944
944
945 @classmethod
945 @classmethod
946 def from_cookie_store(cls, cookie_store):
946 def from_cookie_store(cls, cookie_store):
947 """
947 """
948 Creates AuthUser from a cookie store
948 Creates AuthUser from a cookie store
949
949
950 :param cls:
950 :param cls:
951 :param cookie_store:
951 :param cookie_store:
952 """
952 """
953 user_id = cookie_store.get('user_id')
953 user_id = cookie_store.get('user_id')
954 username = cookie_store.get('username')
954 username = cookie_store.get('username')
955 api_key = cookie_store.get('api_key')
955 api_key = cookie_store.get('api_key')
956 return AuthUser(user_id, api_key, username)
956 return AuthUser(user_id, api_key, username)
957
957
958 @classmethod
958 @classmethod
959 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):
960 _set = set()
960 _set = set()
961
961
962 if inherit_from_default:
962 if inherit_from_default:
963 default_ips = UserIpMap.query().filter(
963 default_ips = UserIpMap.query().filter(
964 UserIpMap.user == User.get_default_user(cache=True))
964 UserIpMap.user == User.get_default_user(cache=True))
965 if cache:
965 if cache:
966 default_ips = default_ips.options(FromCache("sql_cache_short",
966 default_ips = default_ips.options(FromCache("sql_cache_short",
967 "get_user_ips_default"))
967 "get_user_ips_default"))
968
968
969 # populate from default user
969 # populate from default user
970 for ip in default_ips:
970 for ip in default_ips:
971 try:
971 try:
972 _set.add(ip.ip_addr)
972 _set.add(ip.ip_addr)
973 except ObjectDeletedError:
973 except ObjectDeletedError:
974 # since we use heavy caching sometimes it happens that
974 # since we use heavy caching sometimes it happens that
975 # we get deleted objects here, we just skip them
975 # we get deleted objects here, we just skip them
976 pass
976 pass
977
977
978 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
978 user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id)
979 if cache:
979 if cache:
980 user_ips = user_ips.options(FromCache("sql_cache_short",
980 user_ips = user_ips.options(FromCache("sql_cache_short",
981 "get_user_ips_%s" % user_id))
981 "get_user_ips_%s" % user_id))
982
982
983 for ip in user_ips:
983 for ip in user_ips:
984 try:
984 try:
985 _set.add(ip.ip_addr)
985 _set.add(ip.ip_addr)
986 except ObjectDeletedError:
986 except ObjectDeletedError:
987 # since we use heavy caching sometimes it happens that we get
987 # since we use heavy caching sometimes it happens that we get
988 # deleted objects here, we just skip them
988 # deleted objects here, we just skip them
989 pass
989 pass
990 return _set or set(['0.0.0.0/0', '::/0'])
990 return _set or set(['0.0.0.0/0', '::/0'])
991
991
992
992
993 def set_available_permissions(config):
993 def set_available_permissions(config):
994 """
994 """
995 This function will propagate pylons globals with all available defined
995 This function will propagate pylons globals with all available defined
996 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
997 permissions since adding a new permission also requires application restart
997 permissions since adding a new permission also requires application restart
998 ie. to decorate new views with the newly created permission
998 ie. to decorate new views with the newly created permission
999
999
1000 :param config: current pylons config instance
1000 :param config: current pylons config instance
1001
1001
1002 """
1002 """
1003 log.info('getting information about all available permissions')
1003 log.info('getting information about all available permissions')
1004 try:
1004 try:
1005 sa = meta.Session
1005 sa = meta.Session
1006 all_perms = sa.query(Permission).all()
1006 all_perms = sa.query(Permission).all()
1007 config['available_permissions'] = [x.permission_name for x in all_perms]
1007 config['available_permissions'] = [x.permission_name for x in all_perms]
1008 except Exception:
1008 except Exception:
1009 log.error(traceback.format_exc())
1009 log.error(traceback.format_exc())
1010 finally:
1010 finally:
1011 meta.Session.remove()
1011 meta.Session.remove()
1012
1012
1013
1013
1014 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):
1015 """
1015 """
1016 Return the current authentication token, creating one if one doesn't
1016 Return the current authentication token, creating one if one doesn't
1017 already exist and the save_if_missing flag is present.
1017 already exist and the save_if_missing flag is present.
1018
1018
1019 :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
1020 :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
1021 :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
1022 session
1022 session
1023 """
1023 """
1024 if not session:
1024 if not session:
1025 from pylons import session
1025 from pylons import session
1026
1026
1027 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:
1028 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
1028 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
1029 session[csrf_token_key] = token
1029 session[csrf_token_key] = token
1030 if hasattr(session, 'save'):
1030 if hasattr(session, 'save'):
1031 session.save()
1031 session.save()
1032 return session.get(csrf_token_key)
1032 return session.get(csrf_token_key)
1033
1033
1034
1034
1035 # CHECK DECORATORS
1035 # CHECK DECORATORS
1036 class CSRFRequired(object):
1036 class CSRFRequired(object):
1037 """
1037 """
1038 Decorator for authenticating a form
1038 Decorator for authenticating a form
1039
1039
1040 This decorator uses an authorization token stored in the client's
1040 This decorator uses an authorization token stored in the client's
1041 session for prevention of certain Cross-site request forgery (CSRF)
1041 session for prevention of certain Cross-site request forgery (CSRF)
1042 attacks (See
1042 attacks (See
1043 http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
1043 http://en.wikipedia.org/wiki/Cross-site_request_forgery for more
1044 information).
1044 information).
1045
1045
1046 For use with the ``webhelpers.secure_form`` helper functions.
1046 For use with the ``webhelpers.secure_form`` helper functions.
1047
1047
1048 """
1048 """
1049 def __init__(self, token=csrf_token_key, header='X-CSRF-Token'):
1049 def __init__(self, token=csrf_token_key, header='X-CSRF-Token'):
1050 self.token = token
1050 self.token = token
1051 self.header = header
1051 self.header = header
1052
1052
1053 def __call__(self, func):
1053 def __call__(self, func):
1054 return get_cython_compat_decorator(self.__wrapper, func)
1054 return get_cython_compat_decorator(self.__wrapper, func)
1055
1055
1056 def _get_csrf(self, _request):
1056 def _get_csrf(self, _request):
1057 return _request.POST.get(self.token, _request.headers.get(self.header))
1057 return _request.POST.get(self.token, _request.headers.get(self.header))
1058
1058
1059 def check_csrf(self, _request, cur_token):
1059 def check_csrf(self, _request, cur_token):
1060 supplied_token = self._get_csrf(_request)
1060 supplied_token = self._get_csrf(_request)
1061 return supplied_token and supplied_token == cur_token
1061 return supplied_token and supplied_token == cur_token
1062
1062
1063 def __wrapper(self, func, *fargs, **fkwargs):
1063 def __wrapper(self, func, *fargs, **fkwargs):
1064 cur_token = get_csrf_token(save_if_missing=False)
1064 cur_token = get_csrf_token(save_if_missing=False)
1065 if self.check_csrf(request, cur_token):
1065 if self.check_csrf(request, cur_token):
1066 if request.POST.get(self.token):
1066 if request.POST.get(self.token):
1067 del request.POST[self.token]
1067 del request.POST[self.token]
1068 return func(*fargs, **fkwargs)
1068 return func(*fargs, **fkwargs)
1069 else:
1069 else:
1070 reason = 'token-missing'
1070 reason = 'token-missing'
1071 supplied_token = self._get_csrf(request)
1071 supplied_token = self._get_csrf(request)
1072 if supplied_token and cur_token != supplied_token:
1072 if supplied_token and cur_token != supplied_token:
1073 reason = 'token-mismatch [%s:%s]' % (cur_token or ''[:6],
1073 reason = 'token-mismatch [%s:%s]' % (cur_token or ''[:6],
1074 supplied_token or ''[:6])
1074 supplied_token or ''[:6])
1075
1075
1076 csrf_message = \
1076 csrf_message = \
1077 ("Cross-site request forgery detected, request denied. See "
1077 ("Cross-site request forgery detected, request denied. See "
1078 "http://en.wikipedia.org/wiki/Cross-site_request_forgery for "
1078 "http://en.wikipedia.org/wiki/Cross-site_request_forgery for "
1079 "more information.")
1079 "more information.")
1080 log.warn('Cross-site request forgery detected, request %r DENIED: %s '
1080 log.warn('Cross-site request forgery detected, request %r DENIED: %s '
1081 'REMOTE_ADDR:%s, HEADERS:%s' % (
1081 'REMOTE_ADDR:%s, HEADERS:%s' % (
1082 request, reason, request.remote_addr, request.headers))
1082 request, reason, request.remote_addr, request.headers))
1083
1083
1084 abort(403, detail=csrf_message)
1084 abort(403, detail=csrf_message)
1085
1085
1086
1086
1087 class LoginRequired(object):
1087 class LoginRequired(object):
1088 """
1088 """
1089 Must be logged in to execute this function else
1089 Must be logged in to execute this function else
1090 redirect to login page
1090 redirect to login page
1091
1091
1092 :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
1093 and grants access based on valid token
1093 and grants access based on valid token
1094 """
1094 """
1095 def __init__(self, auth_token_access=False):
1095 def __init__(self, auth_token_access=False):
1096 self.auth_token_access = auth_token_access
1096 self.auth_token_access = auth_token_access
1097
1097
1098 def __call__(self, func):
1098 def __call__(self, func):
1099 return get_cython_compat_decorator(self.__wrapper, func)
1099 return get_cython_compat_decorator(self.__wrapper, func)
1100
1100
1101 def __wrapper(self, func, *fargs, **fkwargs):
1101 def __wrapper(self, func, *fargs, **fkwargs):
1102 from rhodecode.lib import helpers as h
1102 cls = fargs[0]
1103 cls = fargs[0]
1103 user = cls._rhodecode_user
1104 user = cls._rhodecode_user
1104 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
1105 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
1105 log.debug('Starting login restriction checks for user: %s' % (user,))
1106 log.debug('Starting login restriction checks for user: %s' % (user,))
1106 # check if our IP is allowed
1107 # check if our IP is allowed
1107 ip_access_valid = True
1108 ip_access_valid = True
1108 if not user.ip_allowed:
1109 if not user.ip_allowed:
1109 from rhodecode.lib import helpers as h
1110 h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr,))),
1110 h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr,))),
1111 category='warning')
1111 category='warning')
1112 ip_access_valid = False
1112 ip_access_valid = False
1113
1113
1114 # 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
1115 # defined whitelist of controllers which API access will be enabled
1115 # defined whitelist of controllers which API access will be enabled
1116 _auth_token = request.GET.get(
1116 _auth_token = request.GET.get(
1117 'auth_token', '') or request.GET.get('api_key', '')
1117 'auth_token', '') or request.GET.get('api_key', '')
1118 auth_token_access_valid = allowed_auth_token_access(
1118 auth_token_access_valid = allowed_auth_token_access(
1119 loc, auth_token=_auth_token)
1119 loc, auth_token=_auth_token)
1120
1120
1121 # explicit controller is enabled or API is in our whitelist
1121 # explicit controller is enabled or API is in our whitelist
1122 if self.auth_token_access or auth_token_access_valid:
1122 if self.auth_token_access or auth_token_access_valid:
1123 log.debug('Checking AUTH TOKEN access for %s' % (cls,))
1123 log.debug('Checking AUTH TOKEN access for %s' % (cls,))
1124
1124
1125 if _auth_token and _auth_token in user.auth_tokens:
1125 if _auth_token and _auth_token in user.auth_tokens:
1126 auth_token_access_valid = True
1126 auth_token_access_valid = True
1127 log.debug('AUTH TOKEN ****%s is VALID' % (_auth_token[-4:],))
1127 log.debug('AUTH TOKEN ****%s is VALID' % (_auth_token[-4:],))
1128 else:
1128 else:
1129 auth_token_access_valid = False
1129 auth_token_access_valid = False
1130 if not _auth_token:
1130 if not _auth_token:
1131 log.debug("AUTH TOKEN *NOT* present in request")
1131 log.debug("AUTH TOKEN *NOT* present in request")
1132 else:
1132 else:
1133 log.warning(
1133 log.warning(
1134 "AUTH TOKEN ****%s *NOT* valid" % _auth_token[-4:])
1134 "AUTH TOKEN ****%s *NOT* valid" % _auth_token[-4:])
1135
1135
1136 log.debug('Checking if %s is authenticated @ %s' % (user.username, loc))
1136 log.debug('Checking if %s is authenticated @ %s' % (user.username, loc))
1137 reason = 'RHODECODE_AUTH' if user.is_authenticated \
1137 reason = 'RHODECODE_AUTH' if user.is_authenticated \
1138 else 'AUTH_TOKEN_AUTH'
1138 else 'AUTH_TOKEN_AUTH'
1139
1139
1140 if ip_access_valid and (
1140 if ip_access_valid and (
1141 user.is_authenticated or auth_token_access_valid):
1141 user.is_authenticated or auth_token_access_valid):
1142 log.info(
1142 log.info(
1143 'user %s authenticating with:%s IS authenticated on func %s'
1143 'user %s authenticating with:%s IS authenticated on func %s'
1144 % (user, reason, loc))
1144 % (user, reason, loc))
1145
1145
1146 # update user data to check last activity
1146 # update user data to check last activity
1147 user.update_lastactivity()
1147 user.update_lastactivity()
1148 Session().commit()
1148 Session().commit()
1149 return func(*fargs, **fkwargs)
1149 return func(*fargs, **fkwargs)
1150 else:
1150 else:
1151 log.warning(
1151 log.warning(
1152 'user %s authenticating with:%s NOT authenticated on '
1152 'user %s authenticating with:%s NOT authenticated on '
1153 'func: %s: IP_ACCESS:%s AUTH_TOKEN_ACCESS:%s'
1153 'func: %s: IP_ACCESS:%s AUTH_TOKEN_ACCESS:%s'
1154 % (user, reason, loc, ip_access_valid,
1154 % (user, reason, loc, ip_access_valid,
1155 auth_token_access_valid))
1155 auth_token_access_valid))
1156 # we preserve the get PARAM
1156 # we preserve the get PARAM
1157 came_from = request.path_qs
1157 came_from = request.path_qs
1158
1158
1159 log.debug('redirecting to login page with %s' % (came_from,))
1159 log.debug('redirecting to login page with %s' % (came_from,))
1160 return redirect(
1160 return redirect(
1161 url('login_home', came_from=came_from))
1161 h.route_path('login', _query={'came_from': came_from}))
1162
1162
1163
1163
1164 class NotAnonymous(object):
1164 class NotAnonymous(object):
1165 """
1165 """
1166 Must be logged in to execute this function else
1166 Must be logged in to execute this function else
1167 redirect to login page"""
1167 redirect to login page"""
1168
1168
1169 def __call__(self, func):
1169 def __call__(self, func):
1170 return get_cython_compat_decorator(self.__wrapper, func)
1170 return get_cython_compat_decorator(self.__wrapper, func)
1171
1171
1172 def __wrapper(self, func, *fargs, **fkwargs):
1172 def __wrapper(self, func, *fargs, **fkwargs):
1173 cls = fargs[0]
1173 cls = fargs[0]
1174 self.user = cls._rhodecode_user
1174 self.user = cls._rhodecode_user
1175
1175
1176 log.debug('Checking if user is not anonymous @%s' % cls)
1176 log.debug('Checking if user is not anonymous @%s' % cls)
1177
1177
1178 anonymous = self.user.username == User.DEFAULT_USER
1178 anonymous = self.user.username == User.DEFAULT_USER
1179
1179
1180 if anonymous:
1180 if anonymous:
1181 came_from = request.path_qs
1181 came_from = request.path_qs
1182
1182
1183 import rhodecode.lib.helpers as h
1183 import rhodecode.lib.helpers as h
1184 h.flash(_('You need to be a registered user to '
1184 h.flash(_('You need to be a registered user to '
1185 'perform this action'),
1185 'perform this action'),
1186 category='warning')
1186 category='warning')
1187 return redirect(url('login_home', came_from=came_from))
1187 return redirect(
1188 h.route_path('login', _query={'came_from': came_from}))
1188 else:
1189 else:
1189 return func(*fargs, **fkwargs)
1190 return func(*fargs, **fkwargs)
1190
1191
1191
1192
1192 class XHRRequired(object):
1193 class XHRRequired(object):
1193 def __call__(self, func):
1194 def __call__(self, func):
1194 return get_cython_compat_decorator(self.__wrapper, func)
1195 return get_cython_compat_decorator(self.__wrapper, func)
1195
1196
1196 def __wrapper(self, func, *fargs, **fkwargs):
1197 def __wrapper(self, func, *fargs, **fkwargs):
1197 log.debug('Checking if request is XMLHttpRequest (XHR)')
1198 log.debug('Checking if request is XMLHttpRequest (XHR)')
1198 xhr_message = 'This is not a valid XMLHttpRequest (XHR) request'
1199 xhr_message = 'This is not a valid XMLHttpRequest (XHR) request'
1199 if not request.is_xhr:
1200 if not request.is_xhr:
1200 abort(400, detail=xhr_message)
1201 abort(400, detail=xhr_message)
1201
1202
1202 return func(*fargs, **fkwargs)
1203 return func(*fargs, **fkwargs)
1203
1204
1204
1205
1205 class HasAcceptedRepoType(object):
1206 class HasAcceptedRepoType(object):
1206 """
1207 """
1207 Check if requested repo is within given repo type aliases
1208 Check if requested repo is within given repo type aliases
1208
1209
1209 TODO: anderson: not sure where to put this decorator
1210 TODO: anderson: not sure where to put this decorator
1210 """
1211 """
1211
1212
1212 def __init__(self, *repo_type_list):
1213 def __init__(self, *repo_type_list):
1213 self.repo_type_list = set(repo_type_list)
1214 self.repo_type_list = set(repo_type_list)
1214
1215
1215 def __call__(self, func):
1216 def __call__(self, func):
1216 return get_cython_compat_decorator(self.__wrapper, func)
1217 return get_cython_compat_decorator(self.__wrapper, func)
1217
1218
1218 def __wrapper(self, func, *fargs, **fkwargs):
1219 def __wrapper(self, func, *fargs, **fkwargs):
1219 cls = fargs[0]
1220 cls = fargs[0]
1220 rhodecode_repo = cls.rhodecode_repo
1221 rhodecode_repo = cls.rhodecode_repo
1221
1222
1222 log.debug('%s checking repo type for %s in %s',
1223 log.debug('%s checking repo type for %s in %s',
1223 self.__class__.__name__,
1224 self.__class__.__name__,
1224 rhodecode_repo.alias, self.repo_type_list)
1225 rhodecode_repo.alias, self.repo_type_list)
1225
1226
1226 if rhodecode_repo.alias in self.repo_type_list:
1227 if rhodecode_repo.alias in self.repo_type_list:
1227 return func(*fargs, **fkwargs)
1228 return func(*fargs, **fkwargs)
1228 else:
1229 else:
1229 import rhodecode.lib.helpers as h
1230 import rhodecode.lib.helpers as h
1230 h.flash(h.literal(
1231 h.flash(h.literal(
1231 _('Action not supported for %s.' % rhodecode_repo.alias)),
1232 _('Action not supported for %s.' % rhodecode_repo.alias)),
1232 category='warning')
1233 category='warning')
1233 return redirect(
1234 return redirect(
1234 url('summary_home', repo_name=cls.rhodecode_db_repo.repo_name))
1235 url('summary_home', repo_name=cls.rhodecode_db_repo.repo_name))
1235
1236
1236
1237
1237 class PermsDecorator(object):
1238 class PermsDecorator(object):
1238 """
1239 """
1239 Base class for controller decorators, we extract the current user from
1240 Base class for controller decorators, we extract the current user from
1240 the class itself, which has it stored in base controllers
1241 the class itself, which has it stored in base controllers
1241 """
1242 """
1242
1243
1243 def __init__(self, *required_perms):
1244 def __init__(self, *required_perms):
1244 self.required_perms = set(required_perms)
1245 self.required_perms = set(required_perms)
1245
1246
1246 def __call__(self, func):
1247 def __call__(self, func):
1247 return get_cython_compat_decorator(self.__wrapper, func)
1248 return get_cython_compat_decorator(self.__wrapper, func)
1248
1249
1249 def __wrapper(self, func, *fargs, **fkwargs):
1250 def __wrapper(self, func, *fargs, **fkwargs):
1250 cls = fargs[0]
1251 cls = fargs[0]
1251 _user = cls._rhodecode_user
1252 _user = cls._rhodecode_user
1252
1253
1253 log.debug('checking %s permissions %s for %s %s',
1254 log.debug('checking %s permissions %s for %s %s',
1254 self.__class__.__name__, self.required_perms, cls, _user)
1255 self.__class__.__name__, self.required_perms, cls, _user)
1255
1256
1256 if self.check_permissions(_user):
1257 if self.check_permissions(_user):
1257 log.debug('Permission granted for %s %s', cls, _user)
1258 log.debug('Permission granted for %s %s', cls, _user)
1258 return func(*fargs, **fkwargs)
1259 return func(*fargs, **fkwargs)
1259
1260
1260 else:
1261 else:
1261 log.debug('Permission denied for %s %s', cls, _user)
1262 log.debug('Permission denied for %s %s', cls, _user)
1262 anonymous = _user.username == User.DEFAULT_USER
1263 anonymous = _user.username == User.DEFAULT_USER
1263
1264
1264 if anonymous:
1265 if anonymous:
1265 came_from = request.path_qs
1266 came_from = request.path_qs
1266
1267
1267 import rhodecode.lib.helpers as h
1268 import rhodecode.lib.helpers as h
1268 h.flash(_('You need to be signed in to view this page'),
1269 h.flash(_('You need to be signed in to view this page'),
1269 category='warning')
1270 category='warning')
1270 return redirect(url('login_home', came_from=came_from))
1271 return redirect(
1272 h.route_path('login', _query={'came_from': came_from}))
1271
1273
1272 else:
1274 else:
1273 # redirect with forbidden ret code
1275 # redirect with forbidden ret code
1274 return abort(403)
1276 return abort(403)
1275
1277
1276 def check_permissions(self, user):
1278 def check_permissions(self, user):
1277 """Dummy function for overriding"""
1279 """Dummy function for overriding"""
1278 raise NotImplementedError(
1280 raise NotImplementedError(
1279 'You have to write this function in child class')
1281 'You have to write this function in child class')
1280
1282
1281
1283
1282 class HasPermissionAllDecorator(PermsDecorator):
1284 class HasPermissionAllDecorator(PermsDecorator):
1283 """
1285 """
1284 Checks for access permission for all given predicates. All of them
1286 Checks for access permission for all given predicates. All of them
1285 have to be meet in order to fulfill the request
1287 have to be meet in order to fulfill the request
1286 """
1288 """
1287
1289
1288 def check_permissions(self, user):
1290 def check_permissions(self, user):
1289 perms = user.permissions_with_scope({})
1291 perms = user.permissions_with_scope({})
1290 if self.required_perms.issubset(perms['global']):
1292 if self.required_perms.issubset(perms['global']):
1291 return True
1293 return True
1292 return False
1294 return False
1293
1295
1294
1296
1295 class HasPermissionAnyDecorator(PermsDecorator):
1297 class HasPermissionAnyDecorator(PermsDecorator):
1296 """
1298 """
1297 Checks for access permission for any of given predicates. In order to
1299 Checks for access permission for any of given predicates. In order to
1298 fulfill the request any of predicates must be meet
1300 fulfill the request any of predicates must be meet
1299 """
1301 """
1300
1302
1301 def check_permissions(self, user):
1303 def check_permissions(self, user):
1302 perms = user.permissions_with_scope({})
1304 perms = user.permissions_with_scope({})
1303 if self.required_perms.intersection(perms['global']):
1305 if self.required_perms.intersection(perms['global']):
1304 return True
1306 return True
1305 return False
1307 return False
1306
1308
1307
1309
1308 class HasRepoPermissionAllDecorator(PermsDecorator):
1310 class HasRepoPermissionAllDecorator(PermsDecorator):
1309 """
1311 """
1310 Checks for access permission for all given predicates for specific
1312 Checks for access permission for all given predicates for specific
1311 repository. All of them have to be meet in order to fulfill the request
1313 repository. All of them have to be meet in order to fulfill the request
1312 """
1314 """
1313
1315
1314 def check_permissions(self, user):
1316 def check_permissions(self, user):
1315 perms = user.permissions
1317 perms = user.permissions
1316 repo_name = get_repo_slug(request)
1318 repo_name = get_repo_slug(request)
1317 try:
1319 try:
1318 user_perms = set([perms['repositories'][repo_name]])
1320 user_perms = set([perms['repositories'][repo_name]])
1319 except KeyError:
1321 except KeyError:
1320 return False
1322 return False
1321 if self.required_perms.issubset(user_perms):
1323 if self.required_perms.issubset(user_perms):
1322 return True
1324 return True
1323 return False
1325 return False
1324
1326
1325
1327
1326 class HasRepoPermissionAnyDecorator(PermsDecorator):
1328 class HasRepoPermissionAnyDecorator(PermsDecorator):
1327 """
1329 """
1328 Checks for access permission for any of given predicates for specific
1330 Checks for access permission for any of given predicates for specific
1329 repository. In order to fulfill the request any of predicates must be meet
1331 repository. In order to fulfill the request any of predicates must be meet
1330 """
1332 """
1331
1333
1332 def check_permissions(self, user):
1334 def check_permissions(self, user):
1333 perms = user.permissions
1335 perms = user.permissions
1334 repo_name = get_repo_slug(request)
1336 repo_name = get_repo_slug(request)
1335 try:
1337 try:
1336 user_perms = set([perms['repositories'][repo_name]])
1338 user_perms = set([perms['repositories'][repo_name]])
1337 except KeyError:
1339 except KeyError:
1338 return False
1340 return False
1339
1341
1340 if self.required_perms.intersection(user_perms):
1342 if self.required_perms.intersection(user_perms):
1341 return True
1343 return True
1342 return False
1344 return False
1343
1345
1344
1346
1345 class HasRepoGroupPermissionAllDecorator(PermsDecorator):
1347 class HasRepoGroupPermissionAllDecorator(PermsDecorator):
1346 """
1348 """
1347 Checks for access permission for all given predicates for specific
1349 Checks for access permission for all given predicates for specific
1348 repository group. All of them have to be meet in order to
1350 repository group. All of them have to be meet in order to
1349 fulfill the request
1351 fulfill the request
1350 """
1352 """
1351
1353
1352 def check_permissions(self, user):
1354 def check_permissions(self, user):
1353 perms = user.permissions
1355 perms = user.permissions
1354 group_name = get_repo_group_slug(request)
1356 group_name = get_repo_group_slug(request)
1355 try:
1357 try:
1356 user_perms = set([perms['repositories_groups'][group_name]])
1358 user_perms = set([perms['repositories_groups'][group_name]])
1357 except KeyError:
1359 except KeyError:
1358 return False
1360 return False
1359
1361
1360 if self.required_perms.issubset(user_perms):
1362 if self.required_perms.issubset(user_perms):
1361 return True
1363 return True
1362 return False
1364 return False
1363
1365
1364
1366
1365 class HasRepoGroupPermissionAnyDecorator(PermsDecorator):
1367 class HasRepoGroupPermissionAnyDecorator(PermsDecorator):
1366 """
1368 """
1367 Checks for access permission for any of given predicates for specific
1369 Checks for access permission for any of given predicates for specific
1368 repository group. In order to fulfill the request any
1370 repository group. In order to fulfill the request any
1369 of predicates must be met
1371 of predicates must be met
1370 """
1372 """
1371
1373
1372 def check_permissions(self, user):
1374 def check_permissions(self, user):
1373 perms = user.permissions
1375 perms = user.permissions
1374 group_name = get_repo_group_slug(request)
1376 group_name = get_repo_group_slug(request)
1375 try:
1377 try:
1376 user_perms = set([perms['repositories_groups'][group_name]])
1378 user_perms = set([perms['repositories_groups'][group_name]])
1377 except KeyError:
1379 except KeyError:
1378 return False
1380 return False
1379
1381
1380 if self.required_perms.intersection(user_perms):
1382 if self.required_perms.intersection(user_perms):
1381 return True
1383 return True
1382 return False
1384 return False
1383
1385
1384
1386
1385 class HasUserGroupPermissionAllDecorator(PermsDecorator):
1387 class HasUserGroupPermissionAllDecorator(PermsDecorator):
1386 """
1388 """
1387 Checks for access permission for all given predicates for specific
1389 Checks for access permission for all given predicates for specific
1388 user group. All of them have to be meet in order to fulfill the request
1390 user group. All of them have to be meet in order to fulfill the request
1389 """
1391 """
1390
1392
1391 def check_permissions(self, user):
1393 def check_permissions(self, user):
1392 perms = user.permissions
1394 perms = user.permissions
1393 group_name = get_user_group_slug(request)
1395 group_name = get_user_group_slug(request)
1394 try:
1396 try:
1395 user_perms = set([perms['user_groups'][group_name]])
1397 user_perms = set([perms['user_groups'][group_name]])
1396 except KeyError:
1398 except KeyError:
1397 return False
1399 return False
1398
1400
1399 if self.required_perms.issubset(user_perms):
1401 if self.required_perms.issubset(user_perms):
1400 return True
1402 return True
1401 return False
1403 return False
1402
1404
1403
1405
1404 class HasUserGroupPermissionAnyDecorator(PermsDecorator):
1406 class HasUserGroupPermissionAnyDecorator(PermsDecorator):
1405 """
1407 """
1406 Checks for access permission for any of given predicates for specific
1408 Checks for access permission for any of given predicates for specific
1407 user group. In order to fulfill the request any of predicates must be meet
1409 user group. In order to fulfill the request any of predicates must be meet
1408 """
1410 """
1409
1411
1410 def check_permissions(self, user):
1412 def check_permissions(self, user):
1411 perms = user.permissions
1413 perms = user.permissions
1412 group_name = get_user_group_slug(request)
1414 group_name = get_user_group_slug(request)
1413 try:
1415 try:
1414 user_perms = set([perms['user_groups'][group_name]])
1416 user_perms = set([perms['user_groups'][group_name]])
1415 except KeyError:
1417 except KeyError:
1416 return False
1418 return False
1417
1419
1418 if self.required_perms.intersection(user_perms):
1420 if self.required_perms.intersection(user_perms):
1419 return True
1421 return True
1420 return False
1422 return False
1421
1423
1422
1424
1423 # CHECK FUNCTIONS
1425 # CHECK FUNCTIONS
1424 class PermsFunction(object):
1426 class PermsFunction(object):
1425 """Base function for other check functions"""
1427 """Base function for other check functions"""
1426
1428
1427 def __init__(self, *perms):
1429 def __init__(self, *perms):
1428 self.required_perms = set(perms)
1430 self.required_perms = set(perms)
1429 self.repo_name = None
1431 self.repo_name = None
1430 self.repo_group_name = None
1432 self.repo_group_name = None
1431 self.user_group_name = None
1433 self.user_group_name = None
1432
1434
1433 def __bool__(self):
1435 def __bool__(self):
1434 frame = inspect.currentframe()
1436 frame = inspect.currentframe()
1435 stack_trace = traceback.format_stack(frame)
1437 stack_trace = traceback.format_stack(frame)
1436 log.error('Checking bool value on a class instance of perm '
1438 log.error('Checking bool value on a class instance of perm '
1437 'function is not allowed: %s' % ''.join(stack_trace))
1439 'function is not allowed: %s' % ''.join(stack_trace))
1438 # rather than throwing errors, here we always return False so if by
1440 # rather than throwing errors, here we always return False so if by
1439 # accident someone checks truth for just an instance it will always end
1441 # accident someone checks truth for just an instance it will always end
1440 # up in returning False
1442 # up in returning False
1441 return False
1443 return False
1442 __nonzero__ = __bool__
1444 __nonzero__ = __bool__
1443
1445
1444 def __call__(self, check_location='', user=None):
1446 def __call__(self, check_location='', user=None):
1445 if not user:
1447 if not user:
1446 log.debug('Using user attribute from global request')
1448 log.debug('Using user attribute from global request')
1447 # TODO: remove this someday,put as user as attribute here
1449 # TODO: remove this someday,put as user as attribute here
1448 user = request.user
1450 user = request.user
1449
1451
1450 # init auth user if not already given
1452 # init auth user if not already given
1451 if not isinstance(user, AuthUser):
1453 if not isinstance(user, AuthUser):
1452 log.debug('Wrapping user %s into AuthUser', user)
1454 log.debug('Wrapping user %s into AuthUser', user)
1453 user = AuthUser(user.user_id)
1455 user = AuthUser(user.user_id)
1454
1456
1455 cls_name = self.__class__.__name__
1457 cls_name = self.__class__.__name__
1456 check_scope = self._get_check_scope(cls_name)
1458 check_scope = self._get_check_scope(cls_name)
1457 check_location = check_location or 'unspecified location'
1459 check_location = check_location or 'unspecified location'
1458
1460
1459 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
1461 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
1460 self.required_perms, user, check_scope, check_location)
1462 self.required_perms, user, check_scope, check_location)
1461 if not user:
1463 if not user:
1462 log.warning('Empty user given for permission check')
1464 log.warning('Empty user given for permission check')
1463 return False
1465 return False
1464
1466
1465 if self.check_permissions(user):
1467 if self.check_permissions(user):
1466 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1468 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1467 check_scope, user, check_location)
1469 check_scope, user, check_location)
1468 return True
1470 return True
1469
1471
1470 else:
1472 else:
1471 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1473 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1472 check_scope, user, check_location)
1474 check_scope, user, check_location)
1473 return False
1475 return False
1474
1476
1475 def _get_check_scope(self, cls_name):
1477 def _get_check_scope(self, cls_name):
1476 return {
1478 return {
1477 'HasPermissionAll': 'GLOBAL',
1479 'HasPermissionAll': 'GLOBAL',
1478 'HasPermissionAny': 'GLOBAL',
1480 'HasPermissionAny': 'GLOBAL',
1479 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
1481 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
1480 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
1482 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
1481 'HasRepoGroupPermissionAll': 'repo_group:%s' % self.repo_group_name,
1483 'HasRepoGroupPermissionAll': 'repo_group:%s' % self.repo_group_name,
1482 'HasRepoGroupPermissionAny': 'repo_group:%s' % self.repo_group_name,
1484 'HasRepoGroupPermissionAny': 'repo_group:%s' % self.repo_group_name,
1483 'HasUserGroupPermissionAll': 'user_group:%s' % self.user_group_name,
1485 'HasUserGroupPermissionAll': 'user_group:%s' % self.user_group_name,
1484 'HasUserGroupPermissionAny': 'user_group:%s' % self.user_group_name,
1486 'HasUserGroupPermissionAny': 'user_group:%s' % self.user_group_name,
1485 }.get(cls_name, '?:%s' % cls_name)
1487 }.get(cls_name, '?:%s' % cls_name)
1486
1488
1487 def check_permissions(self, user):
1489 def check_permissions(self, user):
1488 """Dummy function for overriding"""
1490 """Dummy function for overriding"""
1489 raise Exception('You have to write this function in child class')
1491 raise Exception('You have to write this function in child class')
1490
1492
1491
1493
1492 class HasPermissionAll(PermsFunction):
1494 class HasPermissionAll(PermsFunction):
1493 def check_permissions(self, user):
1495 def check_permissions(self, user):
1494 perms = user.permissions_with_scope({})
1496 perms = user.permissions_with_scope({})
1495 if self.required_perms.issubset(perms.get('global')):
1497 if self.required_perms.issubset(perms.get('global')):
1496 return True
1498 return True
1497 return False
1499 return False
1498
1500
1499
1501
1500 class HasPermissionAny(PermsFunction):
1502 class HasPermissionAny(PermsFunction):
1501 def check_permissions(self, user):
1503 def check_permissions(self, user):
1502 perms = user.permissions_with_scope({})
1504 perms = user.permissions_with_scope({})
1503 if self.required_perms.intersection(perms.get('global')):
1505 if self.required_perms.intersection(perms.get('global')):
1504 return True
1506 return True
1505 return False
1507 return False
1506
1508
1507
1509
1508 class HasRepoPermissionAll(PermsFunction):
1510 class HasRepoPermissionAll(PermsFunction):
1509 def __call__(self, repo_name=None, check_location='', user=None):
1511 def __call__(self, repo_name=None, check_location='', user=None):
1510 self.repo_name = repo_name
1512 self.repo_name = repo_name
1511 return super(HasRepoPermissionAll, self).__call__(check_location, user)
1513 return super(HasRepoPermissionAll, self).__call__(check_location, user)
1512
1514
1513 def check_permissions(self, user):
1515 def check_permissions(self, user):
1514 if not self.repo_name:
1516 if not self.repo_name:
1515 self.repo_name = get_repo_slug(request)
1517 self.repo_name = get_repo_slug(request)
1516
1518
1517 perms = user.permissions
1519 perms = user.permissions
1518 try:
1520 try:
1519 user_perms = set([perms['repositories'][self.repo_name]])
1521 user_perms = set([perms['repositories'][self.repo_name]])
1520 except KeyError:
1522 except KeyError:
1521 return False
1523 return False
1522 if self.required_perms.issubset(user_perms):
1524 if self.required_perms.issubset(user_perms):
1523 return True
1525 return True
1524 return False
1526 return False
1525
1527
1526
1528
1527 class HasRepoPermissionAny(PermsFunction):
1529 class HasRepoPermissionAny(PermsFunction):
1528 def __call__(self, repo_name=None, check_location='', user=None):
1530 def __call__(self, repo_name=None, check_location='', user=None):
1529 self.repo_name = repo_name
1531 self.repo_name = repo_name
1530 return super(HasRepoPermissionAny, self).__call__(check_location, user)
1532 return super(HasRepoPermissionAny, self).__call__(check_location, user)
1531
1533
1532 def check_permissions(self, user):
1534 def check_permissions(self, user):
1533 if not self.repo_name:
1535 if not self.repo_name:
1534 self.repo_name = get_repo_slug(request)
1536 self.repo_name = get_repo_slug(request)
1535
1537
1536 perms = user.permissions
1538 perms = user.permissions
1537 try:
1539 try:
1538 user_perms = set([perms['repositories'][self.repo_name]])
1540 user_perms = set([perms['repositories'][self.repo_name]])
1539 except KeyError:
1541 except KeyError:
1540 return False
1542 return False
1541 if self.required_perms.intersection(user_perms):
1543 if self.required_perms.intersection(user_perms):
1542 return True
1544 return True
1543 return False
1545 return False
1544
1546
1545
1547
1546 class HasRepoGroupPermissionAny(PermsFunction):
1548 class HasRepoGroupPermissionAny(PermsFunction):
1547 def __call__(self, group_name=None, check_location='', user=None):
1549 def __call__(self, group_name=None, check_location='', user=None):
1548 self.repo_group_name = group_name
1550 self.repo_group_name = group_name
1549 return super(HasRepoGroupPermissionAny, self).__call__(
1551 return super(HasRepoGroupPermissionAny, self).__call__(
1550 check_location, user)
1552 check_location, user)
1551
1553
1552 def check_permissions(self, user):
1554 def check_permissions(self, user):
1553 perms = user.permissions
1555 perms = user.permissions
1554 try:
1556 try:
1555 user_perms = set(
1557 user_perms = set(
1556 [perms['repositories_groups'][self.repo_group_name]])
1558 [perms['repositories_groups'][self.repo_group_name]])
1557 except KeyError:
1559 except KeyError:
1558 return False
1560 return False
1559 if self.required_perms.intersection(user_perms):
1561 if self.required_perms.intersection(user_perms):
1560 return True
1562 return True
1561 return False
1563 return False
1562
1564
1563
1565
1564 class HasRepoGroupPermissionAll(PermsFunction):
1566 class HasRepoGroupPermissionAll(PermsFunction):
1565 def __call__(self, group_name=None, check_location='', user=None):
1567 def __call__(self, group_name=None, check_location='', user=None):
1566 self.repo_group_name = group_name
1568 self.repo_group_name = group_name
1567 return super(HasRepoGroupPermissionAll, self).__call__(
1569 return super(HasRepoGroupPermissionAll, self).__call__(
1568 check_location, user)
1570 check_location, user)
1569
1571
1570 def check_permissions(self, user):
1572 def check_permissions(self, user):
1571 perms = user.permissions
1573 perms = user.permissions
1572 try:
1574 try:
1573 user_perms = set(
1575 user_perms = set(
1574 [perms['repositories_groups'][self.repo_group_name]])
1576 [perms['repositories_groups'][self.repo_group_name]])
1575 except KeyError:
1577 except KeyError:
1576 return False
1578 return False
1577 if self.required_perms.issubset(user_perms):
1579 if self.required_perms.issubset(user_perms):
1578 return True
1580 return True
1579 return False
1581 return False
1580
1582
1581
1583
1582 class HasUserGroupPermissionAny(PermsFunction):
1584 class HasUserGroupPermissionAny(PermsFunction):
1583 def __call__(self, user_group_name=None, check_location='', user=None):
1585 def __call__(self, user_group_name=None, check_location='', user=None):
1584 self.user_group_name = user_group_name
1586 self.user_group_name = user_group_name
1585 return super(HasUserGroupPermissionAny, self).__call__(
1587 return super(HasUserGroupPermissionAny, self).__call__(
1586 check_location, user)
1588 check_location, user)
1587
1589
1588 def check_permissions(self, user):
1590 def check_permissions(self, user):
1589 perms = user.permissions
1591 perms = user.permissions
1590 try:
1592 try:
1591 user_perms = set([perms['user_groups'][self.user_group_name]])
1593 user_perms = set([perms['user_groups'][self.user_group_name]])
1592 except KeyError:
1594 except KeyError:
1593 return False
1595 return False
1594 if self.required_perms.intersection(user_perms):
1596 if self.required_perms.intersection(user_perms):
1595 return True
1597 return True
1596 return False
1598 return False
1597
1599
1598
1600
1599 class HasUserGroupPermissionAll(PermsFunction):
1601 class HasUserGroupPermissionAll(PermsFunction):
1600 def __call__(self, user_group_name=None, check_location='', user=None):
1602 def __call__(self, user_group_name=None, check_location='', user=None):
1601 self.user_group_name = user_group_name
1603 self.user_group_name = user_group_name
1602 return super(HasUserGroupPermissionAll, self).__call__(
1604 return super(HasUserGroupPermissionAll, self).__call__(
1603 check_location, user)
1605 check_location, user)
1604
1606
1605 def check_permissions(self, user):
1607 def check_permissions(self, user):
1606 perms = user.permissions
1608 perms = user.permissions
1607 try:
1609 try:
1608 user_perms = set([perms['user_groups'][self.user_group_name]])
1610 user_perms = set([perms['user_groups'][self.user_group_name]])
1609 except KeyError:
1611 except KeyError:
1610 return False
1612 return False
1611 if self.required_perms.issubset(user_perms):
1613 if self.required_perms.issubset(user_perms):
1612 return True
1614 return True
1613 return False
1615 return False
1614
1616
1615
1617
1616 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
1618 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
1617 class HasPermissionAnyMiddleware(object):
1619 class HasPermissionAnyMiddleware(object):
1618 def __init__(self, *perms):
1620 def __init__(self, *perms):
1619 self.required_perms = set(perms)
1621 self.required_perms = set(perms)
1620
1622
1621 def __call__(self, user, repo_name):
1623 def __call__(self, user, repo_name):
1622 # repo_name MUST be unicode, since we handle keys in permission
1624 # repo_name MUST be unicode, since we handle keys in permission
1623 # dict by unicode
1625 # dict by unicode
1624 repo_name = safe_unicode(repo_name)
1626 repo_name = safe_unicode(repo_name)
1625 user = AuthUser(user.user_id)
1627 user = AuthUser(user.user_id)
1626 log.debug(
1628 log.debug(
1627 'Checking VCS protocol permissions %s for user:%s repo:`%s`',
1629 'Checking VCS protocol permissions %s for user:%s repo:`%s`',
1628 self.required_perms, user, repo_name)
1630 self.required_perms, user, repo_name)
1629
1631
1630 if self.check_permissions(user, repo_name):
1632 if self.check_permissions(user, repo_name):
1631 log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s',
1633 log.debug('Permission to repo:`%s` GRANTED for user:%s @ %s',
1632 repo_name, user, 'PermissionMiddleware')
1634 repo_name, user, 'PermissionMiddleware')
1633 return True
1635 return True
1634
1636
1635 else:
1637 else:
1636 log.debug('Permission to repo:`%s` DENIED for user:%s @ %s',
1638 log.debug('Permission to repo:`%s` DENIED for user:%s @ %s',
1637 repo_name, user, 'PermissionMiddleware')
1639 repo_name, user, 'PermissionMiddleware')
1638 return False
1640 return False
1639
1641
1640 def check_permissions(self, user, repo_name):
1642 def check_permissions(self, user, repo_name):
1641 perms = user.permissions_with_scope({'repo_name': repo_name})
1643 perms = user.permissions_with_scope({'repo_name': repo_name})
1642
1644
1643 try:
1645 try:
1644 user_perms = set([perms['repositories'][repo_name]])
1646 user_perms = set([perms['repositories'][repo_name]])
1645 except Exception:
1647 except Exception:
1646 log.exception('Error while accessing user permissions')
1648 log.exception('Error while accessing user permissions')
1647 return False
1649 return False
1648
1650
1649 if self.required_perms.intersection(user_perms):
1651 if self.required_perms.intersection(user_perms):
1650 return True
1652 return True
1651 return False
1653 return False
1652
1654
1653
1655
1654 # SPECIAL VERSION TO HANDLE API AUTH
1656 # SPECIAL VERSION TO HANDLE API AUTH
1655 class _BaseApiPerm(object):
1657 class _BaseApiPerm(object):
1656 def __init__(self, *perms):
1658 def __init__(self, *perms):
1657 self.required_perms = set(perms)
1659 self.required_perms = set(perms)
1658
1660
1659 def __call__(self, check_location=None, user=None, repo_name=None,
1661 def __call__(self, check_location=None, user=None, repo_name=None,
1660 group_name=None, user_group_name=None):
1662 group_name=None, user_group_name=None):
1661 cls_name = self.__class__.__name__
1663 cls_name = self.__class__.__name__
1662 check_scope = 'global:%s' % (self.required_perms,)
1664 check_scope = 'global:%s' % (self.required_perms,)
1663 if repo_name:
1665 if repo_name:
1664 check_scope += ', repo_name:%s' % (repo_name,)
1666 check_scope += ', repo_name:%s' % (repo_name,)
1665
1667
1666 if group_name:
1668 if group_name:
1667 check_scope += ', repo_group_name:%s' % (group_name,)
1669 check_scope += ', repo_group_name:%s' % (group_name,)
1668
1670
1669 if user_group_name:
1671 if user_group_name:
1670 check_scope += ', user_group_name:%s' % (user_group_name,)
1672 check_scope += ', user_group_name:%s' % (user_group_name,)
1671
1673
1672 log.debug(
1674 log.debug(
1673 'checking cls:%s %s %s @ %s'
1675 'checking cls:%s %s %s @ %s'
1674 % (cls_name, self.required_perms, check_scope, check_location))
1676 % (cls_name, self.required_perms, check_scope, check_location))
1675 if not user:
1677 if not user:
1676 log.debug('Empty User passed into arguments')
1678 log.debug('Empty User passed into arguments')
1677 return False
1679 return False
1678
1680
1679 # process user
1681 # process user
1680 if not isinstance(user, AuthUser):
1682 if not isinstance(user, AuthUser):
1681 user = AuthUser(user.user_id)
1683 user = AuthUser(user.user_id)
1682 if not check_location:
1684 if not check_location:
1683 check_location = 'unspecified'
1685 check_location = 'unspecified'
1684 if self.check_permissions(user.permissions, repo_name, group_name,
1686 if self.check_permissions(user.permissions, repo_name, group_name,
1685 user_group_name):
1687 user_group_name):
1686 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1688 log.debug('Permission to repo:`%s` GRANTED for user:`%s` @ %s',
1687 check_scope, user, check_location)
1689 check_scope, user, check_location)
1688 return True
1690 return True
1689
1691
1690 else:
1692 else:
1691 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1693 log.debug('Permission to repo:`%s` DENIED for user:`%s` @ %s',
1692 check_scope, user, check_location)
1694 check_scope, user, check_location)
1693 return False
1695 return False
1694
1696
1695 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1697 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1696 user_group_name=None):
1698 user_group_name=None):
1697 """
1699 """
1698 implement in child class should return True if permissions are ok,
1700 implement in child class should return True if permissions are ok,
1699 False otherwise
1701 False otherwise
1700
1702
1701 :param perm_defs: dict with permission definitions
1703 :param perm_defs: dict with permission definitions
1702 :param repo_name: repo name
1704 :param repo_name: repo name
1703 """
1705 """
1704 raise NotImplementedError()
1706 raise NotImplementedError()
1705
1707
1706
1708
1707 class HasPermissionAllApi(_BaseApiPerm):
1709 class HasPermissionAllApi(_BaseApiPerm):
1708 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1710 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1709 user_group_name=None):
1711 user_group_name=None):
1710 if self.required_perms.issubset(perm_defs.get('global')):
1712 if self.required_perms.issubset(perm_defs.get('global')):
1711 return True
1713 return True
1712 return False
1714 return False
1713
1715
1714
1716
1715 class HasPermissionAnyApi(_BaseApiPerm):
1717 class HasPermissionAnyApi(_BaseApiPerm):
1716 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1718 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1717 user_group_name=None):
1719 user_group_name=None):
1718 if self.required_perms.intersection(perm_defs.get('global')):
1720 if self.required_perms.intersection(perm_defs.get('global')):
1719 return True
1721 return True
1720 return False
1722 return False
1721
1723
1722
1724
1723 class HasRepoPermissionAllApi(_BaseApiPerm):
1725 class HasRepoPermissionAllApi(_BaseApiPerm):
1724 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1726 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1725 user_group_name=None):
1727 user_group_name=None):
1726 try:
1728 try:
1727 _user_perms = set([perm_defs['repositories'][repo_name]])
1729 _user_perms = set([perm_defs['repositories'][repo_name]])
1728 except KeyError:
1730 except KeyError:
1729 log.warning(traceback.format_exc())
1731 log.warning(traceback.format_exc())
1730 return False
1732 return False
1731 if self.required_perms.issubset(_user_perms):
1733 if self.required_perms.issubset(_user_perms):
1732 return True
1734 return True
1733 return False
1735 return False
1734
1736
1735
1737
1736 class HasRepoPermissionAnyApi(_BaseApiPerm):
1738 class HasRepoPermissionAnyApi(_BaseApiPerm):
1737 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1739 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1738 user_group_name=None):
1740 user_group_name=None):
1739 try:
1741 try:
1740 _user_perms = set([perm_defs['repositories'][repo_name]])
1742 _user_perms = set([perm_defs['repositories'][repo_name]])
1741 except KeyError:
1743 except KeyError:
1742 log.warning(traceback.format_exc())
1744 log.warning(traceback.format_exc())
1743 return False
1745 return False
1744 if self.required_perms.intersection(_user_perms):
1746 if self.required_perms.intersection(_user_perms):
1745 return True
1747 return True
1746 return False
1748 return False
1747
1749
1748
1750
1749 class HasRepoGroupPermissionAnyApi(_BaseApiPerm):
1751 class HasRepoGroupPermissionAnyApi(_BaseApiPerm):
1750 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1752 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1751 user_group_name=None):
1753 user_group_name=None):
1752 try:
1754 try:
1753 _user_perms = set([perm_defs['repositories_groups'][group_name]])
1755 _user_perms = set([perm_defs['repositories_groups'][group_name]])
1754 except KeyError:
1756 except KeyError:
1755 log.warning(traceback.format_exc())
1757 log.warning(traceback.format_exc())
1756 return False
1758 return False
1757 if self.required_perms.intersection(_user_perms):
1759 if self.required_perms.intersection(_user_perms):
1758 return True
1760 return True
1759 return False
1761 return False
1760
1762
1761
1763
1762 class HasRepoGroupPermissionAllApi(_BaseApiPerm):
1764 class HasRepoGroupPermissionAllApi(_BaseApiPerm):
1763 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1765 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1764 user_group_name=None):
1766 user_group_name=None):
1765 try:
1767 try:
1766 _user_perms = set([perm_defs['repositories_groups'][group_name]])
1768 _user_perms = set([perm_defs['repositories_groups'][group_name]])
1767 except KeyError:
1769 except KeyError:
1768 log.warning(traceback.format_exc())
1770 log.warning(traceback.format_exc())
1769 return False
1771 return False
1770 if self.required_perms.issubset(_user_perms):
1772 if self.required_perms.issubset(_user_perms):
1771 return True
1773 return True
1772 return False
1774 return False
1773
1775
1774
1776
1775 class HasUserGroupPermissionAnyApi(_BaseApiPerm):
1777 class HasUserGroupPermissionAnyApi(_BaseApiPerm):
1776 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1778 def check_permissions(self, perm_defs, repo_name=None, group_name=None,
1777 user_group_name=None):
1779 user_group_name=None):
1778 try:
1780 try:
1779 _user_perms = set([perm_defs['user_groups'][user_group_name]])
1781 _user_perms = set([perm_defs['user_groups'][user_group_name]])
1780 except KeyError:
1782 except KeyError:
1781 log.warning(traceback.format_exc())
1783 log.warning(traceback.format_exc())
1782 return False
1784 return False
1783 if self.required_perms.intersection(_user_perms):
1785 if self.required_perms.intersection(_user_perms):
1784 return True
1786 return True
1785 return False
1787 return False
1786
1788
1787
1789
1788 def check_ip_access(source_ip, allowed_ips=None):
1790 def check_ip_access(source_ip, allowed_ips=None):
1789 """
1791 """
1790 Checks if source_ip is a subnet of any of allowed_ips.
1792 Checks if source_ip is a subnet of any of allowed_ips.
1791
1793
1792 :param source_ip:
1794 :param source_ip:
1793 :param allowed_ips: list of allowed ips together with mask
1795 :param allowed_ips: list of allowed ips together with mask
1794 """
1796 """
1795 log.debug('checking if ip:%s is subnet of %s' % (source_ip, allowed_ips))
1797 log.debug('checking if ip:%s is subnet of %s' % (source_ip, allowed_ips))
1796 source_ip_address = ipaddress.ip_address(source_ip)
1798 source_ip_address = ipaddress.ip_address(source_ip)
1797 if isinstance(allowed_ips, (tuple, list, set)):
1799 if isinstance(allowed_ips, (tuple, list, set)):
1798 for ip in allowed_ips:
1800 for ip in allowed_ips:
1799 try:
1801 try:
1800 network_address = ipaddress.ip_network(ip, strict=False)
1802 network_address = ipaddress.ip_network(ip, strict=False)
1801 if source_ip_address in network_address:
1803 if source_ip_address in network_address:
1802 log.debug('IP %s is network %s' %
1804 log.debug('IP %s is network %s' %
1803 (source_ip_address, network_address))
1805 (source_ip_address, network_address))
1804 return True
1806 return True
1805 # for any case we cannot determine the IP, don't crash just
1807 # for any case we cannot determine the IP, don't crash just
1806 # skip it and log as error, we want to say forbidden still when
1808 # skip it and log as error, we want to say forbidden still when
1807 # sending bad IP
1809 # sending bad IP
1808 except Exception:
1810 except Exception:
1809 log.error(traceback.format_exc())
1811 log.error(traceback.format_exc())
1810 continue
1812 continue
1811 return False
1813 return False
1812
1814
1813
1815
1814 def get_cython_compat_decorator(wrapper, func):
1816 def get_cython_compat_decorator(wrapper, func):
1815 """
1817 """
1816 Creates a cython compatible decorator. The previously used
1818 Creates a cython compatible decorator. The previously used
1817 decorator.decorator() function seems to be incompatible with cython.
1819 decorator.decorator() function seems to be incompatible with cython.
1818
1820
1819 :param wrapper: __wrapper method of the decorator class
1821 :param wrapper: __wrapper method of the decorator class
1820 :param func: decorated function
1822 :param func: decorated function
1821 """
1823 """
1822 @wraps(func)
1824 @wraps(func)
1823 def local_wrapper(*args, **kwds):
1825 def local_wrapper(*args, **kwds):
1824 return wrapper(func, *args, **kwds)
1826 return wrapper(func, *args, **kwds)
1825 local_wrapper.__wrapped__ = func
1827 local_wrapper.__wrapped__ = func
1826 return local_wrapper
1828 return local_wrapper
General Comments 0
You need to be logged in to leave comments. Login now