##// END OF EJS Templates
more detailed logging on auth system...
marcink -
r2125:097327aa beta
parent child Browse files
Show More
@@ -1,25 +1,30 b''
1 .. _debugging:
1 .. _debugging:
2
2
3 ===================
3 ===================
4 DEBUGGING RHODECODE
4 Debugging RhodeCode
5 ===================
5 ===================
6
6
7 If you encountered problems with RhodeCode here are some instructions how to
7 If you encountered problems with RhodeCode here are some instructions how to
8 possibly debug them.
8 possibly debug them.
9
9
10 ** First make sure you're using the latest version available.**
10 ** First make sure you're using the latest version available.**
11
11
12 enable detailed debug
12 enable detailed debug
13 ---------------------
13 ---------------------
14
14
15 RhodeCode uses standard python logging modules to log it's output.
15 RhodeCode uses standard python logging modules to log it's output.
16 By default only loggers with INFO level are displayed. To enable full output
16 By default only loggers with INFO level are displayed. To enable full output
17 change `level = DEBUG` for all logging handlers in currently used .ini file.
17 change `level = DEBUG` for all logging handlers in currently used .ini file.
18 After this you can check much more detailed output of actions happening on
18 This change will allow to see much more detailed output in the logfile or
19 RhodeCode system.
19 console. This generally helps a lot to track issues.
20
20
21
21
22 enable interactive debug mode
22 enable interactive debug mode
23 -----------------------------
23 -----------------------------
24
24
25 To enable interactive debug mode simply
25 To enable interactive debug mode simply comment out `set debug = false` in
26 .ini file, this will trigger and interactive debugger each time there an
27 error in browser, or send a http link if error occured in the backend. This
28 is a great tool for fast debugging as you get a handy python console right
29 in the web view. ** NEVER ENABLE THIS ON PRODUCTION ** the interactive console
30 can be a serious security threat to you system.
@@ -1,814 +1,821 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.auth
3 rhodecode.lib.auth
4 ~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~
5
5
6 authentication and permission libraries
6 authentication and permission libraries
7
7
8 :created_on: Apr 4, 2010
8 :created_on: Apr 4, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import random
26 import random
27 import logging
27 import logging
28 import traceback
28 import traceback
29 import hashlib
29 import hashlib
30
30
31 from tempfile import _RandomNameSequence
31 from tempfile import _RandomNameSequence
32 from decorator import decorator
32 from decorator import decorator
33
33
34 from pylons import config, url, request
34 from pylons import config, url, request
35 from pylons.controllers.util import abort, redirect
35 from pylons.controllers.util import abort, redirect
36 from pylons.i18n.translation import _
36 from pylons.i18n.translation import _
37
37
38 from rhodecode import __platform__, PLATFORM_WIN, PLATFORM_OTHERS
38 from rhodecode import __platform__, PLATFORM_WIN, PLATFORM_OTHERS
39 from rhodecode.model.meta import Session
39 from rhodecode.model.meta import Session
40
40
41 if __platform__ in PLATFORM_WIN:
41 if __platform__ in PLATFORM_WIN:
42 from hashlib import sha256
42 from hashlib import sha256
43 if __platform__ in PLATFORM_OTHERS:
43 if __platform__ in PLATFORM_OTHERS:
44 import bcrypt
44 import bcrypt
45
45
46 from rhodecode.lib.utils2 import str2bool, safe_unicode
46 from rhodecode.lib.utils2 import str2bool, safe_unicode
47 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
47 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
48 from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug
48 from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug
49 from rhodecode.lib.auth_ldap import AuthLdap
49 from rhodecode.lib.auth_ldap import AuthLdap
50
50
51 from rhodecode.model import meta
51 from rhodecode.model import meta
52 from rhodecode.model.user import UserModel
52 from rhodecode.model.user import UserModel
53 from rhodecode.model.db import Permission, RhodeCodeSetting, User
53 from rhodecode.model.db import Permission, RhodeCodeSetting, User
54
54
55 log = logging.getLogger(__name__)
55 log = logging.getLogger(__name__)
56
56
57
57
58 class PasswordGenerator(object):
58 class PasswordGenerator(object):
59 """
59 """
60 This is a simple class for generating password from different sets of
60 This is a simple class for generating password from different sets of
61 characters
61 characters
62 usage::
62 usage::
63
63
64 passwd_gen = PasswordGenerator()
64 passwd_gen = PasswordGenerator()
65 #print 8-letter password containing only big and small letters
65 #print 8-letter password containing only big and small letters
66 of alphabet
66 of alphabet
67 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
67 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
68 """
68 """
69 ALPHABETS_NUM = r'''1234567890'''
69 ALPHABETS_NUM = r'''1234567890'''
70 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
70 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
71 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
71 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
72 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
72 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
73 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
73 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
74 + ALPHABETS_NUM + ALPHABETS_SPECIAL
74 + ALPHABETS_NUM + ALPHABETS_SPECIAL
75 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
75 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
76 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
76 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
77 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
77 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
78 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
78 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
79
79
80 def __init__(self, passwd=''):
80 def __init__(self, passwd=''):
81 self.passwd = passwd
81 self.passwd = passwd
82
82
83 def gen_password(self, length, type_=None):
83 def gen_password(self, length, type_=None):
84 if type_ is None:
84 if type_ is None:
85 type_ = self.ALPHABETS_FULL
85 type_ = self.ALPHABETS_FULL
86 self.passwd = ''.join([random.choice(type_) for _ in xrange(length)])
86 self.passwd = ''.join([random.choice(type_) for _ in xrange(length)])
87 return self.passwd
87 return self.passwd
88
88
89
89
90 class RhodeCodeCrypto(object):
90 class RhodeCodeCrypto(object):
91
91
92 @classmethod
92 @classmethod
93 def hash_string(cls, str_):
93 def hash_string(cls, str_):
94 """
94 """
95 Cryptographic function used for password hashing based on pybcrypt
95 Cryptographic function used for password hashing based on pybcrypt
96 or pycrypto in windows
96 or pycrypto in windows
97
97
98 :param password: password to hash
98 :param password: password to hash
99 """
99 """
100 if __platform__ in PLATFORM_WIN:
100 if __platform__ in PLATFORM_WIN:
101 return sha256(str_).hexdigest()
101 return sha256(str_).hexdigest()
102 elif __platform__ in PLATFORM_OTHERS:
102 elif __platform__ in PLATFORM_OTHERS:
103 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
103 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
104 else:
104 else:
105 raise Exception('Unknown or unsupported platform %s' \
105 raise Exception('Unknown or unsupported platform %s' \
106 % __platform__)
106 % __platform__)
107
107
108 @classmethod
108 @classmethod
109 def hash_check(cls, password, hashed):
109 def hash_check(cls, password, hashed):
110 """
110 """
111 Checks matching password with it's hashed value, runs different
111 Checks matching password with it's hashed value, runs different
112 implementation based on platform it runs on
112 implementation based on platform it runs on
113
113
114 :param password: password
114 :param password: password
115 :param hashed: password in hashed form
115 :param hashed: password in hashed form
116 """
116 """
117
117
118 if __platform__ in PLATFORM_WIN:
118 if __platform__ in PLATFORM_WIN:
119 return sha256(password).hexdigest() == hashed
119 return sha256(password).hexdigest() == hashed
120 elif __platform__ in PLATFORM_OTHERS:
120 elif __platform__ in PLATFORM_OTHERS:
121 return bcrypt.hashpw(password, hashed) == hashed
121 return bcrypt.hashpw(password, hashed) == hashed
122 else:
122 else:
123 raise Exception('Unknown or unsupported platform %s' \
123 raise Exception('Unknown or unsupported platform %s' \
124 % __platform__)
124 % __platform__)
125
125
126
126
127 def get_crypt_password(password):
127 def get_crypt_password(password):
128 return RhodeCodeCrypto.hash_string(password)
128 return RhodeCodeCrypto.hash_string(password)
129
129
130
130
131 def check_password(password, hashed):
131 def check_password(password, hashed):
132 return RhodeCodeCrypto.hash_check(password, hashed)
132 return RhodeCodeCrypto.hash_check(password, hashed)
133
133
134
134
135 def generate_api_key(str_, salt=None):
135 def generate_api_key(str_, salt=None):
136 """
136 """
137 Generates API KEY from given string
137 Generates API KEY from given string
138
138
139 :param str_:
139 :param str_:
140 :param salt:
140 :param salt:
141 """
141 """
142
142
143 if salt is None:
143 if salt is None:
144 salt = _RandomNameSequence().next()
144 salt = _RandomNameSequence().next()
145
145
146 return hashlib.sha1(str_ + salt).hexdigest()
146 return hashlib.sha1(str_ + salt).hexdigest()
147
147
148
148
149 def authfunc(environ, username, password):
149 def authfunc(environ, username, password):
150 """
150 """
151 Dummy authentication wrapper function used in Mercurial and Git for
151 Dummy authentication wrapper function used in Mercurial and Git for
152 access control.
152 access control.
153
153
154 :param environ: needed only for using in Basic auth
154 :param environ: needed only for using in Basic auth
155 """
155 """
156 return authenticate(username, password)
156 return authenticate(username, password)
157
157
158
158
159 def authenticate(username, password):
159 def authenticate(username, password):
160 """
160 """
161 Authentication function used for access control,
161 Authentication function used for access control,
162 firstly checks for db authentication then if ldap is enabled for ldap
162 firstly checks for db authentication then if ldap is enabled for ldap
163 authentication, also creates ldap user if not in database
163 authentication, also creates ldap user if not in database
164
164
165 :param username: username
165 :param username: username
166 :param password: password
166 :param password: password
167 """
167 """
168
168
169 user_model = UserModel()
169 user_model = UserModel()
170 user = User.get_by_username(username)
170 user = User.get_by_username(username)
171
171
172 log.debug('Authenticating user using RhodeCode account')
172 log.debug('Authenticating user using RhodeCode account')
173 if user is not None and not user.ldap_dn:
173 if user is not None and not user.ldap_dn:
174 if user.active:
174 if user.active:
175 if user.username == 'default' and user.active:
175 if user.username == 'default' and user.active:
176 log.info('user %s authenticated correctly as anonymous user' %
176 log.info('user %s authenticated correctly as anonymous user' %
177 username)
177 username)
178 return True
178 return True
179
179
180 elif user.username == username and check_password(password,
180 elif user.username == username and check_password(password,
181 user.password):
181 user.password):
182 log.info('user %s authenticated correctly' % username)
182 log.info('user %s authenticated correctly' % username)
183 return True
183 return True
184 else:
184 else:
185 log.warning('user %s tried auth but is disabled' % username)
185 log.warning('user %s tried auth but is disabled' % username)
186
186
187 else:
187 else:
188 log.debug('Regular authentication failed')
188 log.debug('Regular authentication failed')
189 user_obj = User.get_by_username(username, case_insensitive=True)
189 user_obj = User.get_by_username(username, case_insensitive=True)
190
190
191 if user_obj is not None and not user_obj.ldap_dn:
191 if user_obj is not None and not user_obj.ldap_dn:
192 log.debug('this user already exists as non ldap')
192 log.debug('this user already exists as non ldap')
193 return False
193 return False
194
194
195 ldap_settings = RhodeCodeSetting.get_ldap_settings()
195 ldap_settings = RhodeCodeSetting.get_ldap_settings()
196 #======================================================================
196 #======================================================================
197 # FALLBACK TO LDAP AUTH IF ENABLE
197 # FALLBACK TO LDAP AUTH IF ENABLE
198 #======================================================================
198 #======================================================================
199 if str2bool(ldap_settings.get('ldap_active')):
199 if str2bool(ldap_settings.get('ldap_active')):
200 log.debug("Authenticating user using ldap")
200 log.debug("Authenticating user using ldap")
201 kwargs = {
201 kwargs = {
202 'server': ldap_settings.get('ldap_host', ''),
202 'server': ldap_settings.get('ldap_host', ''),
203 'base_dn': ldap_settings.get('ldap_base_dn', ''),
203 'base_dn': ldap_settings.get('ldap_base_dn', ''),
204 'port': ldap_settings.get('ldap_port'),
204 'port': ldap_settings.get('ldap_port'),
205 'bind_dn': ldap_settings.get('ldap_dn_user'),
205 'bind_dn': ldap_settings.get('ldap_dn_user'),
206 'bind_pass': ldap_settings.get('ldap_dn_pass'),
206 'bind_pass': ldap_settings.get('ldap_dn_pass'),
207 'tls_kind': ldap_settings.get('ldap_tls_kind'),
207 'tls_kind': ldap_settings.get('ldap_tls_kind'),
208 'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'),
208 'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'),
209 'ldap_filter': ldap_settings.get('ldap_filter'),
209 'ldap_filter': ldap_settings.get('ldap_filter'),
210 'search_scope': ldap_settings.get('ldap_search_scope'),
210 'search_scope': ldap_settings.get('ldap_search_scope'),
211 'attr_login': ldap_settings.get('ldap_attr_login'),
211 'attr_login': ldap_settings.get('ldap_attr_login'),
212 'ldap_version': 3,
212 'ldap_version': 3,
213 }
213 }
214 log.debug('Checking for ldap authentication')
214 log.debug('Checking for ldap authentication')
215 try:
215 try:
216 aldap = AuthLdap(**kwargs)
216 aldap = AuthLdap(**kwargs)
217 (user_dn, ldap_attrs) = aldap.authenticate_ldap(username,
217 (user_dn, ldap_attrs) = aldap.authenticate_ldap(username,
218 password)
218 password)
219 log.debug('Got ldap DN response %s' % user_dn)
219 log.debug('Got ldap DN response %s' % user_dn)
220
220
221 get_ldap_attr = lambda k: ldap_attrs.get(ldap_settings\
221 get_ldap_attr = lambda k: ldap_attrs.get(ldap_settings\
222 .get(k), [''])[0]
222 .get(k), [''])[0]
223
223
224 user_attrs = {
224 user_attrs = {
225 'name': safe_unicode(get_ldap_attr('ldap_attr_firstname')),
225 'name': safe_unicode(get_ldap_attr('ldap_attr_firstname')),
226 'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')),
226 'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')),
227 'email': get_ldap_attr('ldap_attr_email'),
227 'email': get_ldap_attr('ldap_attr_email'),
228 }
228 }
229
229
230 # don't store LDAP password since we don't need it. Override
230 # don't store LDAP password since we don't need it. Override
231 # with some random generated password
231 # with some random generated password
232 _password = PasswordGenerator().gen_password(length=8)
232 _password = PasswordGenerator().gen_password(length=8)
233 # create this user on the fly if it doesn't exist in rhodecode
233 # create this user on the fly if it doesn't exist in rhodecode
234 # database
234 # database
235 if user_model.create_ldap(username, _password, user_dn,
235 if user_model.create_ldap(username, _password, user_dn,
236 user_attrs):
236 user_attrs):
237 log.info('created new ldap user %s' % username)
237 log.info('created new ldap user %s' % username)
238
238
239 Session.commit()
239 Session.commit()
240 return True
240 return True
241 except (LdapUsernameError, LdapPasswordError,):
241 except (LdapUsernameError, LdapPasswordError,):
242 pass
242 pass
243 except (Exception,):
243 except (Exception,):
244 log.error(traceback.format_exc())
244 log.error(traceback.format_exc())
245 pass
245 pass
246 return False
246 return False
247
247
248
248
249 def login_container_auth(username):
249 def login_container_auth(username):
250 user = User.get_by_username(username)
250 user = User.get_by_username(username)
251 if user is None:
251 if user is None:
252 user_attrs = {
252 user_attrs = {
253 'name': username,
253 'name': username,
254 'lastname': None,
254 'lastname': None,
255 'email': None,
255 'email': None,
256 }
256 }
257 user = UserModel().create_for_container_auth(username, user_attrs)
257 user = UserModel().create_for_container_auth(username, user_attrs)
258 if not user:
258 if not user:
259 return None
259 return None
260 log.info('User %s was created by container authentication' % username)
260 log.info('User %s was created by container authentication' % username)
261
261
262 if not user.active:
262 if not user.active:
263 return None
263 return None
264
264
265 user.update_lastlogin()
265 user.update_lastlogin()
266 Session.commit()
266 Session.commit()
267
267
268 log.debug('User %s is now logged in by container authentication',
268 log.debug('User %s is now logged in by container authentication',
269 user.username)
269 user.username)
270 return user
270 return user
271
271
272
272
273 def get_container_username(environ, config):
273 def get_container_username(environ, config):
274 username = None
274 username = None
275
275
276 if str2bool(config.get('container_auth_enabled', False)):
276 if str2bool(config.get('container_auth_enabled', False)):
277 from paste.httpheaders import REMOTE_USER
277 from paste.httpheaders import REMOTE_USER
278 username = REMOTE_USER(environ)
278 username = REMOTE_USER(environ)
279
279
280 if not username and str2bool(config.get('proxypass_auth_enabled', False)):
280 if not username and str2bool(config.get('proxypass_auth_enabled', False)):
281 username = environ.get('HTTP_X_FORWARDED_USER')
281 username = environ.get('HTTP_X_FORWARDED_USER')
282
282
283 if username:
283 if username:
284 # Removing realm and domain from username
284 # Removing realm and domain from username
285 username = username.partition('@')[0]
285 username = username.partition('@')[0]
286 username = username.rpartition('\\')[2]
286 username = username.rpartition('\\')[2]
287 log.debug('Received username %s from container' % username)
287 log.debug('Received username %s from container' % username)
288
288
289 return username
289 return username
290
290
291
291
292 class CookieStoreWrapper(object):
292 class CookieStoreWrapper(object):
293
293
294 def __init__(self, cookie_store):
294 def __init__(self, cookie_store):
295 self.cookie_store = cookie_store
295 self.cookie_store = cookie_store
296
296
297 def __repr__(self):
297 def __repr__(self):
298 return 'CookieStore<%s>' % (self.cookie_store)
298 return 'CookieStore<%s>' % (self.cookie_store)
299
299
300 def get(self, key, other=None):
300 def get(self, key, other=None):
301 if isinstance(self.cookie_store, dict):
301 if isinstance(self.cookie_store, dict):
302 return self.cookie_store.get(key, other)
302 return self.cookie_store.get(key, other)
303 elif isinstance(self.cookie_store, AuthUser):
303 elif isinstance(self.cookie_store, AuthUser):
304 return self.cookie_store.__dict__.get(key, other)
304 return self.cookie_store.__dict__.get(key, other)
305
305
306
306
307 class AuthUser(object):
307 class AuthUser(object):
308 """
308 """
309 A simple object that handles all attributes of user in RhodeCode
309 A simple object that handles all attributes of user in RhodeCode
310
310
311 It does lookup based on API key,given user, or user present in session
311 It does lookup based on API key,given user, or user present in session
312 Then it fills all required information for such user. It also checks if
312 Then it fills all required information for such user. It also checks if
313 anonymous access is enabled and if so, it returns default user as logged
313 anonymous access is enabled and if so, it returns default user as logged
314 in
314 in
315 """
315 """
316
316
317 def __init__(self, user_id=None, api_key=None, username=None):
317 def __init__(self, user_id=None, api_key=None, username=None):
318
318
319 self.user_id = user_id
319 self.user_id = user_id
320 self.api_key = None
320 self.api_key = None
321 self.username = username
321 self.username = username
322
322
323 self.name = ''
323 self.name = ''
324 self.lastname = ''
324 self.lastname = ''
325 self.email = ''
325 self.email = ''
326 self.is_authenticated = False
326 self.is_authenticated = False
327 self.admin = False
327 self.admin = False
328 self.permissions = {}
328 self.permissions = {}
329 self._api_key = api_key
329 self._api_key = api_key
330 self.propagate_data()
330 self.propagate_data()
331 self._instance = None
331 self._instance = None
332
332
333 def propagate_data(self):
333 def propagate_data(self):
334 user_model = UserModel()
334 user_model = UserModel()
335 self.anonymous_user = User.get_by_username('default', cache=True)
335 self.anonymous_user = User.get_by_username('default', cache=True)
336 is_user_loaded = False
336 is_user_loaded = False
337
337
338 # try go get user by api key
338 # try go get user by api key
339 if self._api_key and self._api_key != self.anonymous_user.api_key:
339 if self._api_key and self._api_key != self.anonymous_user.api_key:
340 log.debug('Auth User lookup by API KEY %s' % self._api_key)
340 log.debug('Auth User lookup by API KEY %s' % self._api_key)
341 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
341 is_user_loaded = user_model.fill_data(self, api_key=self._api_key)
342 # lookup by userid
342 # lookup by userid
343 elif (self.user_id is not None and
343 elif (self.user_id is not None and
344 self.user_id != self.anonymous_user.user_id):
344 self.user_id != self.anonymous_user.user_id):
345 log.debug('Auth User lookup by USER ID %s' % self.user_id)
345 log.debug('Auth User lookup by USER ID %s' % self.user_id)
346 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
346 is_user_loaded = user_model.fill_data(self, user_id=self.user_id)
347 # lookup by username
347 # lookup by username
348 elif self.username and \
348 elif self.username and \
349 str2bool(config.get('container_auth_enabled', False)):
349 str2bool(config.get('container_auth_enabled', False)):
350
350
351 log.debug('Auth User lookup by USER NAME %s' % self.username)
351 log.debug('Auth User lookup by USER NAME %s' % self.username)
352 dbuser = login_container_auth(self.username)
352 dbuser = login_container_auth(self.username)
353 if dbuser is not None:
353 if dbuser is not None:
354 for k, v in dbuser.get_dict().items():
354 for k, v in dbuser.get_dict().items():
355 setattr(self, k, v)
355 setattr(self, k, v)
356 self.set_authenticated()
356 self.set_authenticated()
357 is_user_loaded = True
357 is_user_loaded = True
358 else:
358 else:
359 log.debug('No data in %s that could been used to log in' % self)
359 log.debug('No data in %s that could been used to log in' % self)
360
360
361 if not is_user_loaded:
361 if not is_user_loaded:
362 # if we cannot authenticate user try anonymous
362 # if we cannot authenticate user try anonymous
363 if self.anonymous_user.active is True:
363 if self.anonymous_user.active is True:
364 user_model.fill_data(self, user_id=self.anonymous_user.user_id)
364 user_model.fill_data(self, user_id=self.anonymous_user.user_id)
365 # then we set this user is logged in
365 # then we set this user is logged in
366 self.is_authenticated = True
366 self.is_authenticated = True
367 else:
367 else:
368 self.user_id = None
368 self.user_id = None
369 self.username = None
369 self.username = None
370 self.is_authenticated = False
370 self.is_authenticated = False
371
371
372 if not self.username:
372 if not self.username:
373 self.username = 'None'
373 self.username = 'None'
374
374
375 log.debug('Auth User is now %s' % self)
375 log.debug('Auth User is now %s' % self)
376 user_model.fill_perms(self)
376 user_model.fill_perms(self)
377
377
378 @property
378 @property
379 def is_admin(self):
379 def is_admin(self):
380 return self.admin
380 return self.admin
381
381
382 def __repr__(self):
382 def __repr__(self):
383 return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
383 return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
384 self.is_authenticated)
384 self.is_authenticated)
385
385
386 def set_authenticated(self, authenticated=True):
386 def set_authenticated(self, authenticated=True):
387 if self.user_id != self.anonymous_user.user_id:
387 if self.user_id != self.anonymous_user.user_id:
388 self.is_authenticated = authenticated
388 self.is_authenticated = authenticated
389
389
390 def get_cookie_store(self):
390 def get_cookie_store(self):
391 return {'username': self.username,
391 return {'username': self.username,
392 'user_id': self.user_id,
392 'user_id': self.user_id,
393 'is_authenticated': self.is_authenticated}
393 'is_authenticated': self.is_authenticated}
394
394
395 @classmethod
395 @classmethod
396 def from_cookie_store(cls, cookie_store):
396 def from_cookie_store(cls, cookie_store):
397 """
397 """
398 Creates AuthUser from a cookie store
398 Creates AuthUser from a cookie store
399
399
400 :param cls:
400 :param cls:
401 :param cookie_store:
401 :param cookie_store:
402 """
402 """
403 user_id = cookie_store.get('user_id')
403 user_id = cookie_store.get('user_id')
404 username = cookie_store.get('username')
404 username = cookie_store.get('username')
405 api_key = cookie_store.get('api_key')
405 api_key = cookie_store.get('api_key')
406 return AuthUser(user_id, api_key, username)
406 return AuthUser(user_id, api_key, username)
407
407
408
408
409 def set_available_permissions(config):
409 def set_available_permissions(config):
410 """
410 """
411 This function will propagate pylons globals with all available defined
411 This function will propagate pylons globals with all available defined
412 permission given in db. We don't want to check each time from db for new
412 permission given in db. We don't want to check each time from db for new
413 permissions since adding a new permission also requires application restart
413 permissions since adding a new permission also requires application restart
414 ie. to decorate new views with the newly created permission
414 ie. to decorate new views with the newly created permission
415
415
416 :param config: current pylons config instance
416 :param config: current pylons config instance
417
417
418 """
418 """
419 log.info('getting information about all available permissions')
419 log.info('getting information about all available permissions')
420 try:
420 try:
421 sa = meta.Session
421 sa = meta.Session
422 all_perms = sa.query(Permission).all()
422 all_perms = sa.query(Permission).all()
423 except Exception:
423 except Exception:
424 pass
424 pass
425 finally:
425 finally:
426 meta.Session.remove()
426 meta.Session.remove()
427
427
428 config['available_permissions'] = [x.permission_name for x in all_perms]
428 config['available_permissions'] = [x.permission_name for x in all_perms]
429
429
430
430
431 #==============================================================================
431 #==============================================================================
432 # CHECK DECORATORS
432 # CHECK DECORATORS
433 #==============================================================================
433 #==============================================================================
434 class LoginRequired(object):
434 class LoginRequired(object):
435 """
435 """
436 Must be logged in to execute this function else
436 Must be logged in to execute this function else
437 redirect to login page
437 redirect to login page
438
438
439 :param api_access: if enabled this checks only for valid auth token
439 :param api_access: if enabled this checks only for valid auth token
440 and grants access based on valid token
440 and grants access based on valid token
441 """
441 """
442
442
443 def __init__(self, api_access=False):
443 def __init__(self, api_access=False):
444 self.api_access = api_access
444 self.api_access = api_access
445
445
446 def __call__(self, func):
446 def __call__(self, func):
447 return decorator(self.__wrapper, func)
447 return decorator(self.__wrapper, func)
448
448
449 def __wrapper(self, func, *fargs, **fkwargs):
449 def __wrapper(self, func, *fargs, **fkwargs):
450 cls = fargs[0]
450 cls = fargs[0]
451 user = cls.rhodecode_user
451 user = cls.rhodecode_user
452
452
453 api_access_ok = False
453 api_access_ok = False
454 if self.api_access:
454 if self.api_access:
455 log.debug('Checking API KEY access for %s' % cls)
455 log.debug('Checking API KEY access for %s' % cls)
456 if user.api_key == request.GET.get('api_key'):
456 if user.api_key == request.GET.get('api_key'):
457 api_access_ok = True
457 api_access_ok = True
458 else:
458 else:
459 log.debug("API KEY token not valid")
459 log.debug("API KEY token not valid")
460 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
460 loc = "%s:%s" % (cls.__class__.__name__, func.__name__)
461 log.debug('Checking if %s is authenticated @ %s' % (user.username, loc))
461 log.debug('Checking if %s is authenticated @ %s' % (user.username, loc))
462 if user.is_authenticated or api_access_ok:
462 if user.is_authenticated or api_access_ok:
463 log.info('user %s is authenticated and granted access to %s' % (
463 log.info('user %s is authenticated and granted access to %s' % (
464 user.username, loc)
464 user.username, loc)
465 )
465 )
466 return func(*fargs, **fkwargs)
466 return func(*fargs, **fkwargs)
467 else:
467 else:
468 log.warn('user %s NOT authenticated on func: %s' % (
468 log.warn('user %s NOT authenticated on func: %s' % (
469 user, loc)
469 user, loc)
470 )
470 )
471 p = url.current()
471 p = url.current()
472
472
473 log.debug('redirecting to login page with %s' % p)
473 log.debug('redirecting to login page with %s' % p)
474 return redirect(url('login_home', came_from=p))
474 return redirect(url('login_home', came_from=p))
475
475
476
476
477 class NotAnonymous(object):
477 class NotAnonymous(object):
478 """
478 """
479 Must be logged in to execute this function else
479 Must be logged in to execute this function else
480 redirect to login page"""
480 redirect to login page"""
481
481
482 def __call__(self, func):
482 def __call__(self, func):
483 return decorator(self.__wrapper, func)
483 return decorator(self.__wrapper, func)
484
484
485 def __wrapper(self, func, *fargs, **fkwargs):
485 def __wrapper(self, func, *fargs, **fkwargs):
486 cls = fargs[0]
486 cls = fargs[0]
487 self.user = cls.rhodecode_user
487 self.user = cls.rhodecode_user
488
488
489 log.debug('Checking if user is not anonymous @%s' % cls)
489 log.debug('Checking if user is not anonymous @%s' % cls)
490
490
491 anonymous = self.user.username == 'default'
491 anonymous = self.user.username == 'default'
492
492
493 if anonymous:
493 if anonymous:
494 p = url.current()
494 p = url.current()
495
495
496 import rhodecode.lib.helpers as h
496 import rhodecode.lib.helpers as h
497 h.flash(_('You need to be a registered user to '
497 h.flash(_('You need to be a registered user to '
498 'perform this action'),
498 'perform this action'),
499 category='warning')
499 category='warning')
500 return redirect(url('login_home', came_from=p))
500 return redirect(url('login_home', came_from=p))
501 else:
501 else:
502 return func(*fargs, **fkwargs)
502 return func(*fargs, **fkwargs)
503
503
504
504
505 class PermsDecorator(object):
505 class PermsDecorator(object):
506 """Base class for controller decorators"""
506 """Base class for controller decorators"""
507
507
508 def __init__(self, *required_perms):
508 def __init__(self, *required_perms):
509 available_perms = config['available_permissions']
509 available_perms = config['available_permissions']
510 for perm in required_perms:
510 for perm in required_perms:
511 if perm not in available_perms:
511 if perm not in available_perms:
512 raise Exception("'%s' permission is not defined" % perm)
512 raise Exception("'%s' permission is not defined" % perm)
513 self.required_perms = set(required_perms)
513 self.required_perms = set(required_perms)
514 self.user_perms = None
514 self.user_perms = None
515
515
516 def __call__(self, func):
516 def __call__(self, func):
517 return decorator(self.__wrapper, func)
517 return decorator(self.__wrapper, func)
518
518
519 def __wrapper(self, func, *fargs, **fkwargs):
519 def __wrapper(self, func, *fargs, **fkwargs):
520 cls = fargs[0]
520 cls = fargs[0]
521 self.user = cls.rhodecode_user
521 self.user = cls.rhodecode_user
522 self.user_perms = self.user.permissions
522 self.user_perms = self.user.permissions
523 log.debug('checking %s permissions %s for %s %s',
523 log.debug('checking %s permissions %s for %s %s',
524 self.__class__.__name__, self.required_perms, cls,
524 self.__class__.__name__, self.required_perms, cls, self.user)
525 self.user)
526
525
527 if self.check_permissions():
526 if self.check_permissions():
528 log.debug('Permission granted for %s %s' % (cls, self.user))
527 log.debug('Permission granted for %s %s' % (cls, self.user))
529 return func(*fargs, **fkwargs)
528 return func(*fargs, **fkwargs)
530
529
531 else:
530 else:
532 log.debug('Permission denied for %s %s' % (cls, self.user))
531 log.debug('Permission denied for %s %s' % (cls, self.user))
533 anonymous = self.user.username == 'default'
532 anonymous = self.user.username == 'default'
534
533
535 if anonymous:
534 if anonymous:
536 p = url.current()
535 p = url.current()
537
536
538 import rhodecode.lib.helpers as h
537 import rhodecode.lib.helpers as h
539 h.flash(_('You need to be a signed in to '
538 h.flash(_('You need to be a signed in to '
540 'view this page'),
539 'view this page'),
541 category='warning')
540 category='warning')
542 return redirect(url('login_home', came_from=p))
541 return redirect(url('login_home', came_from=p))
543
542
544 else:
543 else:
545 # redirect with forbidden ret code
544 # redirect with forbidden ret code
546 return abort(403)
545 return abort(403)
547
546
548 def check_permissions(self):
547 def check_permissions(self):
549 """Dummy function for overriding"""
548 """Dummy function for overriding"""
550 raise Exception('You have to write this function in child class')
549 raise Exception('You have to write this function in child class')
551
550
552
551
553 class HasPermissionAllDecorator(PermsDecorator):
552 class HasPermissionAllDecorator(PermsDecorator):
554 """
553 """
555 Checks for access permission for all given predicates. All of them
554 Checks for access permission for all given predicates. All of them
556 have to be meet in order to fulfill the request
555 have to be meet in order to fulfill the request
557 """
556 """
558
557
559 def check_permissions(self):
558 def check_permissions(self):
560 if self.required_perms.issubset(self.user_perms.get('global')):
559 if self.required_perms.issubset(self.user_perms.get('global')):
561 return True
560 return True
562 return False
561 return False
563
562
564
563
565 class HasPermissionAnyDecorator(PermsDecorator):
564 class HasPermissionAnyDecorator(PermsDecorator):
566 """
565 """
567 Checks for access permission for any of given predicates. In order to
566 Checks for access permission for any of given predicates. In order to
568 fulfill the request any of predicates must be meet
567 fulfill the request any of predicates must be meet
569 """
568 """
570
569
571 def check_permissions(self):
570 def check_permissions(self):
572 if self.required_perms.intersection(self.user_perms.get('global')):
571 if self.required_perms.intersection(self.user_perms.get('global')):
573 return True
572 return True
574 return False
573 return False
575
574
576
575
577 class HasRepoPermissionAllDecorator(PermsDecorator):
576 class HasRepoPermissionAllDecorator(PermsDecorator):
578 """
577 """
579 Checks for access permission for all given predicates for specific
578 Checks for access permission for all given predicates for specific
580 repository. All of them have to be meet in order to fulfill the request
579 repository. All of them have to be meet in order to fulfill the request
581 """
580 """
582
581
583 def check_permissions(self):
582 def check_permissions(self):
584 repo_name = get_repo_slug(request)
583 repo_name = get_repo_slug(request)
585 try:
584 try:
586 user_perms = set([self.user_perms['repositories'][repo_name]])
585 user_perms = set([self.user_perms['repositories'][repo_name]])
587 except KeyError:
586 except KeyError:
588 return False
587 return False
589 if self.required_perms.issubset(user_perms):
588 if self.required_perms.issubset(user_perms):
590 return True
589 return True
591 return False
590 return False
592
591
593
592
594 class HasRepoPermissionAnyDecorator(PermsDecorator):
593 class HasRepoPermissionAnyDecorator(PermsDecorator):
595 """
594 """
596 Checks for access permission for any of given predicates for specific
595 Checks for access permission for any of given predicates for specific
597 repository. In order to fulfill the request any of predicates must be meet
596 repository. In order to fulfill the request any of predicates must be meet
598 """
597 """
599
598
600 def check_permissions(self):
599 def check_permissions(self):
601 repo_name = get_repo_slug(request)
600 repo_name = get_repo_slug(request)
602
601
603 try:
602 try:
604 user_perms = set([self.user_perms['repositories'][repo_name]])
603 user_perms = set([self.user_perms['repositories'][repo_name]])
605 except KeyError:
604 except KeyError:
606 return False
605 return False
606
607 if self.required_perms.intersection(user_perms):
607 if self.required_perms.intersection(user_perms):
608 return True
608 return True
609 return False
609 return False
610
610
611
611
612 class HasReposGroupPermissionAllDecorator(PermsDecorator):
612 class HasReposGroupPermissionAllDecorator(PermsDecorator):
613 """
613 """
614 Checks for access permission for all given predicates for specific
614 Checks for access permission for all given predicates for specific
615 repository. All of them have to be meet in order to fulfill the request
615 repository. All of them have to be meet in order to fulfill the request
616 """
616 """
617
617
618 def check_permissions(self):
618 def check_permissions(self):
619 group_name = get_repos_group_slug(request)
619 group_name = get_repos_group_slug(request)
620 try:
620 try:
621 user_perms = set([self.user_perms['repositories_groups'][group_name]])
621 user_perms = set([self.user_perms['repositories_groups'][group_name]])
622 except KeyError:
622 except KeyError:
623 return False
623 return False
624 if self.required_perms.issubset(user_perms):
624 if self.required_perms.issubset(user_perms):
625 return True
625 return True
626 return False
626 return False
627
627
628
628
629 class HasReposGroupPermissionAnyDecorator(PermsDecorator):
629 class HasReposGroupPermissionAnyDecorator(PermsDecorator):
630 """
630 """
631 Checks for access permission for any of given predicates for specific
631 Checks for access permission for any of given predicates for specific
632 repository. In order to fulfill the request any of predicates must be meet
632 repository. In order to fulfill the request any of predicates must be meet
633 """
633 """
634
634
635 def check_permissions(self):
635 def check_permissions(self):
636 group_name = get_repos_group_slug(request)
636 group_name = get_repos_group_slug(request)
637
637
638 try:
638 try:
639 user_perms = set([self.user_perms['repositories_groups'][group_name]])
639 user_perms = set([self.user_perms['repositories_groups'][group_name]])
640 except KeyError:
640 except KeyError:
641 return False
641 return False
642 if self.required_perms.intersection(user_perms):
642 if self.required_perms.intersection(user_perms):
643 return True
643 return True
644 return False
644 return False
645
645
646
646
647 #==============================================================================
647 #==============================================================================
648 # CHECK FUNCTIONS
648 # CHECK FUNCTIONS
649 #==============================================================================
649 #==============================================================================
650 class PermsFunction(object):
650 class PermsFunction(object):
651 """Base function for other check functions"""
651 """Base function for other check functions"""
652
652
653 def __init__(self, *perms):
653 def __init__(self, *perms):
654 available_perms = config['available_permissions']
654 available_perms = config['available_permissions']
655
655
656 for perm in perms:
656 for perm in perms:
657 if perm not in available_perms:
657 if perm not in available_perms:
658 raise Exception("'%s' permission is not defined" % perm)
658 raise Exception("'%s' permission is not defined" % perm)
659 self.required_perms = set(perms)
659 self.required_perms = set(perms)
660 self.user_perms = None
660 self.user_perms = None
661 self.granted_for = ''
662 self.repo_name = None
661 self.repo_name = None
662 self.group_name = None
663
663
664 def __call__(self, check_Location=''):
664 def __call__(self, check_Location=''):
665 user = request.user
665 user = request.user
666 log.debug('checking %s %s %s', self.__class__.__name__,
666 cls_name = self.__class__.__name__
667 self.required_perms, user)
667 check_scope = {
668 'HasPermissionAll': '',
669 'HasPermissionAny': '',
670 'HasRepoPermissionAll': 'repo:%s' % self.repo_name,
671 'HasRepoPermissionAny': 'repo:%s' % self.repo_name,
672 'HasReposGroupPermissionAll': 'group:%s' % self.group_name,
673 'HasReposGroupPermissionAny': 'group:%s' % self.group_name,
674 }.get(cls_name, '?')
675 log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
676 self.required_perms, user, check_scope,
677 check_Location or 'unspecified location')
668 if not user:
678 if not user:
669 log.debug('Empty request user')
679 log.debug('Empty request user')
670 return False
680 return False
671 self.user_perms = user.permissions
681 self.user_perms = user.permissions
672 self.granted_for = user
673
674 if self.check_permissions():
682 if self.check_permissions():
675 log.debug('Permission granted %s @ %s', self.granted_for,
683 log.debug('Permission granted for user: %s @ %s', user,
676 check_Location or 'unspecified location')
684 check_Location or 'unspecified location')
677 return True
685 return True
678
686
679 else:
687 else:
680 log.debug('Permission denied for %s @ %s', self.granted_for,
688 log.debug('Permission denied for user: %s @ %s', user,
681 check_Location or 'unspecified location')
689 check_Location or 'unspecified location')
682 return False
690 return False
683
691
684 def check_permissions(self):
692 def check_permissions(self):
685 """Dummy function for overriding"""
693 """Dummy function for overriding"""
686 raise Exception('You have to write this function in child class')
694 raise Exception('You have to write this function in child class')
687
695
688
696
689 class HasPermissionAll(PermsFunction):
697 class HasPermissionAll(PermsFunction):
690 def check_permissions(self):
698 def check_permissions(self):
691 if self.required_perms.issubset(self.user_perms.get('global')):
699 if self.required_perms.issubset(self.user_perms.get('global')):
692 return True
700 return True
693 return False
701 return False
694
702
695
703
696 class HasPermissionAny(PermsFunction):
704 class HasPermissionAny(PermsFunction):
697 def check_permissions(self):
705 def check_permissions(self):
698 if self.required_perms.intersection(self.user_perms.get('global')):
706 if self.required_perms.intersection(self.user_perms.get('global')):
699 return True
707 return True
700 return False
708 return False
701
709
702
710
703 class HasRepoPermissionAll(PermsFunction):
711 class HasRepoPermissionAll(PermsFunction):
704
705 def __call__(self, repo_name=None, check_Location=''):
712 def __call__(self, repo_name=None, check_Location=''):
706 self.repo_name = repo_name
713 self.repo_name = repo_name
707 return super(HasRepoPermissionAll, self).__call__(check_Location)
714 return super(HasRepoPermissionAll, self).__call__(check_Location)
708
715
709 def check_permissions(self):
716 def check_permissions(self):
710 if not self.repo_name:
717 if not self.repo_name:
711 self.repo_name = get_repo_slug(request)
718 self.repo_name = get_repo_slug(request)
712
719
713 try:
720 try:
714 self.user_perms = set(
721 self._user_perms = set(
715 [self.user_perms['repositories'][self.repo_name]]
722 [self.user_perms['repositories'][self.repo_name]]
716 )
723 )
717 except KeyError:
724 except KeyError:
718 return False
725 return False
719 self.granted_for = self.repo_name
726 if self.required_perms.issubset(self._user_perms):
720 if self.required_perms.issubset(self.user_perms):
721 return True
727 return True
722 return False
728 return False
723
729
724
730
725 class HasRepoPermissionAny(PermsFunction):
731 class HasRepoPermissionAny(PermsFunction):
726
727 def __call__(self, repo_name=None, check_Location=''):
732 def __call__(self, repo_name=None, check_Location=''):
728 self.repo_name = repo_name
733 self.repo_name = repo_name
729 return super(HasRepoPermissionAny, self).__call__(check_Location)
734 return super(HasRepoPermissionAny, self).__call__(check_Location)
730
735
731 def check_permissions(self):
736 def check_permissions(self):
732 if not self.repo_name:
737 if not self.repo_name:
733 self.repo_name = get_repo_slug(request)
738 self.repo_name = get_repo_slug(request)
734
739
735 try:
740 try:
736 self.user_perms = set(
741 self._user_perms = set(
737 [self.user_perms['repositories'][self.repo_name]]
742 [self.user_perms['repositories'][self.repo_name]]
738 )
743 )
739 except KeyError:
744 except KeyError:
740 return False
745 return False
741 self.granted_for = self.repo_name
746 if self.required_perms.intersection(self._user_perms):
742 if self.required_perms.intersection(self.user_perms):
743 return True
747 return True
744 return False
748 return False
745
749
746
750
747 class HasReposGroupPermissionAny(PermsFunction):
751 class HasReposGroupPermissionAny(PermsFunction):
748 def __call__(self, group_name=None, check_Location=''):
752 def __call__(self, group_name=None, check_Location=''):
749 self.group_name = group_name
753 self.group_name = group_name
750 return super(HasReposGroupPermissionAny, self).__call__(check_Location)
754 return super(HasReposGroupPermissionAny, self).__call__(check_Location)
751
755
752 def check_permissions(self):
756 def check_permissions(self):
753 try:
757 try:
754 self.user_perms = set(
758 self._user_perms = set(
755 [self.user_perms['repositories_groups'][self.group_name]]
759 [self.user_perms['repositories_groups'][self.group_name]]
756 )
760 )
757 except KeyError:
761 except KeyError:
758 return False
762 return False
759 self.granted_for = self.repo_name
763 if self.required_perms.intersection(self._user_perms):
760 if self.required_perms.intersection(self.user_perms):
761 return True
764 return True
762 return False
765 return False
763
766
764
767
765 class HasReposGroupPermissionAll(PermsFunction):
768 class HasReposGroupPermissionAll(PermsFunction):
766 def __call__(self, group_name=None, check_Location=''):
769 def __call__(self, group_name=None, check_Location=''):
767 self.group_name = group_name
770 self.group_name = group_name
768 return super(HasReposGroupPermissionAny, self).__call__(check_Location)
771 return super(HasReposGroupPermissionAny, self).__call__(check_Location)
769
772
770 def check_permissions(self):
773 def check_permissions(self):
771 try:
774 try:
772 self.user_perms = set(
775 self._user_perms = set(
773 [self.user_perms['repositories_groups'][self.group_name]]
776 [self.user_perms['repositories_groups'][self.group_name]]
774 )
777 )
775 except KeyError:
778 except KeyError:
776 return False
779 return False
777 self.granted_for = self.repo_name
780 if self.required_perms.issubset(self._user_perms):
778 if self.required_perms.issubset(self.user_perms):
779 return True
781 return True
780 return False
782 return False
781
783
782
784
783 #==============================================================================
785 #==============================================================================
784 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
786 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
785 #==============================================================================
787 #==============================================================================
786 class HasPermissionAnyMiddleware(object):
788 class HasPermissionAnyMiddleware(object):
787 def __init__(self, *perms):
789 def __init__(self, *perms):
788 self.required_perms = set(perms)
790 self.required_perms = set(perms)
789
791
790 def __call__(self, user, repo_name):
792 def __call__(self, user, repo_name):
791 # repo_name MUST be unicode, since we handle keys in permission
793 # repo_name MUST be unicode, since we handle keys in permission
792 # dict by unicode
794 # dict by unicode
793 repo_name = safe_unicode(repo_name)
795 repo_name = safe_unicode(repo_name)
794 usr = AuthUser(user.user_id)
796 usr = AuthUser(user.user_id)
795 try:
797 try:
796 self.user_perms = set([usr.permissions['repositories'][repo_name]])
798 self.user_perms = set([usr.permissions['repositories'][repo_name]])
797 except Exception:
799 except Exception:
798 log.error('Exception while accessing permissions %s' %
800 log.error('Exception while accessing permissions %s' %
799 traceback.format_exc())
801 traceback.format_exc())
800 self.user_perms = set()
802 self.user_perms = set()
801 self.granted_for = ''
802 self.username = user.username
803 self.username = user.username
803 self.repo_name = repo_name
804 self.repo_name = repo_name
804 return self.check_permissions()
805 return self.check_permissions()
805
806
806 def check_permissions(self):
807 def check_permissions(self):
807 log.debug('checking mercurial protocol '
808 log.debug('checking mercurial protocol '
808 'permissions %s for user:%s repository:%s', self.user_perms,
809 'permissions %s for user:%s repository:%s', self.user_perms,
809 self.username, self.repo_name)
810 self.username, self.repo_name)
810 if self.required_perms.intersection(self.user_perms):
811 if self.required_perms.intersection(self.user_perms):
811 log.debug('permission granted')
812 log.debug('permission granted for user:%s on repo:%s' % (
813 self.username, self.repo_name
814 )
815 )
812 return True
816 return True
813 log.debug('permission denied')
817 log.debug('permission denied for user:%s on repo:%s' % (
818 self.username, self.repo_name
819 )
820 )
814 return False
821 return False
General Comments 0
You need to be logged in to leave comments. Login now