##// END OF EJS Templates
fixed anonymous access bug.
marcink -
r686:ff6a8196 beta
parent child Browse files
Show More
@@ -1,480 +1,479 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # authentication and permission libraries
3 # authentication and permission libraries
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on April 4, 2010
21 Created on April 4, 2010
22
22
23 @author: marcink
23 @author: marcink
24 """
24 """
25 from pylons import config, session, url, request
25 from pylons import config, session, url, request
26 from pylons.controllers.util import abort, redirect
26 from pylons.controllers.util import abort, redirect
27 from rhodecode.lib.utils import get_repo_slug
27 from rhodecode.lib.utils import get_repo_slug
28 from rhodecode.model import meta
28 from rhodecode.model import meta
29 from rhodecode.model.user import UserModel
29 from rhodecode.model.user import UserModel
30 from rhodecode.model.caching_query import FromCache
30 from rhodecode.model.caching_query import FromCache
31 from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
31 from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
32 UserToPerm
32 UserToPerm
33 import bcrypt
33 import bcrypt
34 from decorator import decorator
34 from decorator import decorator
35 import logging
35 import logging
36 import random
36 import random
37
37
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
40 class PasswordGenerator(object):
40 class PasswordGenerator(object):
41 """This is a simple class for generating password from
41 """This is a simple class for generating password from
42 different sets of characters
42 different sets of characters
43 usage:
43 usage:
44 passwd_gen = PasswordGenerator()
44 passwd_gen = PasswordGenerator()
45 #print 8-letter password containing only big and small letters of alphabet
45 #print 8-letter password containing only big and small letters of alphabet
46 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
46 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
47 """
47 """
48 ALPHABETS_NUM = r'''1234567890'''#[0]
48 ALPHABETS_NUM = r'''1234567890'''#[0]
49 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''#[1]
49 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''#[1]
50 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''#[2]
50 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''#[2]
51 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' #[3]
51 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' #[3]
52 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_SPECIAL#[4]
52 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_SPECIAL#[4]
53 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM#[5]
53 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM#[5]
54 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
54 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
55 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
55 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
56 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
56 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
57
57
58 def __init__(self, passwd=''):
58 def __init__(self, passwd=''):
59 self.passwd = passwd
59 self.passwd = passwd
60
60
61 def gen_password(self, len, type):
61 def gen_password(self, len, type):
62 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
62 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
63 return self.passwd
63 return self.passwd
64
64
65
65
66 def get_crypt_password(password):
66 def get_crypt_password(password):
67 """Cryptographic function used for password hashing based on sha1
67 """Cryptographic function used for password hashing based on sha1
68 :param password: password to hash
68 :param password: password to hash
69 """
69 """
70 return bcrypt.hashpw(password, bcrypt.gensalt(10))
70 return bcrypt.hashpw(password, bcrypt.gensalt(10))
71
71
72 def check_password(password, hashed):
72 def check_password(password, hashed):
73 return bcrypt.hashpw(password, hashed) == hashed
73 return bcrypt.hashpw(password, hashed) == hashed
74
74
75 def authfunc(environ, username, password):
75 def authfunc(environ, username, password):
76 user = UserModel().get_by_username(username, cache=False)
76 user = UserModel().get_by_username(username, cache=False)
77
77
78 if user:
78 if user:
79 if user.active:
79 if user.active:
80
80
81 if user.username == 'default' and user.active:
81 if user.username == 'default' and user.active:
82 log.info('user %s authenticated correctly', username)
82 log.info('user %s authenticated correctly', username)
83 return True
83 return True
84
84
85 elif user.username == username and check_password(password, user.password):
85 elif user.username == username and check_password(password, user.password):
86 log.info('user %s authenticated correctly', username)
86 log.info('user %s authenticated correctly', username)
87 return True
87 return True
88 else:
88 else:
89 log.error('user %s is disabled', username)
89 log.error('user %s is disabled', username)
90
90
91 return False
91 return False
92
92
93 class AuthUser(object):
93 class AuthUser(object):
94 """
94 """
95 A simple object that handles a mercurial username for authentication
95 A simple object that handles a mercurial username for authentication
96 """
96 """
97 def __init__(self):
97 def __init__(self):
98 self.username = 'None'
98 self.username = 'None'
99 self.name = ''
99 self.name = ''
100 self.lastname = ''
100 self.lastname = ''
101 self.email = ''
101 self.email = ''
102 self.user_id = None
102 self.user_id = None
103 self.is_authenticated = False
103 self.is_authenticated = False
104 self.is_admin = False
104 self.is_admin = False
105 self.permissions = {}
105 self.permissions = {}
106
106
107 def __repr__(self):
107 def __repr__(self):
108 return "<AuthUser('id:%s:%s')>" % (self.user_id, self.username)
108 return "<AuthUser('id:%s:%s')>" % (self.user_id, self.username)
109
109
110 def set_available_permissions(config):
110 def set_available_permissions(config):
111 """
111 """
112 This function will propagate pylons globals with all available defined
112 This function will propagate pylons globals with all available defined
113 permission given in db. We don't wannt to check each time from db for new
113 permission given in db. We don't wannt to check each time from db for new
114 permissions since adding a new permission also requires application restart
114 permissions since adding a new permission also requires application restart
115 ie. to decorate new views with the newly created permission
115 ie. to decorate new views with the newly created permission
116 :param config:
116 :param config:
117 """
117 """
118 log.info('getting information about all available permissions')
118 log.info('getting information about all available permissions')
119 try:
119 try:
120 sa = meta.Session()
120 sa = meta.Session()
121 all_perms = sa.query(Permission).all()
121 all_perms = sa.query(Permission).all()
122 except:
122 except:
123 pass
123 pass
124 finally:
124 finally:
125 meta.Session.remove()
125 meta.Session.remove()
126
126
127 config['available_permissions'] = [x.permission_name for x in all_perms]
127 config['available_permissions'] = [x.permission_name for x in all_perms]
128
128
129 def set_base_path(config):
129 def set_base_path(config):
130 config['base_path'] = config['pylons.app_globals'].base_path
130 config['base_path'] = config['pylons.app_globals'].base_path
131
131
132
132
133 def fill_perms(user):
133 def fill_perms(user):
134 """
134 """
135 Fills user permission attribute with permissions taken from database
135 Fills user permission attribute with permissions taken from database
136 :param user:
136 :param user:
137 """
137 """
138
138
139 sa = meta.Session()
139 sa = meta.Session()
140 user.permissions['repositories'] = {}
140 user.permissions['repositories'] = {}
141 user.permissions['global'] = set()
141 user.permissions['global'] = set()
142
142
143 #===========================================================================
143 #===========================================================================
144 # fetch default permissions
144 # fetch default permissions
145 #===========================================================================
145 #===========================================================================
146 default_user = UserModel(sa).get_by_username('default', cache=True)
146 default_user = UserModel(sa).get_by_username('default', cache=True)
147
147
148 default_perms = sa.query(RepoToPerm, Repository, Permission)\
148 default_perms = sa.query(RepoToPerm, Repository, Permission)\
149 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
149 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
150 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
150 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
151 .filter(RepoToPerm.user == default_user).all()
151 .filter(RepoToPerm.user == default_user).all()
152
152
153 if user.is_admin:
153 if user.is_admin:
154 #=======================================================================
154 #=======================================================================
155 # #admin have all default rights set to admin
155 # #admin have all default rights set to admin
156 #=======================================================================
156 #=======================================================================
157 user.permissions['global'].add('hg.admin')
157 user.permissions['global'].add('hg.admin')
158
158
159 for perm in default_perms:
159 for perm in default_perms:
160 p = 'repository.admin'
160 p = 'repository.admin'
161 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
161 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
162
162
163 else:
163 else:
164 #=======================================================================
164 #=======================================================================
165 # set default permissions
165 # set default permissions
166 #=======================================================================
166 #=======================================================================
167
167
168 #default global
168 #default global
169 default_global_perms = sa.query(UserToPerm)\
169 default_global_perms = sa.query(UserToPerm)\
170 .filter(UserToPerm.user == sa.query(User).filter(User.username ==
170 .filter(UserToPerm.user == sa.query(User).filter(User.username ==
171 'default').one())
171 'default').one())
172
172
173 for perm in default_global_perms:
173 for perm in default_global_perms:
174 user.permissions['global'].add(perm.permission.permission_name)
174 user.permissions['global'].add(perm.permission.permission_name)
175
175
176 #default repositories
176 #default repositories
177 for perm in default_perms:
177 for perm in default_perms:
178 if perm.Repository.private and not perm.Repository.user_id == user.user_id:
178 if perm.Repository.private and not perm.Repository.user_id == user.user_id:
179 #disable defaults for private repos,
179 #disable defaults for private repos,
180 p = 'repository.none'
180 p = 'repository.none'
181 elif perm.Repository.user_id == user.user_id:
181 elif perm.Repository.user_id == user.user_id:
182 #set admin if owner
182 #set admin if owner
183 p = 'repository.admin'
183 p = 'repository.admin'
184 else:
184 else:
185 p = perm.Permission.permission_name
185 p = perm.Permission.permission_name
186
186
187 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
187 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
188
188
189 #=======================================================================
189 #=======================================================================
190 # #overwrite default with user permissions if any
190 # #overwrite default with user permissions if any
191 #=======================================================================
191 #=======================================================================
192 user_perms = sa.query(RepoToPerm, Permission, Repository)\
192 user_perms = sa.query(RepoToPerm, Permission, Repository)\
193 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
193 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
194 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
194 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
195 .filter(RepoToPerm.user_id == user.user_id).all()
195 .filter(RepoToPerm.user_id == user.user_id).all()
196
196
197 for perm in user_perms:
197 for perm in user_perms:
198 if perm.Repository.user_id == user.user_id:#set admin if owner
198 if perm.Repository.user_id == user.user_id:#set admin if owner
199 p = 'repository.admin'
199 p = 'repository.admin'
200 else:
200 else:
201 p = perm.Permission.permission_name
201 p = perm.Permission.permission_name
202 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
202 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
203 meta.Session.remove()
203 meta.Session.remove()
204 return user
204 return user
205
205
206 def get_user(session):
206 def get_user(session):
207 """
207 """
208 Gets user from session, and wraps permissions into user
208 Gets user from session, and wraps permissions into user
209 :param session:
209 :param session:
210 """
210 """
211 user = session.get('rhodecode_user', AuthUser())
211 user = session.get('rhodecode_user', AuthUser())
212
213
214 #if the user is not logged in we check for anonymous access
212 #if the user is not logged in we check for anonymous access
215 #if user is logged and it's a default user check if we still have anonymous
213 #if user is logged and it's a default user check if we still have anonymous
216 #access enabled
214 #access enabled
217 if user.user_id is None or user.username == 'default':
215 if user.user_id is None or user.username == 'default':
218 anonymous_user = UserModel().get_by_username('default', cache=True)
216 anonymous_user = UserModel().get_by_username('default', cache=True)
219 if anonymous_user.active is True:
217 if anonymous_user.active is True:
220 #then we set this user is logged in
218 #then we set this user is logged in
221 user.is_authenticated = True
219 user.is_authenticated = True
220 user.user_id = anonymous_user.user_id
222 else:
221 else:
223 user.is_authenticated = False
222 user.is_authenticated = False
224
223
225 if user.is_authenticated:
224 if user.is_authenticated:
226 user = UserModel().fill_data(user)
225 user = UserModel().fill_data(user)
227
226
228 user = fill_perms(user)
227 user = fill_perms(user)
229 session['rhodecode_user'] = user
228 session['rhodecode_user'] = user
230 session.save()
229 session.save()
231 return user
230 return user
232
231
233 #===============================================================================
232 #===============================================================================
234 # CHECK DECORATORS
233 # CHECK DECORATORS
235 #===============================================================================
234 #===============================================================================
236 class LoginRequired(object):
235 class LoginRequired(object):
237 """Must be logged in to execute this function else redirect to login page"""
236 """Must be logged in to execute this function else redirect to login page"""
238
237
239 def __call__(self, func):
238 def __call__(self, func):
240 return decorator(self.__wrapper, func)
239 return decorator(self.__wrapper, func)
241
240
242 def __wrapper(self, func, *fargs, **fkwargs):
241 def __wrapper(self, func, *fargs, **fkwargs):
243 user = session.get('rhodecode_user', AuthUser())
242 user = session.get('rhodecode_user', AuthUser())
244 log.debug('Checking login required for user:%s', user.username)
243 log.debug('Checking login required for user:%s', user.username)
245 if user.is_authenticated:
244 if user.is_authenticated:
246 log.debug('user %s is authenticated', user.username)
245 log.debug('user %s is authenticated', user.username)
247 return func(*fargs, **fkwargs)
246 return func(*fargs, **fkwargs)
248 else:
247 else:
249 log.warn('user %s not authenticated', user.username)
248 log.warn('user %s not authenticated', user.username)
250
249
251 p = ''
250 p = ''
252 if request.environ.get('SCRIPT_NAME') != '/':
251 if request.environ.get('SCRIPT_NAME') != '/':
253 p += request.environ.get('SCRIPT_NAME')
252 p += request.environ.get('SCRIPT_NAME')
254
253
255 p += request.environ.get('PATH_INFO')
254 p += request.environ.get('PATH_INFO')
256 if request.environ.get('QUERY_STRING'):
255 if request.environ.get('QUERY_STRING'):
257 p += '?' + request.environ.get('QUERY_STRING')
256 p += '?' + request.environ.get('QUERY_STRING')
258
257
259 log.debug('redirecting to login page with %s', p)
258 log.debug('redirecting to login page with %s', p)
260 return redirect(url('login_home', came_from=p))
259 return redirect(url('login_home', came_from=p))
261
260
262 class PermsDecorator(object):
261 class PermsDecorator(object):
263 """Base class for decorators"""
262 """Base class for decorators"""
264
263
265 def __init__(self, *required_perms):
264 def __init__(self, *required_perms):
266 available_perms = config['available_permissions']
265 available_perms = config['available_permissions']
267 for perm in required_perms:
266 for perm in required_perms:
268 if perm not in available_perms:
267 if perm not in available_perms:
269 raise Exception("'%s' permission is not defined" % perm)
268 raise Exception("'%s' permission is not defined" % perm)
270 self.required_perms = set(required_perms)
269 self.required_perms = set(required_perms)
271 self.user_perms = None
270 self.user_perms = None
272
271
273 def __call__(self, func):
272 def __call__(self, func):
274 return decorator(self.__wrapper, func)
273 return decorator(self.__wrapper, func)
275
274
276
275
277 def __wrapper(self, func, *fargs, **fkwargs):
276 def __wrapper(self, func, *fargs, **fkwargs):
278 # _wrapper.__name__ = func.__name__
277 # _wrapper.__name__ = func.__name__
279 # _wrapper.__dict__.update(func.__dict__)
278 # _wrapper.__dict__.update(func.__dict__)
280 # _wrapper.__doc__ = func.__doc__
279 # _wrapper.__doc__ = func.__doc__
281 self.user = session.get('rhodecode_user', AuthUser())
280 self.user = session.get('rhodecode_user', AuthUser())
282 self.user_perms = self.user.permissions
281 self.user_perms = self.user.permissions
283 log.debug('checking %s permissions %s for %s %s',
282 log.debug('checking %s permissions %s for %s %s',
284 self.__class__.__name__, self.required_perms, func.__name__,
283 self.__class__.__name__, self.required_perms, func.__name__,
285 self.user)
284 self.user)
286
285
287 if self.check_permissions():
286 if self.check_permissions():
288 log.debug('Permission granted for %s %s', func.__name__, self.user)
287 log.debug('Permission granted for %s %s', func.__name__, self.user)
289
288
290 return func(*fargs, **fkwargs)
289 return func(*fargs, **fkwargs)
291
290
292 else:
291 else:
293 log.warning('Permission denied for %s %s', func.__name__, self.user)
292 log.warning('Permission denied for %s %s', func.__name__, self.user)
294 #redirect with forbidden ret code
293 #redirect with forbidden ret code
295 return abort(403)
294 return abort(403)
296
295
297
296
298
297
299 def check_permissions(self):
298 def check_permissions(self):
300 """Dummy function for overriding"""
299 """Dummy function for overriding"""
301 raise Exception('You have to write this function in child class')
300 raise Exception('You have to write this function in child class')
302
301
303 class HasPermissionAllDecorator(PermsDecorator):
302 class HasPermissionAllDecorator(PermsDecorator):
304 """Checks for access permission for all given predicates. All of them
303 """Checks for access permission for all given predicates. All of them
305 have to be meet in order to fulfill the request
304 have to be meet in order to fulfill the request
306 """
305 """
307
306
308 def check_permissions(self):
307 def check_permissions(self):
309 if self.required_perms.issubset(self.user_perms.get('global')):
308 if self.required_perms.issubset(self.user_perms.get('global')):
310 return True
309 return True
311 return False
310 return False
312
311
313
312
314 class HasPermissionAnyDecorator(PermsDecorator):
313 class HasPermissionAnyDecorator(PermsDecorator):
315 """Checks for access permission for any of given predicates. In order to
314 """Checks for access permission for any of given predicates. In order to
316 fulfill the request any of predicates must be meet
315 fulfill the request any of predicates must be meet
317 """
316 """
318
317
319 def check_permissions(self):
318 def check_permissions(self):
320 if self.required_perms.intersection(self.user_perms.get('global')):
319 if self.required_perms.intersection(self.user_perms.get('global')):
321 return True
320 return True
322 return False
321 return False
323
322
324 class HasRepoPermissionAllDecorator(PermsDecorator):
323 class HasRepoPermissionAllDecorator(PermsDecorator):
325 """Checks for access permission for all given predicates for specific
324 """Checks for access permission for all given predicates for specific
326 repository. All of them have to be meet in order to fulfill the request
325 repository. All of them have to be meet in order to fulfill the request
327 """
326 """
328
327
329 def check_permissions(self):
328 def check_permissions(self):
330 repo_name = get_repo_slug(request)
329 repo_name = get_repo_slug(request)
331 try:
330 try:
332 user_perms = set([self.user_perms['repositories'][repo_name]])
331 user_perms = set([self.user_perms['repositories'][repo_name]])
333 except KeyError:
332 except KeyError:
334 return False
333 return False
335 if self.required_perms.issubset(user_perms):
334 if self.required_perms.issubset(user_perms):
336 return True
335 return True
337 return False
336 return False
338
337
339
338
340 class HasRepoPermissionAnyDecorator(PermsDecorator):
339 class HasRepoPermissionAnyDecorator(PermsDecorator):
341 """Checks for access permission for any of given predicates for specific
340 """Checks for access permission for any of given predicates for specific
342 repository. In order to fulfill the request any of predicates must be meet
341 repository. In order to fulfill the request any of predicates must be meet
343 """
342 """
344
343
345 def check_permissions(self):
344 def check_permissions(self):
346 repo_name = get_repo_slug(request)
345 repo_name = get_repo_slug(request)
347
346
348 try:
347 try:
349 user_perms = set([self.user_perms['repositories'][repo_name]])
348 user_perms = set([self.user_perms['repositories'][repo_name]])
350 except KeyError:
349 except KeyError:
351 return False
350 return False
352 if self.required_perms.intersection(user_perms):
351 if self.required_perms.intersection(user_perms):
353 return True
352 return True
354 return False
353 return False
355 #===============================================================================
354 #===============================================================================
356 # CHECK FUNCTIONS
355 # CHECK FUNCTIONS
357 #===============================================================================
356 #===============================================================================
358
357
359 class PermsFunction(object):
358 class PermsFunction(object):
360 """Base function for other check functions"""
359 """Base function for other check functions"""
361
360
362 def __init__(self, *perms):
361 def __init__(self, *perms):
363 available_perms = config['available_permissions']
362 available_perms = config['available_permissions']
364
363
365 for perm in perms:
364 for perm in perms:
366 if perm not in available_perms:
365 if perm not in available_perms:
367 raise Exception("'%s' permission in not defined" % perm)
366 raise Exception("'%s' permission in not defined" % perm)
368 self.required_perms = set(perms)
367 self.required_perms = set(perms)
369 self.user_perms = None
368 self.user_perms = None
370 self.granted_for = ''
369 self.granted_for = ''
371 self.repo_name = None
370 self.repo_name = None
372
371
373 def __call__(self, check_Location=''):
372 def __call__(self, check_Location=''):
374 user = session.get('rhodecode_user', False)
373 user = session.get('rhodecode_user', False)
375 if not user:
374 if not user:
376 return False
375 return False
377 self.user_perms = user.permissions
376 self.user_perms = user.permissions
378 self.granted_for = user.username
377 self.granted_for = user.username
379 log.debug('checking %s %s %s', self.__class__.__name__,
378 log.debug('checking %s %s %s', self.__class__.__name__,
380 self.required_perms, user)
379 self.required_perms, user)
381
380
382 if self.check_permissions():
381 if self.check_permissions():
383 log.debug('Permission granted for %s @ %s %s', self.granted_for,
382 log.debug('Permission granted for %s @ %s %s', self.granted_for,
384 check_Location, user)
383 check_Location, user)
385 return True
384 return True
386
385
387 else:
386 else:
388 log.warning('Permission denied for %s @ %s %s', self.granted_for,
387 log.warning('Permission denied for %s @ %s %s', self.granted_for,
389 check_Location, user)
388 check_Location, user)
390 return False
389 return False
391
390
392 def check_permissions(self):
391 def check_permissions(self):
393 """Dummy function for overriding"""
392 """Dummy function for overriding"""
394 raise Exception('You have to write this function in child class')
393 raise Exception('You have to write this function in child class')
395
394
396 class HasPermissionAll(PermsFunction):
395 class HasPermissionAll(PermsFunction):
397 def check_permissions(self):
396 def check_permissions(self):
398 if self.required_perms.issubset(self.user_perms.get('global')):
397 if self.required_perms.issubset(self.user_perms.get('global')):
399 return True
398 return True
400 return False
399 return False
401
400
402 class HasPermissionAny(PermsFunction):
401 class HasPermissionAny(PermsFunction):
403 def check_permissions(self):
402 def check_permissions(self):
404 if self.required_perms.intersection(self.user_perms.get('global')):
403 if self.required_perms.intersection(self.user_perms.get('global')):
405 return True
404 return True
406 return False
405 return False
407
406
408 class HasRepoPermissionAll(PermsFunction):
407 class HasRepoPermissionAll(PermsFunction):
409
408
410 def __call__(self, repo_name=None, check_Location=''):
409 def __call__(self, repo_name=None, check_Location=''):
411 self.repo_name = repo_name
410 self.repo_name = repo_name
412 return super(HasRepoPermissionAll, self).__call__(check_Location)
411 return super(HasRepoPermissionAll, self).__call__(check_Location)
413
412
414 def check_permissions(self):
413 def check_permissions(self):
415 if not self.repo_name:
414 if not self.repo_name:
416 self.repo_name = get_repo_slug(request)
415 self.repo_name = get_repo_slug(request)
417
416
418 try:
417 try:
419 self.user_perms = set([self.user_perms['repositories']\
418 self.user_perms = set([self.user_perms['repositories']\
420 [self.repo_name]])
419 [self.repo_name]])
421 except KeyError:
420 except KeyError:
422 return False
421 return False
423 self.granted_for = self.repo_name
422 self.granted_for = self.repo_name
424 if self.required_perms.issubset(self.user_perms):
423 if self.required_perms.issubset(self.user_perms):
425 return True
424 return True
426 return False
425 return False
427
426
428 class HasRepoPermissionAny(PermsFunction):
427 class HasRepoPermissionAny(PermsFunction):
429
428
430 def __call__(self, repo_name=None, check_Location=''):
429 def __call__(self, repo_name=None, check_Location=''):
431 self.repo_name = repo_name
430 self.repo_name = repo_name
432 return super(HasRepoPermissionAny, self).__call__(check_Location)
431 return super(HasRepoPermissionAny, self).__call__(check_Location)
433
432
434 def check_permissions(self):
433 def check_permissions(self):
435 if not self.repo_name:
434 if not self.repo_name:
436 self.repo_name = get_repo_slug(request)
435 self.repo_name = get_repo_slug(request)
437
436
438 try:
437 try:
439 self.user_perms = set([self.user_perms['repositories']\
438 self.user_perms = set([self.user_perms['repositories']\
440 [self.repo_name]])
439 [self.repo_name]])
441 except KeyError:
440 except KeyError:
442 return False
441 return False
443 self.granted_for = self.repo_name
442 self.granted_for = self.repo_name
444 if self.required_perms.intersection(self.user_perms):
443 if self.required_perms.intersection(self.user_perms):
445 return True
444 return True
446 return False
445 return False
447
446
448 #===============================================================================
447 #===============================================================================
449 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
448 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
450 #===============================================================================
449 #===============================================================================
451
450
452 class HasPermissionAnyMiddleware(object):
451 class HasPermissionAnyMiddleware(object):
453 def __init__(self, *perms):
452 def __init__(self, *perms):
454 self.required_perms = set(perms)
453 self.required_perms = set(perms)
455
454
456 def __call__(self, user, repo_name):
455 def __call__(self, user, repo_name):
457 usr = AuthUser()
456 usr = AuthUser()
458 usr.user_id = user.user_id
457 usr.user_id = user.user_id
459 usr.username = user.username
458 usr.username = user.username
460 usr.is_admin = user.admin
459 usr.is_admin = user.admin
461
460
462 try:
461 try:
463 self.user_perms = set([fill_perms(usr)\
462 self.user_perms = set([fill_perms(usr)\
464 .permissions['repositories'][repo_name]])
463 .permissions['repositories'][repo_name]])
465 except:
464 except:
466 self.user_perms = set()
465 self.user_perms = set()
467 self.granted_for = ''
466 self.granted_for = ''
468 self.username = user.username
467 self.username = user.username
469 self.repo_name = repo_name
468 self.repo_name = repo_name
470 return self.check_permissions()
469 return self.check_permissions()
471
470
472 def check_permissions(self):
471 def check_permissions(self):
473 log.debug('checking mercurial protocol '
472 log.debug('checking mercurial protocol '
474 'permissions for user:%s repository:%s',
473 'permissions for user:%s repository:%s',
475 self.username, self.repo_name)
474 self.username, self.repo_name)
476 if self.required_perms.intersection(self.user_perms):
475 if self.required_perms.intersection(self.user_perms):
477 log.debug('permission granted')
476 log.debug('permission granted')
478 return True
477 return True
479 log.debug('permission denied')
478 log.debug('permission denied')
480 return False
479 return False
@@ -1,166 +1,171 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # Model for users
3 # Model for users
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5 #
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20 """
20 """
21 Created on April 9, 2010
21 Created on April 9, 2010
22 Model for users
22 Model for users
23 :author: marcink
23 :author: marcink
24 """
24 """
25
25
26 from pylons.i18n.translation import _
26 from pylons.i18n.translation import _
27 from rhodecode.model.caching_query import FromCache
27 from rhodecode.model.caching_query import FromCache
28 from rhodecode.model.db import User
28 from rhodecode.model.db import User
29 from rhodecode.model.meta import Session
29 from rhodecode.model.meta import Session
30 import logging
30 import logging
31 import traceback
31 import traceback
32
32
33 log = logging.getLogger(__name__)
33 log = logging.getLogger(__name__)
34
34
35 class DefaultUserException(Exception):pass
35 class DefaultUserException(Exception):pass
36
36
37 class UserModel(object):
37 class UserModel(object):
38
38
39 def __init__(self, sa=None):
39 def __init__(self, sa=None):
40 if not sa:
40 if not sa:
41 self.sa = Session()
41 self.sa = Session()
42 else:
42 else:
43 self.sa = sa
43 self.sa = sa
44
44
45 def get(self, user_id, cache=False):
45 def get(self, user_id, cache=False):
46 user = self.sa.query(User)
46 user = self.sa.query(User)
47 if cache:
47 if cache:
48 user = user.options(FromCache("sql_cache_short",
48 user = user.options(FromCache("sql_cache_short",
49 "get_user_%s" % user_id))
49 "get_user_%s" % user_id))
50 return user.get(user_id)
50 return user.get(user_id)
51
51
52
52
53 def get_by_username(self, username, cache=False):
53 def get_by_username(self, username, cache=False):
54 user = self.sa.query(User)\
54 user = self.sa.query(User)\
55 .filter(User.username == username)
55 .filter(User.username == username)
56 if cache:
56 if cache:
57 user = user.options(FromCache("sql_cache_short",
57 user = user.options(FromCache("sql_cache_short",
58 "get_user_%s" % username))
58 "get_user_%s" % username))
59 return user.scalar()
59 return user.scalar()
60
60
61 def create(self, form_data):
61 def create(self, form_data):
62 try:
62 try:
63 new_user = User()
63 new_user = User()
64 for k, v in form_data.items():
64 for k, v in form_data.items():
65 setattr(new_user, k, v)
65 setattr(new_user, k, v)
66
66
67 self.sa.add(new_user)
67 self.sa.add(new_user)
68 self.sa.commit()
68 self.sa.commit()
69 except:
69 except:
70 log.error(traceback.format_exc())
70 log.error(traceback.format_exc())
71 self.sa.rollback()
71 self.sa.rollback()
72 raise
72 raise
73
73
74 def create_registration(self, form_data):
74 def create_registration(self, form_data):
75 try:
75 try:
76 new_user = User()
76 new_user = User()
77 for k, v in form_data.items():
77 for k, v in form_data.items():
78 if k != 'admin':
78 if k != 'admin':
79 setattr(new_user, k, v)
79 setattr(new_user, k, v)
80
80
81 self.sa.add(new_user)
81 self.sa.add(new_user)
82 self.sa.commit()
82 self.sa.commit()
83 except:
83 except:
84 log.error(traceback.format_exc())
84 log.error(traceback.format_exc())
85 self.sa.rollback()
85 self.sa.rollback()
86 raise
86 raise
87
87
88 def update(self, user_id, form_data):
88 def update(self, user_id, form_data):
89 try:
89 try:
90 new_user = self.get(user_id, cache=False)
90 new_user = self.get(user_id, cache=False)
91 if new_user.username == 'default':
91 if new_user.username == 'default':
92 raise DefaultUserException(
92 raise DefaultUserException(
93 _("You can't Edit this user since it's"
93 _("You can't Edit this user since it's"
94 " crucial for entire application"))
94 " crucial for entire application"))
95 for k, v in form_data.items():
95 for k, v in form_data.items():
96 if k == 'new_password' and v != '':
96 if k == 'new_password' and v != '':
97 new_user.password = v
97 new_user.password = v
98 else:
98 else:
99 setattr(new_user, k, v)
99 setattr(new_user, k, v)
100
100
101 self.sa.add(new_user)
101 self.sa.add(new_user)
102 self.sa.commit()
102 self.sa.commit()
103 except:
103 except:
104 log.error(traceback.format_exc())
104 log.error(traceback.format_exc())
105 self.sa.rollback()
105 self.sa.rollback()
106 raise
106 raise
107
107
108 def update_my_account(self, user_id, form_data):
108 def update_my_account(self, user_id, form_data):
109 try:
109 try:
110 new_user = self.get(user_id, cache=False)
110 new_user = self.get(user_id, cache=False)
111 if new_user.username == 'default':
111 if new_user.username == 'default':
112 raise DefaultUserException(
112 raise DefaultUserException(
113 _("You can't Edit this user since it's"
113 _("You can't Edit this user since it's"
114 " crucial for entire application"))
114 " crucial for entire application"))
115 for k, v in form_data.items():
115 for k, v in form_data.items():
116 if k == 'new_password' and v != '':
116 if k == 'new_password' and v != '':
117 new_user.password = v
117 new_user.password = v
118 else:
118 else:
119 if k not in ['admin', 'active']:
119 if k not in ['admin', 'active']:
120 setattr(new_user, k, v)
120 setattr(new_user, k, v)
121
121
122 self.sa.add(new_user)
122 self.sa.add(new_user)
123 self.sa.commit()
123 self.sa.commit()
124 except:
124 except:
125 log.error(traceback.format_exc())
125 log.error(traceback.format_exc())
126 self.sa.rollback()
126 self.sa.rollback()
127 raise
127 raise
128
128
129 def delete(self, user_id):
129 def delete(self, user_id):
130 try:
130 try:
131 user = self.get(user_id, cache=False)
131 user = self.get(user_id, cache=False)
132 if user.username == 'default':
132 if user.username == 'default':
133 raise DefaultUserException(
133 raise DefaultUserException(
134 _("You can't remove this user since it's"
134 _("You can't remove this user since it's"
135 " crucial for entire application"))
135 " crucial for entire application"))
136 self.sa.delete(user)
136 self.sa.delete(user)
137 self.sa.commit()
137 self.sa.commit()
138 except:
138 except:
139 log.error(traceback.format_exc())
139 log.error(traceback.format_exc())
140 self.sa.rollback()
140 self.sa.rollback()
141 raise
141 raise
142
142
143 def reset_password(self, data):
143 def reset_password(self, data):
144 from rhodecode.lib.celerylib import tasks, run_task
144 from rhodecode.lib.celerylib import tasks, run_task
145 run_task(tasks.reset_user_password, data['email'])
145 run_task(tasks.reset_user_password, data['email'])
146
146
147
147
148 def fill_data(self, user):
148 def fill_data(self, user):
149 """
149 """
150 Fills user data with those from database and log out user if not
150 Fills user data with those from database and log out user if not
151 present in database
151 present in database
152 :param user:
152 :param user:
153 """
153 """
154
155 if not hasattr(user, 'user_id') or user.user_id is None:
156 raise Exception('passed in user has to have the user_id attribute')
157
158
154 log.debug('filling auth user data')
159 log.debug('filling auth user data')
155 try:
160 try:
156 dbuser = self.get(user.user_id)
161 dbuser = self.get(user.user_id)
157 user.username = dbuser.username
162 user.username = dbuser.username
158 user.is_admin = dbuser.admin
163 user.is_admin = dbuser.admin
159 user.name = dbuser.name
164 user.name = dbuser.name
160 user.lastname = dbuser.lastname
165 user.lastname = dbuser.lastname
161 user.email = dbuser.email
166 user.email = dbuser.email
162 except:
167 except:
163 log.error(traceback.format_exc())
168 log.error(traceback.format_exc())
164 user.is_authenticated = False
169 user.is_authenticated = False
165
170
166 return user
171 return user
General Comments 0
You need to be logged in to leave comments. Login now