##// END OF EJS Templates
fixes #136 leftover patch
marcink -
r1168:7327a0d1 default
parent child Browse files
Show More
@@ -1,614 +1,614 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.auth
3 rhodecode.lib.auth
4 ~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~
5
5
6 authentication and permission libraries
6 authentication and permission libraries
7
7
8 :created_on: Apr 4, 2010
8 :created_on: Apr 4, 2010
9 :copyright: (c) 2010 by marcink.
9 :copyright: (c) 2010 by marcink.
10 :license: LICENSE_NAME, see LICENSE_FILE for more details.
10 :license: LICENSE_NAME, see LICENSE_FILE for more details.
11 """
11 """
12 # This program is free software; you can redistribute it and/or
12 # This program is free software; you can redistribute it and/or
13 # modify it under the terms of the GNU General Public License
13 # modify it under the terms of the GNU General Public License
14 # as published by the Free Software Foundation; version 2
14 # as published by the Free Software Foundation; version 2
15 # of the License or (at your opinion) any later version of the license.
15 # of the License or (at your opinion) any later version of the license.
16 #
16 #
17 # This program is distributed in the hope that it will be useful,
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
20 # GNU General Public License for more details.
21 #
21 #
22 # You should have received a copy of the GNU General Public License
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # MA 02110-1301, USA.
25 # MA 02110-1301, USA.
26
26
27 import random
27 import random
28 import logging
28 import logging
29 import traceback
29 import traceback
30
30
31 from decorator import decorator
31 from decorator import decorator
32
32
33 from pylons import config, session, url, request
33 from pylons import config, session, url, request
34 from pylons.controllers.util import abort, redirect
34 from pylons.controllers.util import abort, redirect
35 from pylons.i18n.translation import _
35 from pylons.i18n.translation import _
36
36
37 from rhodecode import __platform__, PLATFORM_WIN, PLATFORM_OTHERS
37 from rhodecode import __platform__, PLATFORM_WIN, PLATFORM_OTHERS
38
38
39 if __platform__ in PLATFORM_WIN:
39 if __platform__ in PLATFORM_WIN:
40 from hashlib import sha256
40 from hashlib import sha256
41 if __platform__ in PLATFORM_OTHERS:
41 if __platform__ in PLATFORM_OTHERS:
42 import bcrypt
42 import bcrypt
43
43
44 from rhodecode.lib import str2bool
44 from rhodecode.lib import str2bool
45 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
45 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
46 from rhodecode.lib.utils import get_repo_slug
46 from rhodecode.lib.utils import get_repo_slug
47 from rhodecode.lib.auth_ldap import AuthLdap
47 from rhodecode.lib.auth_ldap import AuthLdap
48
48
49 from rhodecode.model import meta
49 from rhodecode.model import meta
50 from rhodecode.model.user import UserModel
50 from rhodecode.model.user import UserModel
51 from rhodecode.model.db import Permission, RepoToPerm, Repository, \
51 from rhodecode.model.db import Permission, RepoToPerm, Repository, \
52 User, UserToPerm
52 User, UserToPerm
53
53
54
54
55 log = logging.getLogger(__name__)
55 log = logging.getLogger(__name__)
56
56
57 class PasswordGenerator(object):
57 class PasswordGenerator(object):
58 """This is a simple class for generating password from
58 """This is a simple class for generating password from
59 different sets of characters
59 different sets of characters
60 usage:
60 usage:
61 passwd_gen = PasswordGenerator()
61 passwd_gen = PasswordGenerator()
62 #print 8-letter password containing only big and small letters of alphabet
62 #print 8-letter password containing only big and small letters of alphabet
63 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
63 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
64 """
64 """
65 ALPHABETS_NUM = r'''1234567890'''#[0]
65 ALPHABETS_NUM = r'''1234567890'''#[0]
66 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''#[1]
66 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''#[1]
67 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''#[2]
67 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''#[2]
68 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' #[3]
68 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' #[3]
69 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_SPECIAL#[4]
69 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_SPECIAL#[4]
70 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM#[5]
70 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM#[5]
71 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
71 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
72 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
72 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
73 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
73 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
74
74
75 def __init__(self, passwd=''):
75 def __init__(self, passwd=''):
76 self.passwd = passwd
76 self.passwd = passwd
77
77
78 def gen_password(self, len, type):
78 def gen_password(self, len, type):
79 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
79 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
80 return self.passwd
80 return self.passwd
81
81
82 class RhodeCodeCrypto(object):
82 class RhodeCodeCrypto(object):
83
83
84 @classmethod
84 @classmethod
85 def hash_string(cls, str_):
85 def hash_string(cls, str_):
86 """
86 """
87 Cryptographic function used for password hashing based on pybcrypt
87 Cryptographic function used for password hashing based on pybcrypt
88 or pycrypto in windows
88 or pycrypto in windows
89
89
90 :param password: password to hash
90 :param password: password to hash
91 """
91 """
92 if __platform__ in PLATFORM_WIN:
92 if __platform__ in PLATFORM_WIN:
93 return sha256(str_).hexdigest()
93 return sha256(str_).hexdigest()
94 elif __platform__ in PLATFORM_OTHERS:
94 elif __platform__ in PLATFORM_OTHERS:
95 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
95 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
96 else:
96 else:
97 raise Exception('Unknown or unsupported platform %s' % __platform__)
97 raise Exception('Unknown or unsupported platform %s' % __platform__)
98
98
99 @classmethod
99 @classmethod
100 def hash_check(cls, password, hashed):
100 def hash_check(cls, password, hashed):
101 """
101 """
102 Checks matching password with it's hashed value, runs different
102 Checks matching password with it's hashed value, runs different
103 implementation based on platform it runs on
103 implementation based on platform it runs on
104
104
105 :param password: password
105 :param password: password
106 :param hashed: password in hashed form
106 :param hashed: password in hashed form
107 """
107 """
108
108
109 if __platform__ == 'Windows':
109 if __platform__ in PLATFORM_WIN:
110 return sha256(password).hexdigest() == hashed
110 return sha256(password).hexdigest() == hashed
111 elif __platform__ in ('Linux', 'Darwin'):
111 elif __platform__ in PLATFORM_OTHERS:
112 return bcrypt.hashpw(password, hashed) == hashed
112 return bcrypt.hashpw(password, hashed) == hashed
113 else:
113 else:
114 raise Exception('Unknown or unsupported platform %s' % __platform__)
114 raise Exception('Unknown or unsupported platform %s' % __platform__)
115
115
116
116
117 def get_crypt_password(password):
117 def get_crypt_password(password):
118 return RhodeCodeCrypto.hash_string(password)
118 return RhodeCodeCrypto.hash_string(password)
119
119
120 def check_password(password, hashed):
120 def check_password(password, hashed):
121 return RhodeCodeCrypto.hash_check(password, hashed)
121 return RhodeCodeCrypto.hash_check(password, hashed)
122
122
123 def authfunc(environ, username, password):
123 def authfunc(environ, username, password):
124 """
124 """
125 Dummy authentication function used in Mercurial/Git/ and access control,
125 Dummy authentication function used in Mercurial/Git/ and access control,
126
126
127 :param environ: needed only for using in Basic auth
127 :param environ: needed only for using in Basic auth
128 """
128 """
129 return authenticate(username, password)
129 return authenticate(username, password)
130
130
131
131
132 def authenticate(username, password):
132 def authenticate(username, password):
133 """
133 """
134 Authentication function used for access control,
134 Authentication function used for access control,
135 firstly checks for db authentication then if ldap is enabled for ldap
135 firstly checks for db authentication then if ldap is enabled for ldap
136 authentication, also creates ldap user if not in database
136 authentication, also creates ldap user if not in database
137
137
138 :param username: username
138 :param username: username
139 :param password: password
139 :param password: password
140 """
140 """
141 user_model = UserModel()
141 user_model = UserModel()
142 user = user_model.get_by_username(username, cache=False)
142 user = user_model.get_by_username(username, cache=False)
143
143
144 log.debug('Authenticating user using RhodeCode account')
144 log.debug('Authenticating user using RhodeCode account')
145 if user is not None and user.is_ldap is False:
145 if user is not None and user.is_ldap is False:
146 if user.active:
146 if user.active:
147
147
148 if user.username == 'default' and user.active:
148 if user.username == 'default' and user.active:
149 log.info('user %s authenticated correctly as anonymous user',
149 log.info('user %s authenticated correctly as anonymous user',
150 username)
150 username)
151 return True
151 return True
152
152
153 elif user.username == username and check_password(password, user.password):
153 elif user.username == username and check_password(password, user.password):
154 log.info('user %s authenticated correctly', username)
154 log.info('user %s authenticated correctly', username)
155 return True
155 return True
156 else:
156 else:
157 log.warning('user %s is disabled', username)
157 log.warning('user %s is disabled', username)
158
158
159 else:
159 else:
160 log.debug('Regular authentication failed')
160 log.debug('Regular authentication failed')
161 user_obj = user_model.get_by_username(username, cache=False,
161 user_obj = user_model.get_by_username(username, cache=False,
162 case_insensitive=True)
162 case_insensitive=True)
163
163
164 if user_obj is not None and user_obj.is_ldap is False:
164 if user_obj is not None and user_obj.is_ldap is False:
165 log.debug('this user already exists as non ldap')
165 log.debug('this user already exists as non ldap')
166 return False
166 return False
167
167
168 from rhodecode.model.settings import SettingsModel
168 from rhodecode.model.settings import SettingsModel
169 ldap_settings = SettingsModel().get_ldap_settings()
169 ldap_settings = SettingsModel().get_ldap_settings()
170
170
171 #======================================================================
171 #======================================================================
172 # FALLBACK TO LDAP AUTH IN ENABLE
172 # FALLBACK TO LDAP AUTH IN ENABLE
173 #======================================================================
173 #======================================================================
174 if str2bool(ldap_settings.get('ldap_active')):
174 if str2bool(ldap_settings.get('ldap_active')):
175 log.debug("Authenticating user using ldap")
175 log.debug("Authenticating user using ldap")
176 kwargs = {
176 kwargs = {
177 'server':ldap_settings.get('ldap_host', ''),
177 'server':ldap_settings.get('ldap_host', ''),
178 'base_dn':ldap_settings.get('ldap_base_dn', ''),
178 'base_dn':ldap_settings.get('ldap_base_dn', ''),
179 'port':ldap_settings.get('ldap_port'),
179 'port':ldap_settings.get('ldap_port'),
180 'bind_dn':ldap_settings.get('ldap_dn_user'),
180 'bind_dn':ldap_settings.get('ldap_dn_user'),
181 'bind_pass':ldap_settings.get('ldap_dn_pass'),
181 'bind_pass':ldap_settings.get('ldap_dn_pass'),
182 'use_ldaps':str2bool(ldap_settings.get('ldap_ldaps')),
182 'use_ldaps':str2bool(ldap_settings.get('ldap_ldaps')),
183 'ldap_version':3,
183 'ldap_version':3,
184 }
184 }
185 log.debug('Checking for ldap authentication')
185 log.debug('Checking for ldap authentication')
186 try:
186 try:
187 aldap = AuthLdap(**kwargs)
187 aldap = AuthLdap(**kwargs)
188 res = aldap.authenticate_ldap(username, password)
188 res = aldap.authenticate_ldap(username, password)
189 log.debug('Got ldap response %s', res)
189 log.debug('Got ldap response %s', res)
190
190
191 if user_model.create_ldap(username, password):
191 if user_model.create_ldap(username, password):
192 log.info('created new ldap user')
192 log.info('created new ldap user')
193
193
194 return True
194 return True
195 except (LdapUsernameError, LdapPasswordError,):
195 except (LdapUsernameError, LdapPasswordError,):
196 pass
196 pass
197 except (Exception,):
197 except (Exception,):
198 log.error(traceback.format_exc())
198 log.error(traceback.format_exc())
199 pass
199 pass
200 return False
200 return False
201
201
202 class AuthUser(object):
202 class AuthUser(object):
203 """
203 """
204 A simple object that handles a mercurial username for authentication
204 A simple object that handles a mercurial username for authentication
205 """
205 """
206 def __init__(self):
206 def __init__(self):
207 self.username = 'None'
207 self.username = 'None'
208 self.name = ''
208 self.name = ''
209 self.lastname = ''
209 self.lastname = ''
210 self.email = ''
210 self.email = ''
211 self.user_id = None
211 self.user_id = None
212 self.is_authenticated = False
212 self.is_authenticated = False
213 self.is_admin = False
213 self.is_admin = False
214 self.permissions = {}
214 self.permissions = {}
215
215
216 def __repr__(self):
216 def __repr__(self):
217 return "<AuthUser('id:%s:%s')>" % (self.user_id, self.username)
217 return "<AuthUser('id:%s:%s')>" % (self.user_id, self.username)
218
218
219 def set_available_permissions(config):
219 def set_available_permissions(config):
220 """
220 """
221 This function will propagate pylons globals with all available defined
221 This function will propagate pylons globals with all available defined
222 permission given in db. We don't wannt to check each time from db for new
222 permission given in db. We don't wannt to check each time from db for new
223 permissions since adding a new permission also requires application restart
223 permissions since adding a new permission also requires application restart
224 ie. to decorate new views with the newly created permission
224 ie. to decorate new views with the newly created permission
225 :param config:
225 :param config:
226 """
226 """
227 log.info('getting information about all available permissions')
227 log.info('getting information about all available permissions')
228 try:
228 try:
229 sa = meta.Session()
229 sa = meta.Session()
230 all_perms = sa.query(Permission).all()
230 all_perms = sa.query(Permission).all()
231 except:
231 except:
232 pass
232 pass
233 finally:
233 finally:
234 meta.Session.remove()
234 meta.Session.remove()
235
235
236 config['available_permissions'] = [x.permission_name for x in all_perms]
236 config['available_permissions'] = [x.permission_name for x in all_perms]
237
237
238 def set_base_path(config):
238 def set_base_path(config):
239 config['base_path'] = config['pylons.app_globals'].base_path
239 config['base_path'] = config['pylons.app_globals'].base_path
240
240
241
241
242 def fill_perms(user):
242 def fill_perms(user):
243 """
243 """
244 Fills user permission attribute with permissions taken from database
244 Fills user permission attribute with permissions taken from database
245 :param user:
245 :param user:
246 """
246 """
247
247
248 sa = meta.Session()
248 sa = meta.Session()
249 user.permissions['repositories'] = {}
249 user.permissions['repositories'] = {}
250 user.permissions['global'] = set()
250 user.permissions['global'] = set()
251
251
252 #===========================================================================
252 #===========================================================================
253 # fetch default permissions
253 # fetch default permissions
254 #===========================================================================
254 #===========================================================================
255 default_user = UserModel().get_by_username('default', cache=True)
255 default_user = UserModel().get_by_username('default', cache=True)
256
256
257 default_perms = sa.query(RepoToPerm, Repository, Permission)\
257 default_perms = sa.query(RepoToPerm, Repository, Permission)\
258 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
258 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
259 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
259 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
260 .filter(RepoToPerm.user == default_user).all()
260 .filter(RepoToPerm.user == default_user).all()
261
261
262 if user.is_admin:
262 if user.is_admin:
263 #=======================================================================
263 #=======================================================================
264 # #admin have all default rights set to admin
264 # #admin have all default rights set to admin
265 #=======================================================================
265 #=======================================================================
266 user.permissions['global'].add('hg.admin')
266 user.permissions['global'].add('hg.admin')
267
267
268 for perm in default_perms:
268 for perm in default_perms:
269 p = 'repository.admin'
269 p = 'repository.admin'
270 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
270 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
271
271
272 else:
272 else:
273 #=======================================================================
273 #=======================================================================
274 # set default permissions
274 # set default permissions
275 #=======================================================================
275 #=======================================================================
276
276
277 #default global
277 #default global
278 default_global_perms = sa.query(UserToPerm)\
278 default_global_perms = sa.query(UserToPerm)\
279 .filter(UserToPerm.user == sa.query(User)\
279 .filter(UserToPerm.user == sa.query(User)\
280 .filter(User.username == 'default').one())
280 .filter(User.username == 'default').one())
281
281
282 for perm in default_global_perms:
282 for perm in default_global_perms:
283 user.permissions['global'].add(perm.permission.permission_name)
283 user.permissions['global'].add(perm.permission.permission_name)
284
284
285 #default repositories
285 #default repositories
286 for perm in default_perms:
286 for perm in default_perms:
287 if perm.Repository.private and not perm.Repository.user_id == user.user_id:
287 if perm.Repository.private and not perm.Repository.user_id == user.user_id:
288 #disable defaults for private repos,
288 #disable defaults for private repos,
289 p = 'repository.none'
289 p = 'repository.none'
290 elif perm.Repository.user_id == user.user_id:
290 elif perm.Repository.user_id == user.user_id:
291 #set admin if owner
291 #set admin if owner
292 p = 'repository.admin'
292 p = 'repository.admin'
293 else:
293 else:
294 p = perm.Permission.permission_name
294 p = perm.Permission.permission_name
295
295
296 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
296 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
297
297
298 #=======================================================================
298 #=======================================================================
299 # #overwrite default with user permissions if any
299 # #overwrite default with user permissions if any
300 #=======================================================================
300 #=======================================================================
301 user_perms = sa.query(RepoToPerm, Permission, Repository)\
301 user_perms = sa.query(RepoToPerm, Permission, Repository)\
302 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
302 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
303 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
303 .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
304 .filter(RepoToPerm.user_id == user.user_id).all()
304 .filter(RepoToPerm.user_id == user.user_id).all()
305
305
306 for perm in user_perms:
306 for perm in user_perms:
307 if perm.Repository.user_id == user.user_id:#set admin if owner
307 if perm.Repository.user_id == user.user_id:#set admin if owner
308 p = 'repository.admin'
308 p = 'repository.admin'
309 else:
309 else:
310 p = perm.Permission.permission_name
310 p = perm.Permission.permission_name
311 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
311 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
312 meta.Session.remove()
312 meta.Session.remove()
313 return user
313 return user
314
314
315 def get_user(session):
315 def get_user(session):
316 """
316 """
317 Gets user from session, and wraps permissions into user
317 Gets user from session, and wraps permissions into user
318 :param session:
318 :param session:
319 """
319 """
320 user = session.get('rhodecode_user', AuthUser())
320 user = session.get('rhodecode_user', AuthUser())
321 #if the user is not logged in we check for anonymous access
321 #if the user is not logged in we check for anonymous access
322 #if user is logged and it's a default user check if we still have anonymous
322 #if user is logged and it's a default user check if we still have anonymous
323 #access enabled
323 #access enabled
324 if user.user_id is None or user.username == 'default':
324 if user.user_id is None or user.username == 'default':
325 anonymous_user = UserModel().get_by_username('default', cache=True)
325 anonymous_user = UserModel().get_by_username('default', cache=True)
326 if anonymous_user.active is True:
326 if anonymous_user.active is True:
327 #then we set this user is logged in
327 #then we set this user is logged in
328 user.is_authenticated = True
328 user.is_authenticated = True
329 user.user_id = anonymous_user.user_id
329 user.user_id = anonymous_user.user_id
330 else:
330 else:
331 user.is_authenticated = False
331 user.is_authenticated = False
332
332
333 if user.is_authenticated:
333 if user.is_authenticated:
334 user = UserModel().fill_data(user)
334 user = UserModel().fill_data(user)
335
335
336 user = fill_perms(user)
336 user = fill_perms(user)
337 session['rhodecode_user'] = user
337 session['rhodecode_user'] = user
338 session.save()
338 session.save()
339 return user
339 return user
340
340
341 #===============================================================================
341 #===============================================================================
342 # CHECK DECORATORS
342 # CHECK DECORATORS
343 #===============================================================================
343 #===============================================================================
344 class LoginRequired(object):
344 class LoginRequired(object):
345 """Must be logged in to execute this function else
345 """Must be logged in to execute this function else
346 redirect to login page"""
346 redirect to login page"""
347
347
348 def __call__(self, func):
348 def __call__(self, func):
349 return decorator(self.__wrapper, func)
349 return decorator(self.__wrapper, func)
350
350
351 def __wrapper(self, func, *fargs, **fkwargs):
351 def __wrapper(self, func, *fargs, **fkwargs):
352 user = session.get('rhodecode_user', AuthUser())
352 user = session.get('rhodecode_user', AuthUser())
353 log.debug('Checking login required for user:%s', user.username)
353 log.debug('Checking login required for user:%s', user.username)
354 if user.is_authenticated:
354 if user.is_authenticated:
355 log.debug('user %s is authenticated', user.username)
355 log.debug('user %s is authenticated', user.username)
356 return func(*fargs, **fkwargs)
356 return func(*fargs, **fkwargs)
357 else:
357 else:
358 log.warn('user %s not authenticated', user.username)
358 log.warn('user %s not authenticated', user.username)
359
359
360 p = ''
360 p = ''
361 if request.environ.get('SCRIPT_NAME') != '/':
361 if request.environ.get('SCRIPT_NAME') != '/':
362 p += request.environ.get('SCRIPT_NAME')
362 p += request.environ.get('SCRIPT_NAME')
363
363
364 p += request.environ.get('PATH_INFO')
364 p += request.environ.get('PATH_INFO')
365 if request.environ.get('QUERY_STRING'):
365 if request.environ.get('QUERY_STRING'):
366 p += '?' + request.environ.get('QUERY_STRING')
366 p += '?' + request.environ.get('QUERY_STRING')
367
367
368 log.debug('redirecting to login page with %s', p)
368 log.debug('redirecting to login page with %s', p)
369 return redirect(url('login_home', came_from=p))
369 return redirect(url('login_home', came_from=p))
370
370
371 class NotAnonymous(object):
371 class NotAnonymous(object):
372 """Must be logged in to execute this function else
372 """Must be logged in to execute this function else
373 redirect to login page"""
373 redirect to login page"""
374
374
375 def __call__(self, func):
375 def __call__(self, func):
376 return decorator(self.__wrapper, func)
376 return decorator(self.__wrapper, func)
377
377
378 def __wrapper(self, func, *fargs, **fkwargs):
378 def __wrapper(self, func, *fargs, **fkwargs):
379 user = session.get('rhodecode_user', AuthUser())
379 user = session.get('rhodecode_user', AuthUser())
380 log.debug('Checking if user is not anonymous')
380 log.debug('Checking if user is not anonymous')
381
381
382 anonymous = user.username == 'default'
382 anonymous = user.username == 'default'
383
383
384 if anonymous:
384 if anonymous:
385 p = ''
385 p = ''
386 if request.environ.get('SCRIPT_NAME') != '/':
386 if request.environ.get('SCRIPT_NAME') != '/':
387 p += request.environ.get('SCRIPT_NAME')
387 p += request.environ.get('SCRIPT_NAME')
388
388
389 p += request.environ.get('PATH_INFO')
389 p += request.environ.get('PATH_INFO')
390 if request.environ.get('QUERY_STRING'):
390 if request.environ.get('QUERY_STRING'):
391 p += '?' + request.environ.get('QUERY_STRING')
391 p += '?' + request.environ.get('QUERY_STRING')
392 return redirect(url('login_home', came_from=p))
392 return redirect(url('login_home', came_from=p))
393 else:
393 else:
394 return func(*fargs, **fkwargs)
394 return func(*fargs, **fkwargs)
395
395
396 class PermsDecorator(object):
396 class PermsDecorator(object):
397 """Base class for decorators"""
397 """Base class for decorators"""
398
398
399 def __init__(self, *required_perms):
399 def __init__(self, *required_perms):
400 available_perms = config['available_permissions']
400 available_perms = config['available_permissions']
401 for perm in required_perms:
401 for perm in required_perms:
402 if perm not in available_perms:
402 if perm not in available_perms:
403 raise Exception("'%s' permission is not defined" % perm)
403 raise Exception("'%s' permission is not defined" % perm)
404 self.required_perms = set(required_perms)
404 self.required_perms = set(required_perms)
405 self.user_perms = None
405 self.user_perms = None
406
406
407 def __call__(self, func):
407 def __call__(self, func):
408 return decorator(self.__wrapper, func)
408 return decorator(self.__wrapper, func)
409
409
410
410
411 def __wrapper(self, func, *fargs, **fkwargs):
411 def __wrapper(self, func, *fargs, **fkwargs):
412 # _wrapper.__name__ = func.__name__
412 # _wrapper.__name__ = func.__name__
413 # _wrapper.__dict__.update(func.__dict__)
413 # _wrapper.__dict__.update(func.__dict__)
414 # _wrapper.__doc__ = func.__doc__
414 # _wrapper.__doc__ = func.__doc__
415 self.user = session.get('rhodecode_user', AuthUser())
415 self.user = session.get('rhodecode_user', AuthUser())
416 self.user_perms = self.user.permissions
416 self.user_perms = self.user.permissions
417 log.debug('checking %s permissions %s for %s %s',
417 log.debug('checking %s permissions %s for %s %s',
418 self.__class__.__name__, self.required_perms, func.__name__,
418 self.__class__.__name__, self.required_perms, func.__name__,
419 self.user)
419 self.user)
420
420
421 if self.check_permissions():
421 if self.check_permissions():
422 log.debug('Permission granted for %s %s', func.__name__, self.user)
422 log.debug('Permission granted for %s %s', func.__name__, self.user)
423
423
424 return func(*fargs, **fkwargs)
424 return func(*fargs, **fkwargs)
425
425
426 else:
426 else:
427 log.warning('Permission denied for %s %s', func.__name__, self.user)
427 log.warning('Permission denied for %s %s', func.__name__, self.user)
428 #redirect with forbidden ret code
428 #redirect with forbidden ret code
429 return abort(403)
429 return abort(403)
430
430
431
431
432
432
433 def check_permissions(self):
433 def check_permissions(self):
434 """Dummy function for overriding"""
434 """Dummy function for overriding"""
435 raise Exception('You have to write this function in child class')
435 raise Exception('You have to write this function in child class')
436
436
437 class HasPermissionAllDecorator(PermsDecorator):
437 class HasPermissionAllDecorator(PermsDecorator):
438 """Checks for access permission for all given predicates. All of them
438 """Checks for access permission for all given predicates. All of them
439 have to be meet in order to fulfill the request
439 have to be meet in order to fulfill the request
440 """
440 """
441
441
442 def check_permissions(self):
442 def check_permissions(self):
443 if self.required_perms.issubset(self.user_perms.get('global')):
443 if self.required_perms.issubset(self.user_perms.get('global')):
444 return True
444 return True
445 return False
445 return False
446
446
447
447
448 class HasPermissionAnyDecorator(PermsDecorator):
448 class HasPermissionAnyDecorator(PermsDecorator):
449 """Checks for access permission for any of given predicates. In order to
449 """Checks for access permission for any of given predicates. In order to
450 fulfill the request any of predicates must be meet
450 fulfill the request any of predicates must be meet
451 """
451 """
452
452
453 def check_permissions(self):
453 def check_permissions(self):
454 if self.required_perms.intersection(self.user_perms.get('global')):
454 if self.required_perms.intersection(self.user_perms.get('global')):
455 return True
455 return True
456 return False
456 return False
457
457
458 class HasRepoPermissionAllDecorator(PermsDecorator):
458 class HasRepoPermissionAllDecorator(PermsDecorator):
459 """Checks for access permission for all given predicates for specific
459 """Checks for access permission for all given predicates for specific
460 repository. All of them have to be meet in order to fulfill the request
460 repository. All of them have to be meet in order to fulfill the request
461 """
461 """
462
462
463 def check_permissions(self):
463 def check_permissions(self):
464 repo_name = get_repo_slug(request)
464 repo_name = get_repo_slug(request)
465 try:
465 try:
466 user_perms = set([self.user_perms['repositories'][repo_name]])
466 user_perms = set([self.user_perms['repositories'][repo_name]])
467 except KeyError:
467 except KeyError:
468 return False
468 return False
469 if self.required_perms.issubset(user_perms):
469 if self.required_perms.issubset(user_perms):
470 return True
470 return True
471 return False
471 return False
472
472
473
473
474 class HasRepoPermissionAnyDecorator(PermsDecorator):
474 class HasRepoPermissionAnyDecorator(PermsDecorator):
475 """Checks for access permission for any of given predicates for specific
475 """Checks for access permission for any of given predicates for specific
476 repository. In order to fulfill the request any of predicates must be meet
476 repository. In order to fulfill the request any of predicates must be meet
477 """
477 """
478
478
479 def check_permissions(self):
479 def check_permissions(self):
480 repo_name = get_repo_slug(request)
480 repo_name = get_repo_slug(request)
481
481
482 try:
482 try:
483 user_perms = set([self.user_perms['repositories'][repo_name]])
483 user_perms = set([self.user_perms['repositories'][repo_name]])
484 except KeyError:
484 except KeyError:
485 return False
485 return False
486 if self.required_perms.intersection(user_perms):
486 if self.required_perms.intersection(user_perms):
487 return True
487 return True
488 return False
488 return False
489 #===============================================================================
489 #===============================================================================
490 # CHECK FUNCTIONS
490 # CHECK FUNCTIONS
491 #===============================================================================
491 #===============================================================================
492
492
493 class PermsFunction(object):
493 class PermsFunction(object):
494 """Base function for other check functions"""
494 """Base function for other check functions"""
495
495
496 def __init__(self, *perms):
496 def __init__(self, *perms):
497 available_perms = config['available_permissions']
497 available_perms = config['available_permissions']
498
498
499 for perm in perms:
499 for perm in perms:
500 if perm not in available_perms:
500 if perm not in available_perms:
501 raise Exception("'%s' permission in not defined" % perm)
501 raise Exception("'%s' permission in not defined" % perm)
502 self.required_perms = set(perms)
502 self.required_perms = set(perms)
503 self.user_perms = None
503 self.user_perms = None
504 self.granted_for = ''
504 self.granted_for = ''
505 self.repo_name = None
505 self.repo_name = None
506
506
507 def __call__(self, check_Location=''):
507 def __call__(self, check_Location=''):
508 user = session.get('rhodecode_user', False)
508 user = session.get('rhodecode_user', False)
509 if not user:
509 if not user:
510 return False
510 return False
511 self.user_perms = user.permissions
511 self.user_perms = user.permissions
512 self.granted_for = user.username
512 self.granted_for = user.username
513 log.debug('checking %s %s %s', self.__class__.__name__,
513 log.debug('checking %s %s %s', self.__class__.__name__,
514 self.required_perms, user)
514 self.required_perms, user)
515
515
516 if self.check_permissions():
516 if self.check_permissions():
517 log.debug('Permission granted for %s @ %s %s', self.granted_for,
517 log.debug('Permission granted for %s @ %s %s', self.granted_for,
518 check_Location, user)
518 check_Location, user)
519 return True
519 return True
520
520
521 else:
521 else:
522 log.warning('Permission denied for %s @ %s %s', self.granted_for,
522 log.warning('Permission denied for %s @ %s %s', self.granted_for,
523 check_Location, user)
523 check_Location, user)
524 return False
524 return False
525
525
526 def check_permissions(self):
526 def check_permissions(self):
527 """Dummy function for overriding"""
527 """Dummy function for overriding"""
528 raise Exception('You have to write this function in child class')
528 raise Exception('You have to write this function in child class')
529
529
530 class HasPermissionAll(PermsFunction):
530 class HasPermissionAll(PermsFunction):
531 def check_permissions(self):
531 def check_permissions(self):
532 if self.required_perms.issubset(self.user_perms.get('global')):
532 if self.required_perms.issubset(self.user_perms.get('global')):
533 return True
533 return True
534 return False
534 return False
535
535
536 class HasPermissionAny(PermsFunction):
536 class HasPermissionAny(PermsFunction):
537 def check_permissions(self):
537 def check_permissions(self):
538 if self.required_perms.intersection(self.user_perms.get('global')):
538 if self.required_perms.intersection(self.user_perms.get('global')):
539 return True
539 return True
540 return False
540 return False
541
541
542 class HasRepoPermissionAll(PermsFunction):
542 class HasRepoPermissionAll(PermsFunction):
543
543
544 def __call__(self, repo_name=None, check_Location=''):
544 def __call__(self, repo_name=None, check_Location=''):
545 self.repo_name = repo_name
545 self.repo_name = repo_name
546 return super(HasRepoPermissionAll, self).__call__(check_Location)
546 return super(HasRepoPermissionAll, self).__call__(check_Location)
547
547
548 def check_permissions(self):
548 def check_permissions(self):
549 if not self.repo_name:
549 if not self.repo_name:
550 self.repo_name = get_repo_slug(request)
550 self.repo_name = get_repo_slug(request)
551
551
552 try:
552 try:
553 self.user_perms = set([self.user_perms['repositories']\
553 self.user_perms = set([self.user_perms['repositories']\
554 [self.repo_name]])
554 [self.repo_name]])
555 except KeyError:
555 except KeyError:
556 return False
556 return False
557 self.granted_for = self.repo_name
557 self.granted_for = self.repo_name
558 if self.required_perms.issubset(self.user_perms):
558 if self.required_perms.issubset(self.user_perms):
559 return True
559 return True
560 return False
560 return False
561
561
562 class HasRepoPermissionAny(PermsFunction):
562 class HasRepoPermissionAny(PermsFunction):
563
563
564 def __call__(self, repo_name=None, check_Location=''):
564 def __call__(self, repo_name=None, check_Location=''):
565 self.repo_name = repo_name
565 self.repo_name = repo_name
566 return super(HasRepoPermissionAny, self).__call__(check_Location)
566 return super(HasRepoPermissionAny, self).__call__(check_Location)
567
567
568 def check_permissions(self):
568 def check_permissions(self):
569 if not self.repo_name:
569 if not self.repo_name:
570 self.repo_name = get_repo_slug(request)
570 self.repo_name = get_repo_slug(request)
571
571
572 try:
572 try:
573 self.user_perms = set([self.user_perms['repositories']\
573 self.user_perms = set([self.user_perms['repositories']\
574 [self.repo_name]])
574 [self.repo_name]])
575 except KeyError:
575 except KeyError:
576 return False
576 return False
577 self.granted_for = self.repo_name
577 self.granted_for = self.repo_name
578 if self.required_perms.intersection(self.user_perms):
578 if self.required_perms.intersection(self.user_perms):
579 return True
579 return True
580 return False
580 return False
581
581
582 #===============================================================================
582 #===============================================================================
583 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
583 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
584 #===============================================================================
584 #===============================================================================
585
585
586 class HasPermissionAnyMiddleware(object):
586 class HasPermissionAnyMiddleware(object):
587 def __init__(self, *perms):
587 def __init__(self, *perms):
588 self.required_perms = set(perms)
588 self.required_perms = set(perms)
589
589
590 def __call__(self, user, repo_name):
590 def __call__(self, user, repo_name):
591 usr = AuthUser()
591 usr = AuthUser()
592 usr.user_id = user.user_id
592 usr.user_id = user.user_id
593 usr.username = user.username
593 usr.username = user.username
594 usr.is_admin = user.admin
594 usr.is_admin = user.admin
595
595
596 try:
596 try:
597 self.user_perms = set([fill_perms(usr)\
597 self.user_perms = set([fill_perms(usr)\
598 .permissions['repositories'][repo_name]])
598 .permissions['repositories'][repo_name]])
599 except:
599 except:
600 self.user_perms = set()
600 self.user_perms = set()
601 self.granted_for = ''
601 self.granted_for = ''
602 self.username = user.username
602 self.username = user.username
603 self.repo_name = repo_name
603 self.repo_name = repo_name
604 return self.check_permissions()
604 return self.check_permissions()
605
605
606 def check_permissions(self):
606 def check_permissions(self):
607 log.debug('checking mercurial protocol '
607 log.debug('checking mercurial protocol '
608 'permissions for user:%s repository:%s',
608 'permissions for user:%s repository:%s',
609 self.username, self.repo_name)
609 self.username, self.repo_name)
610 if self.required_perms.intersection(self.user_perms):
610 if self.required_perms.intersection(self.user_perms):
611 log.debug('permission granted')
611 log.debug('permission granted')
612 return True
612 return True
613 log.debug('permission denied')
613 log.debug('permission denied')
614 return False
614 return False
General Comments 0
You need to be logged in to leave comments. Login now