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