##// END OF EJS Templates
#78, fixed more reliable case insensitive searches
marcink -
r742:1377a9d4 beta
parent child Browse files
Show More
@@ -1,534 +1,536 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.exceptions import *
27 from rhodecode.lib.exceptions import *
28 from rhodecode.lib.utils import get_repo_slug
28 from rhodecode.lib.utils import get_repo_slug
29 from rhodecode.lib.auth_ldap import AuthLdap
29 from rhodecode.lib.auth_ldap import AuthLdap
30 from rhodecode.model import meta
30 from rhodecode.model import meta
31 from rhodecode.model.user import UserModel
31 from rhodecode.model.user import UserModel
32 from rhodecode.model.caching_query import FromCache
32 from rhodecode.model.caching_query import FromCache
33 from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
33 from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
34 UserToPerm
34 UserToPerm
35 import bcrypt
35 import bcrypt
36 from decorator import decorator
36 from decorator import decorator
37 import logging
37 import logging
38 import random
38 import random
39 import traceback
39 import traceback
40
40
41 log = logging.getLogger(__name__)
41 log = logging.getLogger(__name__)
42
42
43 class PasswordGenerator(object):
43 class PasswordGenerator(object):
44 """This is a simple class for generating password from
44 """This is a simple class for generating password from
45 different sets of characters
45 different sets of characters
46 usage:
46 usage:
47 passwd_gen = PasswordGenerator()
47 passwd_gen = PasswordGenerator()
48 #print 8-letter password containing only big and small letters of alphabet
48 #print 8-letter password containing only big and small letters of alphabet
49 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
49 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
50 """
50 """
51 ALPHABETS_NUM = r'''1234567890'''#[0]
51 ALPHABETS_NUM = r'''1234567890'''#[0]
52 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''#[1]
52 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''#[1]
53 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''#[2]
53 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''#[2]
54 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' #[3]
54 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' #[3]
55 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_SPECIAL#[4]
55 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_SPECIAL#[4]
56 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM#[5]
56 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM#[5]
57 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
57 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
58 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
58 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
59 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
59 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
60
60
61 def __init__(self, passwd=''):
61 def __init__(self, passwd=''):
62 self.passwd = passwd
62 self.passwd = passwd
63
63
64 def gen_password(self, len, type):
64 def gen_password(self, len, type):
65 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
65 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
66 return self.passwd
66 return self.passwd
67
67
68
68
69 def get_crypt_password(password):
69 def get_crypt_password(password):
70 """Cryptographic function used for password hashing based on sha1
70 """Cryptographic function used for password hashing based on sha1
71 :param password: password to hash
71 :param password: password to hash
72 """
72 """
73 return bcrypt.hashpw(password, bcrypt.gensalt(10))
73 return bcrypt.hashpw(password, bcrypt.gensalt(10))
74
74
75 def check_password(password, hashed):
75 def check_password(password, hashed):
76 return bcrypt.hashpw(password, hashed) == hashed
76 return bcrypt.hashpw(password, hashed) == hashed
77
77
78 def authfunc(environ, username, password):
78 def authfunc(environ, username, password):
79 """
79 """
80 Authentication function used in Mercurial/Git/ and access control,
80 Authentication function used in Mercurial/Git/ and access control,
81 firstly checks for db authentication then if ldap is enabled for ldap
81 firstly checks for db authentication then if ldap is enabled for ldap
82 authentication, also creates ldap user if not in database
82 authentication, also creates ldap user if not in database
83
83
84 :param environ: needed only for using in Basic auth, can be None
84 :param environ: needed only for using in Basic auth, can be None
85 :param username: username
85 :param username: username
86 :param password: password
86 :param password: password
87 """
87 """
88 user_model = UserModel()
88 user_model = UserModel()
89 user = user_model.get_by_username(username, cache=False)
89 user = user_model.get_by_username(username, cache=False)
90
90
91 if user is not None and user.is_ldap is False:
91 if user is not None and user.is_ldap is False:
92 if user.active:
92 if user.active:
93
93
94 if user.username == 'default' and user.active:
94 if user.username == 'default' and user.active:
95 log.info('user %s authenticated correctly', username)
95 log.info('user %s authenticated correctly', username)
96 return True
96 return True
97
97
98 elif user.username == username and check_password(password, user.password):
98 elif user.username == username and check_password(password, user.password):
99 log.info('user %s authenticated correctly', username)
99 log.info('user %s authenticated correctly', username)
100 return True
100 return True
101 else:
101 else:
102 log.error('user %s is disabled', username)
102 log.error('user %s is disabled', username)
103
103
104
104
105 else:
105 else:
106
106
107 #since ldap is searching in case insensitive check if this user is still
107 #since ldap is searching in case insensitive check if this user is still
108 #not in our system
108 #not in our system
109 username = username.lower()
109 username = username.lower()
110 if user_model.get_by_username(username, cache=False) is not None:
110 user_obj = user_model.get_by_username(username, cache=False,
111 case_insensitive=True)
112 if user_obj is not None:
111 return False
113 return False
112
114
113 from rhodecode.model.settings import SettingsModel
115 from rhodecode.model.settings import SettingsModel
114 ldap_settings = SettingsModel().get_ldap_settings()
116 ldap_settings = SettingsModel().get_ldap_settings()
115
117
116 #======================================================================
118 #======================================================================
117 # FALLBACK TO LDAP AUTH IN ENABLE
119 # FALLBACK TO LDAP AUTH IN ENABLE
118 #======================================================================
120 #======================================================================
119 if ldap_settings.get('ldap_active', False):
121 if ldap_settings.get('ldap_active', False):
120
122
121 kwargs = {
123 kwargs = {
122 'server':ldap_settings.get('ldap_host', ''),
124 'server':ldap_settings.get('ldap_host', ''),
123 'base_dn':ldap_settings.get('ldap_base_dn', ''),
125 'base_dn':ldap_settings.get('ldap_base_dn', ''),
124 'port':ldap_settings.get('ldap_port'),
126 'port':ldap_settings.get('ldap_port'),
125 'bind_dn':ldap_settings.get('ldap_dn_user'),
127 'bind_dn':ldap_settings.get('ldap_dn_user'),
126 'bind_pass':ldap_settings.get('ldap_dn_pass'),
128 'bind_pass':ldap_settings.get('ldap_dn_pass'),
127 'use_ldaps':ldap_settings.get('ldap_ldaps'),
129 'use_ldaps':ldap_settings.get('ldap_ldaps'),
128 'ldap_version':3,
130 'ldap_version':3,
129 }
131 }
130 log.debug('Checking for ldap authentication')
132 log.debug('Checking for ldap authentication')
131 try:
133 try:
132 aldap = AuthLdap(**kwargs)
134 aldap = AuthLdap(**kwargs)
133 res = aldap.authenticate_ldap(username, password)
135 res = aldap.authenticate_ldap(username, password)
134
136
135 authenticated = res[1]['uid'][0] == username
137 authenticated = res[1]['uid'][0] == username
136
138
137 if authenticated and user_model.create_ldap(username, password):
139 if authenticated and user_model.create_ldap(username, password):
138 log.info('created new ldap user')
140 log.info('created new ldap user')
139
141
140 return authenticated
142 return authenticated
141 except (LdapUsernameError, LdapPasswordError):
143 except (LdapUsernameError, LdapPasswordError):
142 return False
144 return False
143 except:
145 except:
144 log.error(traceback.format_exc())
146 log.error(traceback.format_exc())
145 return False
147 return False
146 return False
148 return False
147
149
148 class AuthUser(object):
150 class AuthUser(object):
149 """
151 """
150 A simple object that handles a mercurial username for authentication
152 A simple object that handles a mercurial username for authentication
151 """
153 """
152 def __init__(self):
154 def __init__(self):
153 self.username = 'None'
155 self.username = 'None'
154 self.name = ''
156 self.name = ''
155 self.lastname = ''
157 self.lastname = ''
156 self.email = ''
158 self.email = ''
157 self.user_id = None
159 self.user_id = None
158 self.is_authenticated = False
160 self.is_authenticated = False
159 self.is_admin = False
161 self.is_admin = False
160 self.permissions = {}
162 self.permissions = {}
161
163
162 def __repr__(self):
164 def __repr__(self):
163 return "<AuthUser('id:%s:%s')>" % (self.user_id, self.username)
165 return "<AuthUser('id:%s:%s')>" % (self.user_id, self.username)
164
166
165 def set_available_permissions(config):
167 def set_available_permissions(config):
166 """
168 """
167 This function will propagate pylons globals with all available defined
169 This function will propagate pylons globals with all available defined
168 permission given in db. We don't wannt to check each time from db for new
170 permission given in db. We don't wannt to check each time from db for new
169 permissions since adding a new permission also requires application restart
171 permissions since adding a new permission also requires application restart
170 ie. to decorate new views with the newly created permission
172 ie. to decorate new views with the newly created permission
171 :param config:
173 :param config:
172 """
174 """
173 log.info('getting information about all available permissions')
175 log.info('getting information about all available permissions')
174 try:
176 try:
175 sa = meta.Session()
177 sa = meta.Session()
176 all_perms = sa.query(Permission).all()
178 all_perms = sa.query(Permission).all()
177 except:
179 except:
178 pass
180 pass
179 finally:
181 finally:
180 meta.Session.remove()
182 meta.Session.remove()
181
183
182 config['available_permissions'] = [x.permission_name for x in all_perms]
184 config['available_permissions'] = [x.permission_name for x in all_perms]
183
185
184 def set_base_path(config):
186 def set_base_path(config):
185 config['base_path'] = config['pylons.app_globals'].base_path
187 config['base_path'] = config['pylons.app_globals'].base_path
186
188
187
189
188 def fill_perms(user):
190 def fill_perms(user):
189 """
191 """
190 Fills user permission attribute with permissions taken from database
192 Fills user permission attribute with permissions taken from database
191 :param user:
193 :param user:
192 """
194 """
193
195
194 sa = meta.Session()
196 sa = meta.Session()
195 user.permissions['repositories'] = {}
197 user.permissions['repositories'] = {}
196 user.permissions['global'] = set()
198 user.permissions['global'] = set()
197
199
198 #===========================================================================
200 #===========================================================================
199 # fetch default permissions
201 # fetch default permissions
200 #===========================================================================
202 #===========================================================================
201 default_user = UserModel().get_by_username('default', cache=True)
203 default_user = UserModel().get_by_username('default', cache=True)
202
204
203 default_perms = sa.query(RepoToPerm, Repository, Permission)\
205 default_perms = sa.query(RepoToPerm, Repository, Permission)\
204 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
206 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
205 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
207 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
206 .filter(RepoToPerm.user == default_user).all()
208 .filter(RepoToPerm.user == default_user).all()
207
209
208 if user.is_admin:
210 if user.is_admin:
209 #=======================================================================
211 #=======================================================================
210 # #admin have all default rights set to admin
212 # #admin have all default rights set to admin
211 #=======================================================================
213 #=======================================================================
212 user.permissions['global'].add('hg.admin')
214 user.permissions['global'].add('hg.admin')
213
215
214 for perm in default_perms:
216 for perm in default_perms:
215 p = 'repository.admin'
217 p = 'repository.admin'
216 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
218 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
217
219
218 else:
220 else:
219 #=======================================================================
221 #=======================================================================
220 # set default permissions
222 # set default permissions
221 #=======================================================================
223 #=======================================================================
222
224
223 #default global
225 #default global
224 default_global_perms = sa.query(UserToPerm)\
226 default_global_perms = sa.query(UserToPerm)\
225 .filter(UserToPerm.user == sa.query(User)\
227 .filter(UserToPerm.user == sa.query(User)\
226 .filter(User.username == 'default').one())
228 .filter(User.username == 'default').one())
227
229
228 for perm in default_global_perms:
230 for perm in default_global_perms:
229 user.permissions['global'].add(perm.permission.permission_name)
231 user.permissions['global'].add(perm.permission.permission_name)
230
232
231 #default repositories
233 #default repositories
232 for perm in default_perms:
234 for perm in default_perms:
233 if perm.Repository.private and not perm.Repository.user_id == user.user_id:
235 if perm.Repository.private and not perm.Repository.user_id == user.user_id:
234 #disable defaults for private repos,
236 #disable defaults for private repos,
235 p = 'repository.none'
237 p = 'repository.none'
236 elif perm.Repository.user_id == user.user_id:
238 elif perm.Repository.user_id == user.user_id:
237 #set admin if owner
239 #set admin if owner
238 p = 'repository.admin'
240 p = 'repository.admin'
239 else:
241 else:
240 p = perm.Permission.permission_name
242 p = perm.Permission.permission_name
241
243
242 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
244 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
243
245
244 #=======================================================================
246 #=======================================================================
245 # #overwrite default with user permissions if any
247 # #overwrite default with user permissions if any
246 #=======================================================================
248 #=======================================================================
247 user_perms = sa.query(RepoToPerm, Permission, Repository)\
249 user_perms = sa.query(RepoToPerm, Permission, Repository)\
248 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
250 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
249 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
251 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
250 .filter(RepoToPerm.user_id == user.user_id).all()
252 .filter(RepoToPerm.user_id == user.user_id).all()
251
253
252 for perm in user_perms:
254 for perm in user_perms:
253 if perm.Repository.user_id == user.user_id:#set admin if owner
255 if perm.Repository.user_id == user.user_id:#set admin if owner
254 p = 'repository.admin'
256 p = 'repository.admin'
255 else:
257 else:
256 p = perm.Permission.permission_name
258 p = perm.Permission.permission_name
257 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
259 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
258 meta.Session.remove()
260 meta.Session.remove()
259 return user
261 return user
260
262
261 def get_user(session):
263 def get_user(session):
262 """
264 """
263 Gets user from session, and wraps permissions into user
265 Gets user from session, and wraps permissions into user
264 :param session:
266 :param session:
265 """
267 """
266 user = session.get('rhodecode_user', AuthUser())
268 user = session.get('rhodecode_user', AuthUser())
267 #if the user is not logged in we check for anonymous access
269 #if the user is not logged in we check for anonymous access
268 #if user is logged and it's a default user check if we still have anonymous
270 #if user is logged and it's a default user check if we still have anonymous
269 #access enabled
271 #access enabled
270 if user.user_id is None or user.username == 'default':
272 if user.user_id is None or user.username == 'default':
271 anonymous_user = UserModel().get_by_username('default', cache=True)
273 anonymous_user = UserModel().get_by_username('default', cache=True)
272 if anonymous_user.active is True:
274 if anonymous_user.active is True:
273 #then we set this user is logged in
275 #then we set this user is logged in
274 user.is_authenticated = True
276 user.is_authenticated = True
275 user.user_id = anonymous_user.user_id
277 user.user_id = anonymous_user.user_id
276 else:
278 else:
277 user.is_authenticated = False
279 user.is_authenticated = False
278
280
279 if user.is_authenticated:
281 if user.is_authenticated:
280 user = UserModel().fill_data(user)
282 user = UserModel().fill_data(user)
281
283
282 user = fill_perms(user)
284 user = fill_perms(user)
283 session['rhodecode_user'] = user
285 session['rhodecode_user'] = user
284 session.save()
286 session.save()
285 return user
287 return user
286
288
287 #===============================================================================
289 #===============================================================================
288 # CHECK DECORATORS
290 # CHECK DECORATORS
289 #===============================================================================
291 #===============================================================================
290 class LoginRequired(object):
292 class LoginRequired(object):
291 """Must be logged in to execute this function else redirect to login page"""
293 """Must be logged in to execute this function else redirect to login page"""
292
294
293 def __call__(self, func):
295 def __call__(self, func):
294 return decorator(self.__wrapper, func)
296 return decorator(self.__wrapper, func)
295
297
296 def __wrapper(self, func, *fargs, **fkwargs):
298 def __wrapper(self, func, *fargs, **fkwargs):
297 user = session.get('rhodecode_user', AuthUser())
299 user = session.get('rhodecode_user', AuthUser())
298 log.debug('Checking login required for user:%s', user.username)
300 log.debug('Checking login required for user:%s', user.username)
299 if user.is_authenticated:
301 if user.is_authenticated:
300 log.debug('user %s is authenticated', user.username)
302 log.debug('user %s is authenticated', user.username)
301 return func(*fargs, **fkwargs)
303 return func(*fargs, **fkwargs)
302 else:
304 else:
303 log.warn('user %s not authenticated', user.username)
305 log.warn('user %s not authenticated', user.username)
304
306
305 p = ''
307 p = ''
306 if request.environ.get('SCRIPT_NAME') != '/':
308 if request.environ.get('SCRIPT_NAME') != '/':
307 p += request.environ.get('SCRIPT_NAME')
309 p += request.environ.get('SCRIPT_NAME')
308
310
309 p += request.environ.get('PATH_INFO')
311 p += request.environ.get('PATH_INFO')
310 if request.environ.get('QUERY_STRING'):
312 if request.environ.get('QUERY_STRING'):
311 p += '?' + request.environ.get('QUERY_STRING')
313 p += '?' + request.environ.get('QUERY_STRING')
312
314
313 log.debug('redirecting to login page with %s', p)
315 log.debug('redirecting to login page with %s', p)
314 return redirect(url('login_home', came_from=p))
316 return redirect(url('login_home', came_from=p))
315
317
316 class PermsDecorator(object):
318 class PermsDecorator(object):
317 """Base class for decorators"""
319 """Base class for decorators"""
318
320
319 def __init__(self, *required_perms):
321 def __init__(self, *required_perms):
320 available_perms = config['available_permissions']
322 available_perms = config['available_permissions']
321 for perm in required_perms:
323 for perm in required_perms:
322 if perm not in available_perms:
324 if perm not in available_perms:
323 raise Exception("'%s' permission is not defined" % perm)
325 raise Exception("'%s' permission is not defined" % perm)
324 self.required_perms = set(required_perms)
326 self.required_perms = set(required_perms)
325 self.user_perms = None
327 self.user_perms = None
326
328
327 def __call__(self, func):
329 def __call__(self, func):
328 return decorator(self.__wrapper, func)
330 return decorator(self.__wrapper, func)
329
331
330
332
331 def __wrapper(self, func, *fargs, **fkwargs):
333 def __wrapper(self, func, *fargs, **fkwargs):
332 # _wrapper.__name__ = func.__name__
334 # _wrapper.__name__ = func.__name__
333 # _wrapper.__dict__.update(func.__dict__)
335 # _wrapper.__dict__.update(func.__dict__)
334 # _wrapper.__doc__ = func.__doc__
336 # _wrapper.__doc__ = func.__doc__
335 self.user = session.get('rhodecode_user', AuthUser())
337 self.user = session.get('rhodecode_user', AuthUser())
336 self.user_perms = self.user.permissions
338 self.user_perms = self.user.permissions
337 log.debug('checking %s permissions %s for %s %s',
339 log.debug('checking %s permissions %s for %s %s',
338 self.__class__.__name__, self.required_perms, func.__name__,
340 self.__class__.__name__, self.required_perms, func.__name__,
339 self.user)
341 self.user)
340
342
341 if self.check_permissions():
343 if self.check_permissions():
342 log.debug('Permission granted for %s %s', func.__name__, self.user)
344 log.debug('Permission granted for %s %s', func.__name__, self.user)
343
345
344 return func(*fargs, **fkwargs)
346 return func(*fargs, **fkwargs)
345
347
346 else:
348 else:
347 log.warning('Permission denied for %s %s', func.__name__, self.user)
349 log.warning('Permission denied for %s %s', func.__name__, self.user)
348 #redirect with forbidden ret code
350 #redirect with forbidden ret code
349 return abort(403)
351 return abort(403)
350
352
351
353
352
354
353 def check_permissions(self):
355 def check_permissions(self):
354 """Dummy function for overriding"""
356 """Dummy function for overriding"""
355 raise Exception('You have to write this function in child class')
357 raise Exception('You have to write this function in child class')
356
358
357 class HasPermissionAllDecorator(PermsDecorator):
359 class HasPermissionAllDecorator(PermsDecorator):
358 """Checks for access permission for all given predicates. All of them
360 """Checks for access permission for all given predicates. All of them
359 have to be meet in order to fulfill the request
361 have to be meet in order to fulfill the request
360 """
362 """
361
363
362 def check_permissions(self):
364 def check_permissions(self):
363 if self.required_perms.issubset(self.user_perms.get('global')):
365 if self.required_perms.issubset(self.user_perms.get('global')):
364 return True
366 return True
365 return False
367 return False
366
368
367
369
368 class HasPermissionAnyDecorator(PermsDecorator):
370 class HasPermissionAnyDecorator(PermsDecorator):
369 """Checks for access permission for any of given predicates. In order to
371 """Checks for access permission for any of given predicates. In order to
370 fulfill the request any of predicates must be meet
372 fulfill the request any of predicates must be meet
371 """
373 """
372
374
373 def check_permissions(self):
375 def check_permissions(self):
374 if self.required_perms.intersection(self.user_perms.get('global')):
376 if self.required_perms.intersection(self.user_perms.get('global')):
375 return True
377 return True
376 return False
378 return False
377
379
378 class HasRepoPermissionAllDecorator(PermsDecorator):
380 class HasRepoPermissionAllDecorator(PermsDecorator):
379 """Checks for access permission for all given predicates for specific
381 """Checks for access permission for all given predicates for specific
380 repository. All of them have to be meet in order to fulfill the request
382 repository. All of them have to be meet in order to fulfill the request
381 """
383 """
382
384
383 def check_permissions(self):
385 def check_permissions(self):
384 repo_name = get_repo_slug(request)
386 repo_name = get_repo_slug(request)
385 try:
387 try:
386 user_perms = set([self.user_perms['repositories'][repo_name]])
388 user_perms = set([self.user_perms['repositories'][repo_name]])
387 except KeyError:
389 except KeyError:
388 return False
390 return False
389 if self.required_perms.issubset(user_perms):
391 if self.required_perms.issubset(user_perms):
390 return True
392 return True
391 return False
393 return False
392
394
393
395
394 class HasRepoPermissionAnyDecorator(PermsDecorator):
396 class HasRepoPermissionAnyDecorator(PermsDecorator):
395 """Checks for access permission for any of given predicates for specific
397 """Checks for access permission for any of given predicates for specific
396 repository. In order to fulfill the request any of predicates must be meet
398 repository. In order to fulfill the request any of predicates must be meet
397 """
399 """
398
400
399 def check_permissions(self):
401 def check_permissions(self):
400 repo_name = get_repo_slug(request)
402 repo_name = get_repo_slug(request)
401
403
402 try:
404 try:
403 user_perms = set([self.user_perms['repositories'][repo_name]])
405 user_perms = set([self.user_perms['repositories'][repo_name]])
404 except KeyError:
406 except KeyError:
405 return False
407 return False
406 if self.required_perms.intersection(user_perms):
408 if self.required_perms.intersection(user_perms):
407 return True
409 return True
408 return False
410 return False
409 #===============================================================================
411 #===============================================================================
410 # CHECK FUNCTIONS
412 # CHECK FUNCTIONS
411 #===============================================================================
413 #===============================================================================
412
414
413 class PermsFunction(object):
415 class PermsFunction(object):
414 """Base function for other check functions"""
416 """Base function for other check functions"""
415
417
416 def __init__(self, *perms):
418 def __init__(self, *perms):
417 available_perms = config['available_permissions']
419 available_perms = config['available_permissions']
418
420
419 for perm in perms:
421 for perm in perms:
420 if perm not in available_perms:
422 if perm not in available_perms:
421 raise Exception("'%s' permission in not defined" % perm)
423 raise Exception("'%s' permission in not defined" % perm)
422 self.required_perms = set(perms)
424 self.required_perms = set(perms)
423 self.user_perms = None
425 self.user_perms = None
424 self.granted_for = ''
426 self.granted_for = ''
425 self.repo_name = None
427 self.repo_name = None
426
428
427 def __call__(self, check_Location=''):
429 def __call__(self, check_Location=''):
428 user = session.get('rhodecode_user', False)
430 user = session.get('rhodecode_user', False)
429 if not user:
431 if not user:
430 return False
432 return False
431 self.user_perms = user.permissions
433 self.user_perms = user.permissions
432 self.granted_for = user.username
434 self.granted_for = user.username
433 log.debug('checking %s %s %s', self.__class__.__name__,
435 log.debug('checking %s %s %s', self.__class__.__name__,
434 self.required_perms, user)
436 self.required_perms, user)
435
437
436 if self.check_permissions():
438 if self.check_permissions():
437 log.debug('Permission granted for %s @ %s %s', self.granted_for,
439 log.debug('Permission granted for %s @ %s %s', self.granted_for,
438 check_Location, user)
440 check_Location, user)
439 return True
441 return True
440
442
441 else:
443 else:
442 log.warning('Permission denied for %s @ %s %s', self.granted_for,
444 log.warning('Permission denied for %s @ %s %s', self.granted_for,
443 check_Location, user)
445 check_Location, user)
444 return False
446 return False
445
447
446 def check_permissions(self):
448 def check_permissions(self):
447 """Dummy function for overriding"""
449 """Dummy function for overriding"""
448 raise Exception('You have to write this function in child class')
450 raise Exception('You have to write this function in child class')
449
451
450 class HasPermissionAll(PermsFunction):
452 class HasPermissionAll(PermsFunction):
451 def check_permissions(self):
453 def check_permissions(self):
452 if self.required_perms.issubset(self.user_perms.get('global')):
454 if self.required_perms.issubset(self.user_perms.get('global')):
453 return True
455 return True
454 return False
456 return False
455
457
456 class HasPermissionAny(PermsFunction):
458 class HasPermissionAny(PermsFunction):
457 def check_permissions(self):
459 def check_permissions(self):
458 if self.required_perms.intersection(self.user_perms.get('global')):
460 if self.required_perms.intersection(self.user_perms.get('global')):
459 return True
461 return True
460 return False
462 return False
461
463
462 class HasRepoPermissionAll(PermsFunction):
464 class HasRepoPermissionAll(PermsFunction):
463
465
464 def __call__(self, repo_name=None, check_Location=''):
466 def __call__(self, repo_name=None, check_Location=''):
465 self.repo_name = repo_name
467 self.repo_name = repo_name
466 return super(HasRepoPermissionAll, self).__call__(check_Location)
468 return super(HasRepoPermissionAll, self).__call__(check_Location)
467
469
468 def check_permissions(self):
470 def check_permissions(self):
469 if not self.repo_name:
471 if not self.repo_name:
470 self.repo_name = get_repo_slug(request)
472 self.repo_name = get_repo_slug(request)
471
473
472 try:
474 try:
473 self.user_perms = set([self.user_perms['repositories']\
475 self.user_perms = set([self.user_perms['repositories']\
474 [self.repo_name]])
476 [self.repo_name]])
475 except KeyError:
477 except KeyError:
476 return False
478 return False
477 self.granted_for = self.repo_name
479 self.granted_for = self.repo_name
478 if self.required_perms.issubset(self.user_perms):
480 if self.required_perms.issubset(self.user_perms):
479 return True
481 return True
480 return False
482 return False
481
483
482 class HasRepoPermissionAny(PermsFunction):
484 class HasRepoPermissionAny(PermsFunction):
483
485
484 def __call__(self, repo_name=None, check_Location=''):
486 def __call__(self, repo_name=None, check_Location=''):
485 self.repo_name = repo_name
487 self.repo_name = repo_name
486 return super(HasRepoPermissionAny, self).__call__(check_Location)
488 return super(HasRepoPermissionAny, self).__call__(check_Location)
487
489
488 def check_permissions(self):
490 def check_permissions(self):
489 if not self.repo_name:
491 if not self.repo_name:
490 self.repo_name = get_repo_slug(request)
492 self.repo_name = get_repo_slug(request)
491
493
492 try:
494 try:
493 self.user_perms = set([self.user_perms['repositories']\
495 self.user_perms = set([self.user_perms['repositories']\
494 [self.repo_name]])
496 [self.repo_name]])
495 except KeyError:
497 except KeyError:
496 return False
498 return False
497 self.granted_for = self.repo_name
499 self.granted_for = self.repo_name
498 if self.required_perms.intersection(self.user_perms):
500 if self.required_perms.intersection(self.user_perms):
499 return True
501 return True
500 return False
502 return False
501
503
502 #===============================================================================
504 #===============================================================================
503 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
505 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
504 #===============================================================================
506 #===============================================================================
505
507
506 class HasPermissionAnyMiddleware(object):
508 class HasPermissionAnyMiddleware(object):
507 def __init__(self, *perms):
509 def __init__(self, *perms):
508 self.required_perms = set(perms)
510 self.required_perms = set(perms)
509
511
510 def __call__(self, user, repo_name):
512 def __call__(self, user, repo_name):
511 usr = AuthUser()
513 usr = AuthUser()
512 usr.user_id = user.user_id
514 usr.user_id = user.user_id
513 usr.username = user.username
515 usr.username = user.username
514 usr.is_admin = user.admin
516 usr.is_admin = user.admin
515
517
516 try:
518 try:
517 self.user_perms = set([fill_perms(usr)\
519 self.user_perms = set([fill_perms(usr)\
518 .permissions['repositories'][repo_name]])
520 .permissions['repositories'][repo_name]])
519 except:
521 except:
520 self.user_perms = set()
522 self.user_perms = set()
521 self.granted_for = ''
523 self.granted_for = ''
522 self.username = user.username
524 self.username = user.username
523 self.repo_name = repo_name
525 self.repo_name = repo_name
524 return self.check_permissions()
526 return self.check_permissions()
525
527
526 def check_permissions(self):
528 def check_permissions(self):
527 log.debug('checking mercurial protocol '
529 log.debug('checking mercurial protocol '
528 'permissions for user:%s repository:%s',
530 'permissions for user:%s repository:%s',
529 self.username, self.repo_name)
531 self.username, self.repo_name)
530 if self.required_perms.intersection(self.user_perms):
532 if self.required_perms.intersection(self.user_perms):
531 log.debug('permission granted')
533 log.debug('permission granted')
532 return True
534 return True
533 log.debug('permission denied')
535 log.debug('permission denied')
534 return False
536 return False
@@ -1,441 +1,449 b''
1 """ this is forms validation classes
1 """ this is forms validation classes
2 http://formencode.org/module-formencode.validators.html
2 http://formencode.org/module-formencode.validators.html
3 for list off all availible validators
3 for list off all availible validators
4
4
5 we can create our own validators
5 we can create our own validators
6
6
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 pre_validators [] These validators will be applied before the schema
8 pre_validators [] These validators will be applied before the schema
9 chained_validators [] These validators will be applied after the schema
9 chained_validators [] These validators will be applied after the schema
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
14
14
15
15
16 <name> = formencode.validators.<name of validator>
16 <name> = formencode.validators.<name of validator>
17 <name> must equal form name
17 <name> must equal form name
18 list=[1,2,3,4,5]
18 list=[1,2,3,4,5]
19 for SELECT use formencode.All(OneOf(list), Int())
19 for SELECT use formencode.All(OneOf(list), Int())
20
20
21 """
21 """
22 from formencode import All
22 from formencode import All
23 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
23 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
24 Email, Bool, StringBoolean
24 Email, Bool, StringBoolean
25 from pylons import session
25 from pylons import session
26 from pylons.i18n.translation import _
26 from pylons.i18n.translation import _
27 from rhodecode.lib.auth import authfunc, get_crypt_password
27 from rhodecode.lib.auth import authfunc, get_crypt_password
28 from rhodecode.lib.exceptions import LdapImportError
28 from rhodecode.lib.exceptions import LdapImportError
29 from rhodecode.model import meta
29 from rhodecode.model import meta
30 from rhodecode.model.user import UserModel
30 from rhodecode.model.user import UserModel
31 from rhodecode.model.repo import RepoModel
31 from rhodecode.model.repo import RepoModel
32 from rhodecode.model.db import User
32 from rhodecode.model.db import User
33 from webhelpers.pylonslib.secure_form import authentication_token
33 from webhelpers.pylonslib.secure_form import authentication_token
34 from rhodecode import BACKENDS
34 from rhodecode import BACKENDS
35 import formencode
35 import formencode
36 import logging
36 import logging
37 import os
37 import os
38 import rhodecode.lib.helpers as h
38 import rhodecode.lib.helpers as h
39
39
40 log = logging.getLogger(__name__)
40 log = logging.getLogger(__name__)
41
41
42 #this is needed to translate the messages using _() in validators
42 #this is needed to translate the messages using _() in validators
43 class State_obj(object):
43 class State_obj(object):
44 _ = staticmethod(_)
44 _ = staticmethod(_)
45
45
46 #===============================================================================
46 #===============================================================================
47 # VALIDATORS
47 # VALIDATORS
48 #===============================================================================
48 #===============================================================================
49 class ValidAuthToken(formencode.validators.FancyValidator):
49 class ValidAuthToken(formencode.validators.FancyValidator):
50 messages = {'invalid_token':_('Token mismatch')}
50 messages = {'invalid_token':_('Token mismatch')}
51
51
52 def validate_python(self, value, state):
52 def validate_python(self, value, state):
53
53
54 if value != authentication_token():
54 if value != authentication_token():
55 raise formencode.Invalid(self.message('invalid_token', state,
55 raise formencode.Invalid(self.message('invalid_token', state,
56 search_number=value), value, state)
56 search_number=value), value, state)
57
57
58 def ValidUsername(edit, old_data):
58 def ValidUsername(edit, old_data):
59 class _ValidUsername(formencode.validators.FancyValidator):
59 class _ValidUsername(formencode.validators.FancyValidator):
60
60
61 def validate_python(self, value, state):
61 def validate_python(self, value, state):
62 if value in ['default', 'new_user']:
62 if value in ['default', 'new_user']:
63 raise formencode.Invalid(_('Invalid username'), value, state)
63 raise formencode.Invalid(_('Invalid username'), value, state)
64 #check if user is unique
64 #check if user is unique
65 old_un = None
65 old_un = None
66 if edit:
66 if edit:
67 old_un = UserModel().get(old_data.get('user_id')).username
67 old_un = UserModel().get(old_data.get('user_id')).username
68
68
69 if old_un != value or not edit:
69 if old_un != value or not edit:
70 if UserModel().get_by_username(value.lower(), cache=False):
70 if UserModel().get_by_username(value, cache=False,
71 case_insensitive=True):
71 raise formencode.Invalid(_('This username already exists') ,
72 raise formencode.Invalid(_('This username already exists') ,
72 value, state)
73 value, state)
73
74
74 return _ValidUsername
75 return _ValidUsername
75
76
76 class ValidPassword(formencode.validators.FancyValidator):
77 class ValidPassword(formencode.validators.FancyValidator):
77
78
78 def to_python(self, value, state):
79 def to_python(self, value, state):
79
80
80 if value:
81 if value:
81
82
82 if value.get('password'):
83 if value.get('password'):
83 try:
84 try:
84 value['password'] = get_crypt_password(value['password'])
85 value['password'] = get_crypt_password(value['password'])
85 except UnicodeEncodeError:
86 except UnicodeEncodeError:
86 e_dict = {'password':_('Invalid characters in password')}
87 e_dict = {'password':_('Invalid characters in password')}
87 raise formencode.Invalid('', value, state, error_dict=e_dict)
88 raise formencode.Invalid('', value, state, error_dict=e_dict)
88
89
89 if value.get('password_confirmation'):
90 if value.get('password_confirmation'):
90 try:
91 try:
91 value['password_confirmation'] = \
92 value['password_confirmation'] = \
92 get_crypt_password(value['password_confirmation'])
93 get_crypt_password(value['password_confirmation'])
93 except UnicodeEncodeError:
94 except UnicodeEncodeError:
94 e_dict = {'password_confirmation':_('Invalid characters in password')}
95 e_dict = {'password_confirmation':_('Invalid characters in password')}
95 raise formencode.Invalid('', value, state, error_dict=e_dict)
96 raise formencode.Invalid('', value, state, error_dict=e_dict)
96
97
97 if value.get('new_password'):
98 if value.get('new_password'):
98 try:
99 try:
99 value['new_password'] = \
100 value['new_password'] = \
100 get_crypt_password(value['new_password'])
101 get_crypt_password(value['new_password'])
101 except UnicodeEncodeError:
102 except UnicodeEncodeError:
102 e_dict = {'new_password':_('Invalid characters in password')}
103 e_dict = {'new_password':_('Invalid characters in password')}
103 raise formencode.Invalid('', value, state, error_dict=e_dict)
104 raise formencode.Invalid('', value, state, error_dict=e_dict)
104
105
105 return value
106 return value
106
107
107 class ValidPasswordsMatch(formencode.validators.FancyValidator):
108 class ValidPasswordsMatch(formencode.validators.FancyValidator):
108
109
109 def validate_python(self, value, state):
110 def validate_python(self, value, state):
110
111
111 if value['password'] != value['password_confirmation']:
112 if value['password'] != value['password_confirmation']:
112 e_dict = {'password_confirmation':
113 e_dict = {'password_confirmation':
113 _('Password do not match')}
114 _('Password do not match')}
114 raise formencode.Invalid('', value, state, error_dict=e_dict)
115 raise formencode.Invalid('', value, state, error_dict=e_dict)
115
116
116 class ValidAuth(formencode.validators.FancyValidator):
117 class ValidAuth(formencode.validators.FancyValidator):
117 messages = {
118 messages = {
118 'invalid_password':_('invalid password'),
119 'invalid_password':_('invalid password'),
119 'invalid_login':_('invalid user name'),
120 'invalid_login':_('invalid user name'),
120 'disabled_account':_('Your account is disabled')
121 'disabled_account':_('Your account is disabled')
121
122
122 }
123 }
123 #error mapping
124 #error mapping
124 e_dict = {'username':messages['invalid_login'],
125 e_dict = {'username':messages['invalid_login'],
125 'password':messages['invalid_password']}
126 'password':messages['invalid_password']}
126 e_dict_disable = {'username':messages['disabled_account']}
127 e_dict_disable = {'username':messages['disabled_account']}
127
128
128 def validate_python(self, value, state):
129 def validate_python(self, value, state):
129 password = value['password']
130 password = value['password']
130 username = value['username']
131 username = value['username']
131 user = UserModel().get_by_username(username)
132 user = UserModel().get_by_username(username)
132
133
133 if authfunc(None, username, password):
134 if authfunc(None, username, password):
134 return value
135 return value
135 else:
136 else:
136 if user and user.active is False:
137 if user and user.active is False:
137 log.warning('user %s is disabled', username)
138 log.warning('user %s is disabled', username)
138 raise formencode.Invalid(self.message('disabled_account',
139 raise formencode.Invalid(self.message('disabled_account',
139 state=State_obj),
140 state=State_obj),
140 value, state,
141 value, state,
141 error_dict=self.e_dict_disable)
142 error_dict=self.e_dict_disable)
142 else:
143 else:
143 log.warning('user %s not authenticated', username)
144 log.warning('user %s not authenticated', username)
144 raise formencode.Invalid(self.message('invalid_password',
145 raise formencode.Invalid(self.message('invalid_password',
145 state=State_obj), value, state,
146 state=State_obj), value, state,
146 error_dict=self.e_dict)
147 error_dict=self.e_dict)
147
148
148 class ValidRepoUser(formencode.validators.FancyValidator):
149 class ValidRepoUser(formencode.validators.FancyValidator):
149
150
150 def to_python(self, value, state):
151 def to_python(self, value, state):
151 sa = meta.Session()
152 sa = meta.Session()
152 try:
153 try:
153 self.user_db = sa.query(User)\
154 self.user_db = sa.query(User)\
154 .filter(User.active == True)\
155 .filter(User.active == True)\
155 .filter(User.username == value).one()
156 .filter(User.username == value).one()
156 except Exception:
157 except Exception:
157 raise formencode.Invalid(_('This username is not valid'),
158 raise formencode.Invalid(_('This username is not valid'),
158 value, state)
159 value, state)
159 finally:
160 finally:
160 meta.Session.remove()
161 meta.Session.remove()
161
162
162 return self.user_db.user_id
163 return self.user_db.user_id
163
164
164 def ValidRepoName(edit, old_data):
165 def ValidRepoName(edit, old_data):
165 class _ValidRepoName(formencode.validators.FancyValidator):
166 class _ValidRepoName(formencode.validators.FancyValidator):
166
167
167 def to_python(self, value, state):
168 def to_python(self, value, state):
168 slug = h.repo_name_slug(value)
169 slug = h.repo_name_slug(value)
169 if slug in ['_admin']:
170 if slug in ['_admin']:
170 raise formencode.Invalid(_('This repository name is disallowed'),
171 raise formencode.Invalid(_('This repository name is disallowed'),
171 value, state)
172 value, state)
172 if old_data.get('repo_name') != value or not edit:
173 if old_data.get('repo_name') != value or not edit:
173 if RepoModel().get_by_repo_name(slug, cache=False):
174 if RepoModel().get_by_repo_name(slug, cache=False):
174 raise formencode.Invalid(_('This repository already exists') ,
175 raise formencode.Invalid(_('This repository already exists') ,
175 value, state)
176 value, state)
176 return slug
177 return slug
177
178
178
179
179 return _ValidRepoName
180 return _ValidRepoName
180
181
181 def ValidForkType(old_data):
182 def ValidForkType(old_data):
182 class _ValidForkType(formencode.validators.FancyValidator):
183 class _ValidForkType(formencode.validators.FancyValidator):
183
184
184 def to_python(self, value, state):
185 def to_python(self, value, state):
185 if old_data['repo_type'] != value:
186 if old_data['repo_type'] != value:
186 raise formencode.Invalid(_('Fork have to be the same type as original'), value, state)
187 raise formencode.Invalid(_('Fork have to be the same type as original'),
188 value, state)
187 return value
189 return value
188 return _ValidForkType
190 return _ValidForkType
189
191
190 class ValidPerms(formencode.validators.FancyValidator):
192 class ValidPerms(formencode.validators.FancyValidator):
191 messages = {'perm_new_user_name':_('This username is not valid')}
193 messages = {'perm_new_user_name':_('This username is not valid')}
192
194
193 def to_python(self, value, state):
195 def to_python(self, value, state):
194 perms_update = []
196 perms_update = []
195 perms_new = []
197 perms_new = []
196 #build a list of permission to update and new permission to create
198 #build a list of permission to update and new permission to create
197 for k, v in value.items():
199 for k, v in value.items():
198 if k.startswith('perm_'):
200 if k.startswith('perm_'):
199 if k.startswith('perm_new_user'):
201 if k.startswith('perm_new_user'):
200 new_perm = value.get('perm_new_user', False)
202 new_perm = value.get('perm_new_user', False)
201 new_user = value.get('perm_new_user_name', False)
203 new_user = value.get('perm_new_user_name', False)
202 if new_user and new_perm:
204 if new_user and new_perm:
203 if (new_user, new_perm) not in perms_new:
205 if (new_user, new_perm) not in perms_new:
204 perms_new.append((new_user, new_perm))
206 perms_new.append((new_user, new_perm))
205 else:
207 else:
206 usr = k[5:]
208 usr = k[5:]
207 if usr == 'default':
209 if usr == 'default':
208 if value['private']:
210 if value['private']:
209 #set none for default when updating to private repo
211 #set none for default when updating to private repo
210 v = 'repository.none'
212 v = 'repository.none'
211 perms_update.append((usr, v))
213 perms_update.append((usr, v))
212 value['perms_updates'] = perms_update
214 value['perms_updates'] = perms_update
213 value['perms_new'] = perms_new
215 value['perms_new'] = perms_new
214 sa = meta.Session
216 sa = meta.Session
215 for k, v in perms_new:
217 for k, v in perms_new:
216 try:
218 try:
217 self.user_db = sa.query(User)\
219 self.user_db = sa.query(User)\
218 .filter(User.active == True)\
220 .filter(User.active == True)\
219 .filter(User.username == k).one()
221 .filter(User.username == k).one()
220 except Exception:
222 except Exception:
221 msg = self.message('perm_new_user_name',
223 msg = self.message('perm_new_user_name',
222 state=State_obj)
224 state=State_obj)
223 raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})
225 raise formencode.Invalid(msg, value, state,
226 error_dict={'perm_new_user_name':msg})
224 return value
227 return value
225
228
226 class ValidSettings(formencode.validators.FancyValidator):
229 class ValidSettings(formencode.validators.FancyValidator):
227
230
228 def to_python(self, value, state):
231 def to_python(self, value, state):
229 #settings form can't edit user
232 #settings form can't edit user
230 if value.has_key('user'):
233 if value.has_key('user'):
231 del['value']['user']
234 del['value']['user']
232
235
233 return value
236 return value
234
237
235 class ValidPath(formencode.validators.FancyValidator):
238 class ValidPath(formencode.validators.FancyValidator):
236 def to_python(self, value, state):
239 def to_python(self, value, state):
237
240
238 if not os.path.isdir(value):
241 if not os.path.isdir(value):
239 msg = _('This is not a valid path')
242 msg = _('This is not a valid path')
240 raise formencode.Invalid(msg, value, state,
243 raise formencode.Invalid(msg, value, state,
241 error_dict={'paths_root_path':msg})
244 error_dict={'paths_root_path':msg})
242 return value
245 return value
243
246
244 def UniqSystemEmail(old_data):
247 def UniqSystemEmail(old_data):
245 class _UniqSystemEmail(formencode.validators.FancyValidator):
248 class _UniqSystemEmail(formencode.validators.FancyValidator):
246 def to_python(self, value, state):
249 def to_python(self, value, state):
247 value = value.lower()
250 value = value.lower()
248 #TODO:write test for MixedCase scenarios
251 #TODO:write test for MixedCase scenarios
249 if old_data.get('email') != value:
252 if old_data.get('email') != value:
250 sa = meta.Session()
253 sa = meta.Session()
251 try:
254 try:
252 user = sa.query(User).filter(User.email == value).scalar()
255 user = sa.query(User).filter(User.email == value).scalar()
253 if user:
256 if user:
254 raise formencode.Invalid(_("That e-mail address is already taken") ,
257 raise formencode.Invalid(_("That e-mail address is already taken") ,
255 value, state)
258 value, state)
256 finally:
259 finally:
257 meta.Session.remove()
260 meta.Session.remove()
258
261
259 return value
262 return value
260
263
261 return _UniqSystemEmail
264 return _UniqSystemEmail
262
265
263 class ValidSystemEmail(formencode.validators.FancyValidator):
266 class ValidSystemEmail(formencode.validators.FancyValidator):
264 def to_python(self, value, state):
267 def to_python(self, value, state):
265 value = value.lower()
268 value = value.lower()
266 sa = meta.Session
269 sa = meta.Session
267 try:
270 try:
268 user = sa.query(User).filter(User.email == value).scalar()
271 user = sa.query(User).filter(User.email == value).scalar()
269 if user is None:
272 if user is None:
270 raise formencode.Invalid(_("That e-mail address doesn't exist.") ,
273 raise formencode.Invalid(_("That e-mail address doesn't exist.") ,
271 value, state)
274 value, state)
272 finally:
275 finally:
273 meta.Session.remove()
276 meta.Session.remove()
274
277
275 return value
278 return value
276
279
277 class LdapLibValidator(formencode.validators.FancyValidator):
280 class LdapLibValidator(formencode.validators.FancyValidator):
278
281
279 def to_python(self, value, state):
282 def to_python(self, value, state):
280
283
281 try:
284 try:
282 import ldap
285 import ldap
283 except ImportError:
286 except ImportError:
284 raise LdapImportError
287 raise LdapImportError
285 return value
288 return value
286
289
287 #===============================================================================
290 #===============================================================================
288 # FORMS
291 # FORMS
289 #===============================================================================
292 #===============================================================================
290 class LoginForm(formencode.Schema):
293 class LoginForm(formencode.Schema):
291 allow_extra_fields = True
294 allow_extra_fields = True
292 filter_extra_fields = True
295 filter_extra_fields = True
293 username = UnicodeString(
296 username = UnicodeString(
294 strip=True,
297 strip=True,
295 min=1,
298 min=1,
296 not_empty=True,
299 not_empty=True,
297 messages={
300 messages={
298 'empty':_('Please enter a login'),
301 'empty':_('Please enter a login'),
299 'tooShort':_('Enter a value %(min)i characters long or more')}
302 'tooShort':_('Enter a value %(min)i characters long or more')}
300 )
303 )
301
304
302 password = UnicodeString(
305 password = UnicodeString(
303 strip=True,
306 strip=True,
304 min=6,
307 min=6,
305 not_empty=True,
308 not_empty=True,
306 messages={
309 messages={
307 'empty':_('Please enter a password'),
310 'empty':_('Please enter a password'),
308 'tooShort':_('Enter %(min)i characters or more')}
311 'tooShort':_('Enter %(min)i characters or more')}
309 )
312 )
310
313
311
314
312 #chained validators have access to all data
315 #chained validators have access to all data
313 chained_validators = [ValidAuth]
316 chained_validators = [ValidAuth]
314
317
315 def UserForm(edit=False, old_data={}):
318 def UserForm(edit=False, old_data={}):
316 class _UserForm(formencode.Schema):
319 class _UserForm(formencode.Schema):
317 allow_extra_fields = True
320 allow_extra_fields = True
318 filter_extra_fields = True
321 filter_extra_fields = True
319 username = All(UnicodeString(strip=True, min=1, not_empty=True), ValidUsername(edit, old_data))
322 username = All(UnicodeString(strip=True, min=1, not_empty=True),
323 ValidUsername(edit, old_data))
320 if edit:
324 if edit:
321 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
325 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
322 admin = StringBoolean(if_missing=False)
326 admin = StringBoolean(if_missing=False)
323 else:
327 else:
324 password = All(UnicodeString(strip=True, min=6, not_empty=True))
328 password = All(UnicodeString(strip=True, min=6, not_empty=True))
325 active = StringBoolean(if_missing=False)
329 active = StringBoolean(if_missing=False)
326 name = UnicodeString(strip=True, min=1, not_empty=True)
330 name = UnicodeString(strip=True, min=1, not_empty=True)
327 lastname = UnicodeString(strip=True, min=1, not_empty=True)
331 lastname = UnicodeString(strip=True, min=1, not_empty=True)
328 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
332 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
329
333
330 chained_validators = [ValidPassword]
334 chained_validators = [ValidPassword]
331
335
332 return _UserForm
336 return _UserForm
333
337
334 def RegisterForm(edit=False, old_data={}):
338 def RegisterForm(edit=False, old_data={}):
335 class _RegisterForm(formencode.Schema):
339 class _RegisterForm(formencode.Schema):
336 allow_extra_fields = True
340 allow_extra_fields = True
337 filter_extra_fields = True
341 filter_extra_fields = True
338 username = All(ValidUsername(edit, old_data), UnicodeString(strip=True, min=1, not_empty=True))
342 username = All(ValidUsername(edit, old_data),
343 UnicodeString(strip=True, min=1, not_empty=True))
339 password = All(UnicodeString(strip=True, min=6, not_empty=True))
344 password = All(UnicodeString(strip=True, min=6, not_empty=True))
340 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
345 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
341 active = StringBoolean(if_missing=False)
346 active = StringBoolean(if_missing=False)
342 name = UnicodeString(strip=True, min=1, not_empty=True)
347 name = UnicodeString(strip=True, min=1, not_empty=True)
343 lastname = UnicodeString(strip=True, min=1, not_empty=True)
348 lastname = UnicodeString(strip=True, min=1, not_empty=True)
344 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
349 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
345
350
346 chained_validators = [ValidPasswordsMatch, ValidPassword]
351 chained_validators = [ValidPasswordsMatch, ValidPassword]
347
352
348 return _RegisterForm
353 return _RegisterForm
349
354
350 def PasswordResetForm():
355 def PasswordResetForm():
351 class _PasswordResetForm(formencode.Schema):
356 class _PasswordResetForm(formencode.Schema):
352 allow_extra_fields = True
357 allow_extra_fields = True
353 filter_extra_fields = True
358 filter_extra_fields = True
354 email = All(ValidSystemEmail(), Email(not_empty=True))
359 email = All(ValidSystemEmail(), Email(not_empty=True))
355 return _PasswordResetForm
360 return _PasswordResetForm
356
361
357 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
362 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
358 class _RepoForm(formencode.Schema):
363 class _RepoForm(formencode.Schema):
359 allow_extra_fields = True
364 allow_extra_fields = True
360 filter_extra_fields = False
365 filter_extra_fields = False
361 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
366 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
367 ValidRepoName(edit, old_data))
362 description = UnicodeString(strip=True, min=1, not_empty=True)
368 description = UnicodeString(strip=True, min=1, not_empty=True)
363 private = StringBoolean(if_missing=False)
369 private = StringBoolean(if_missing=False)
364 repo_type = OneOf(supported_backends)
370 repo_type = OneOf(supported_backends)
365 if edit:
371 if edit:
366 user = All(Int(not_empty=True), ValidRepoUser)
372 user = All(Int(not_empty=True), ValidRepoUser)
367
373
368 chained_validators = [ValidPerms]
374 chained_validators = [ValidPerms]
369 return _RepoForm
375 return _RepoForm
370
376
371 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
377 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
372 class _RepoForkForm(formencode.Schema):
378 class _RepoForkForm(formencode.Schema):
373 allow_extra_fields = True
379 allow_extra_fields = True
374 filter_extra_fields = False
380 filter_extra_fields = False
375 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
381 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
382 ValidRepoName(edit, old_data))
376 description = UnicodeString(strip=True, min=1, not_empty=True)
383 description = UnicodeString(strip=True, min=1, not_empty=True)
377 private = StringBoolean(if_missing=False)
384 private = StringBoolean(if_missing=False)
378 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
385 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
379 return _RepoForkForm
386 return _RepoForkForm
380
387
381 def RepoSettingsForm(edit=False, old_data={}):
388 def RepoSettingsForm(edit=False, old_data={}):
382 class _RepoForm(formencode.Schema):
389 class _RepoForm(formencode.Schema):
383 allow_extra_fields = True
390 allow_extra_fields = True
384 filter_extra_fields = False
391 filter_extra_fields = False
385 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
392 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
393 ValidRepoName(edit, old_data))
386 description = UnicodeString(strip=True, min=1, not_empty=True)
394 description = UnicodeString(strip=True, min=1, not_empty=True)
387 private = StringBoolean(if_missing=False)
395 private = StringBoolean(if_missing=False)
388
396
389 chained_validators = [ValidPerms, ValidSettings]
397 chained_validators = [ValidPerms, ValidSettings]
390 return _RepoForm
398 return _RepoForm
391
399
392
400
393 def ApplicationSettingsForm():
401 def ApplicationSettingsForm():
394 class _ApplicationSettingsForm(formencode.Schema):
402 class _ApplicationSettingsForm(formencode.Schema):
395 allow_extra_fields = True
403 allow_extra_fields = True
396 filter_extra_fields = False
404 filter_extra_fields = False
397 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
405 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
398 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
406 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
399
407
400 return _ApplicationSettingsForm
408 return _ApplicationSettingsForm
401
409
402 def ApplicationUiSettingsForm():
410 def ApplicationUiSettingsForm():
403 class _ApplicationUiSettingsForm(formencode.Schema):
411 class _ApplicationUiSettingsForm(formencode.Schema):
404 allow_extra_fields = True
412 allow_extra_fields = True
405 filter_extra_fields = False
413 filter_extra_fields = False
406 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
414 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
407 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
415 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
408 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
416 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
409 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
417 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
410 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
418 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
411 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
419 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
412
420
413 return _ApplicationUiSettingsForm
421 return _ApplicationUiSettingsForm
414
422
415 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
423 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
416 class _DefaultPermissionsForm(formencode.Schema):
424 class _DefaultPermissionsForm(formencode.Schema):
417 allow_extra_fields = True
425 allow_extra_fields = True
418 filter_extra_fields = True
426 filter_extra_fields = True
419 overwrite_default = StringBoolean(if_missing=False)
427 overwrite_default = StringBoolean(if_missing=False)
420 anonymous = OneOf(['True', 'False'], if_missing=False)
428 anonymous = OneOf(['True', 'False'], if_missing=False)
421 default_perm = OneOf(perms_choices)
429 default_perm = OneOf(perms_choices)
422 default_register = OneOf(register_choices)
430 default_register = OneOf(register_choices)
423 default_create = OneOf(create_choices)
431 default_create = OneOf(create_choices)
424
432
425 return _DefaultPermissionsForm
433 return _DefaultPermissionsForm
426
434
427
435
428 def LdapSettingsForm():
436 def LdapSettingsForm():
429 class _LdapSettingsForm(formencode.Schema):
437 class _LdapSettingsForm(formencode.Schema):
430 allow_extra_fields = True
438 allow_extra_fields = True
431 filter_extra_fields = True
439 filter_extra_fields = True
432 pre_validators = [LdapLibValidator]
440 pre_validators = [LdapLibValidator]
433 ldap_active = StringBoolean(if_missing=False)
441 ldap_active = StringBoolean(if_missing=False)
434 ldap_host = UnicodeString(strip=True,)
442 ldap_host = UnicodeString(strip=True,)
435 ldap_port = Number(strip=True,)
443 ldap_port = Number(strip=True,)
436 ldap_ldaps = StringBoolean(if_missing=False)
444 ldap_ldaps = StringBoolean(if_missing=False)
437 ldap_dn_user = UnicodeString(strip=True,)
445 ldap_dn_user = UnicodeString(strip=True,)
438 ldap_dn_pass = UnicodeString(strip=True,)
446 ldap_dn_pass = UnicodeString(strip=True,)
439 ldap_base_dn = UnicodeString(strip=True,)
447 ldap_base_dn = UnicodeString(strip=True,)
440
448
441 return _LdapSettingsForm
449 return _LdapSettingsForm
@@ -1,215 +1,219 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 from rhodecode.lib.exceptions import *
30 from rhodecode.lib.exceptions import *
31 import logging
31 import logging
32 import traceback
32 import traceback
33
33
34 log = logging.getLogger(__name__)
34 log = logging.getLogger(__name__)
35
35
36
36
37
37
38 class UserModel(object):
38 class UserModel(object):
39
39
40 def __init__(self):
40 def __init__(self):
41 self.sa = Session()
41 self.sa = Session()
42
42
43 def get(self, user_id, cache=False):
43 def get(self, user_id, cache=False):
44 user = self.sa.query(User)
44 user = self.sa.query(User)
45 if cache:
45 if cache:
46 user = user.options(FromCache("sql_cache_short",
46 user = user.options(FromCache("sql_cache_short",
47 "get_user_%s" % user_id))
47 "get_user_%s" % user_id))
48 return user.get(user_id)
48 return user.get(user_id)
49
49
50
50
51 def get_by_username(self, username, cache=False):
51 def get_by_username(self, username, cache=False, case_insensitive=False):
52 user = self.sa.query(User)\
52
53 .filter(User.username == username)
53 if case_insensitive:
54 user = self.sa.query(User).filter(User.username.ilike(username))
55 else:
56 user = self.sa.query(User)\
57 .filter(User.username == username)
54 if cache:
58 if cache:
55 user = user.options(FromCache("sql_cache_short",
59 user = user.options(FromCache("sql_cache_short",
56 "get_user_%s" % username))
60 "get_user_%s" % username))
57 return user.scalar()
61 return user.scalar()
58
62
59 def create(self, form_data):
63 def create(self, form_data):
60 try:
64 try:
61 new_user = User()
65 new_user = User()
62 for k, v in form_data.items():
66 for k, v in form_data.items():
63 setattr(new_user, k, v)
67 setattr(new_user, k, v)
64
68
65 self.sa.add(new_user)
69 self.sa.add(new_user)
66 self.sa.commit()
70 self.sa.commit()
67 except:
71 except:
68 log.error(traceback.format_exc())
72 log.error(traceback.format_exc())
69 self.sa.rollback()
73 self.sa.rollback()
70 raise
74 raise
71
75
72 def create_ldap(self, username, password):
76 def create_ldap(self, username, password):
73 """
77 """
74 Checks if user is in database, if not creates this user marked
78 Checks if user is in database, if not creates this user marked
75 as ldap user
79 as ldap user
76 :param username:
80 :param username:
77 :param password:
81 :param password:
78 """
82 """
79
83
80 if self.get_by_username(username) is None:
84 if self.get_by_username(username) is None:
81 try:
85 try:
82 new_user = User()
86 new_user = User()
83 new_user.username = username
87 new_user.username = username
84 new_user.password = password
88 new_user.password = password
85 new_user.email = '%s@ldap.server' % username
89 new_user.email = '%s@ldap.server' % username
86 new_user.active = True
90 new_user.active = True
87 new_user.is_ldap = True
91 new_user.is_ldap = True
88 new_user.name = '%s@ldap' % username
92 new_user.name = '%s@ldap' % username
89 new_user.lastname = ''
93 new_user.lastname = ''
90
94
91
95
92 self.sa.add(new_user)
96 self.sa.add(new_user)
93 self.sa.commit()
97 self.sa.commit()
94 return True
98 return True
95 except:
99 except:
96 log.error(traceback.format_exc())
100 log.error(traceback.format_exc())
97 self.sa.rollback()
101 self.sa.rollback()
98 raise
102 raise
99
103
100 return False
104 return False
101
105
102 def create_registration(self, form_data):
106 def create_registration(self, form_data):
103 from rhodecode.lib.celerylib import tasks, run_task
107 from rhodecode.lib.celerylib import tasks, run_task
104 try:
108 try:
105 new_user = User()
109 new_user = User()
106 for k, v in form_data.items():
110 for k, v in form_data.items():
107 if k != 'admin':
111 if k != 'admin':
108 setattr(new_user, k, v)
112 setattr(new_user, k, v)
109
113
110 self.sa.add(new_user)
114 self.sa.add(new_user)
111 self.sa.commit()
115 self.sa.commit()
112 body = ('New user registration\n'
116 body = ('New user registration\n'
113 'username: %s\n'
117 'username: %s\n'
114 'email: %s\n')
118 'email: %s\n')
115 body = body % (form_data['username'], form_data['email'])
119 body = body % (form_data['username'], form_data['email'])
116
120
117 run_task(tasks.send_email, None,
121 run_task(tasks.send_email, None,
118 _('[RhodeCode] New User registration'),
122 _('[RhodeCode] New User registration'),
119 body)
123 body)
120 except:
124 except:
121 log.error(traceback.format_exc())
125 log.error(traceback.format_exc())
122 self.sa.rollback()
126 self.sa.rollback()
123 raise
127 raise
124
128
125 def update(self, user_id, form_data):
129 def update(self, user_id, form_data):
126 try:
130 try:
127 new_user = self.get(user_id, cache=False)
131 new_user = self.get(user_id, cache=False)
128 if new_user.username == 'default':
132 if new_user.username == 'default':
129 raise DefaultUserException(
133 raise DefaultUserException(
130 _("You can't Edit this user since it's"
134 _("You can't Edit this user since it's"
131 " crucial for entire application"))
135 " crucial for entire application"))
132
136
133 for k, v in form_data.items():
137 for k, v in form_data.items():
134 if k == 'new_password' and v != '':
138 if k == 'new_password' and v != '':
135 new_user.password = v
139 new_user.password = v
136 else:
140 else:
137 setattr(new_user, k, v)
141 setattr(new_user, k, v)
138
142
139 self.sa.add(new_user)
143 self.sa.add(new_user)
140 self.sa.commit()
144 self.sa.commit()
141 except:
145 except:
142 log.error(traceback.format_exc())
146 log.error(traceback.format_exc())
143 self.sa.rollback()
147 self.sa.rollback()
144 raise
148 raise
145
149
146 def update_my_account(self, user_id, form_data):
150 def update_my_account(self, user_id, form_data):
147 try:
151 try:
148 new_user = self.get(user_id, cache=False)
152 new_user = self.get(user_id, cache=False)
149 if new_user.username == 'default':
153 if new_user.username == 'default':
150 raise DefaultUserException(
154 raise DefaultUserException(
151 _("You can't Edit this user since it's"
155 _("You can't Edit this user since it's"
152 " crucial for entire application"))
156 " crucial for entire application"))
153 for k, v in form_data.items():
157 for k, v in form_data.items():
154 if k == 'new_password' and v != '':
158 if k == 'new_password' and v != '':
155 new_user.password = v
159 new_user.password = v
156 else:
160 else:
157 if k not in ['admin', 'active']:
161 if k not in ['admin', 'active']:
158 setattr(new_user, k, v)
162 setattr(new_user, k, v)
159
163
160 self.sa.add(new_user)
164 self.sa.add(new_user)
161 self.sa.commit()
165 self.sa.commit()
162 except:
166 except:
163 log.error(traceback.format_exc())
167 log.error(traceback.format_exc())
164 self.sa.rollback()
168 self.sa.rollback()
165 raise
169 raise
166
170
167 def delete(self, user_id):
171 def delete(self, user_id):
168 try:
172 try:
169 user = self.get(user_id, cache=False)
173 user = self.get(user_id, cache=False)
170 if user.username == 'default':
174 if user.username == 'default':
171 raise DefaultUserException(
175 raise DefaultUserException(
172 _("You can't remove this user since it's"
176 _("You can't remove this user since it's"
173 " crucial for entire application"))
177 " crucial for entire application"))
174 if user.repositories:
178 if user.repositories:
175 raise UserOwnsReposException(_('This user still owns %s '
179 raise UserOwnsReposException(_('This user still owns %s '
176 'repositories and cannot be '
180 'repositories and cannot be '
177 'removed. Switch owners or '
181 'removed. Switch owners or '
178 'remove those repositories') \
182 'remove those repositories') \
179 % user.repositories)
183 % user.repositories)
180 self.sa.delete(user)
184 self.sa.delete(user)
181 self.sa.commit()
185 self.sa.commit()
182 except:
186 except:
183 log.error(traceback.format_exc())
187 log.error(traceback.format_exc())
184 self.sa.rollback()
188 self.sa.rollback()
185 raise
189 raise
186
190
187 def reset_password(self, data):
191 def reset_password(self, data):
188 from rhodecode.lib.celerylib import tasks, run_task
192 from rhodecode.lib.celerylib import tasks, run_task
189 run_task(tasks.reset_user_password, data['email'])
193 run_task(tasks.reset_user_password, data['email'])
190
194
191
195
192 def fill_data(self, user):
196 def fill_data(self, user):
193 """
197 """
194 Fills user data with those from database and log out user if not
198 Fills user data with those from database and log out user if not
195 present in database
199 present in database
196 :param user:
200 :param user:
197 """
201 """
198
202
199 if not hasattr(user, 'user_id') or user.user_id is None:
203 if not hasattr(user, 'user_id') or user.user_id is None:
200 raise Exception('passed in user has to have the user_id attribute')
204 raise Exception('passed in user has to have the user_id attribute')
201
205
202
206
203 log.debug('filling auth user data')
207 log.debug('filling auth user data')
204 try:
208 try:
205 dbuser = self.get(user.user_id)
209 dbuser = self.get(user.user_id)
206 user.username = dbuser.username
210 user.username = dbuser.username
207 user.is_admin = dbuser.admin
211 user.is_admin = dbuser.admin
208 user.name = dbuser.name
212 user.name = dbuser.name
209 user.lastname = dbuser.lastname
213 user.lastname = dbuser.lastname
210 user.email = dbuser.email
214 user.email = dbuser.email
211 except:
215 except:
212 log.error(traceback.format_exc())
216 log.error(traceback.format_exc())
213 user.is_authenticated = False
217 user.is_authenticated = False
214
218
215 return user
219 return user
General Comments 0
You need to be logged in to leave comments. Login now