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