##// END OF EJS Templates
Full rewrite of auth module, new functions/decorators. FIxed auth user
marcink -
r316:d6e28177 default
parent child Browse files
Show More
@@ -24,14 +24,16 Created on April 4, 2010
24 24 """
25 25
26 26 from functools import wraps
27 from pylons import session, url, app_globals as g
27 from pylons import session, url, request
28 28 from pylons.controllers.util import abort, redirect
29 29 from pylons_app.model import meta
30 from pylons_app.model.db import User, Repo2Perm
30 from pylons_app.model.db import User, Repo2Perm, Repository, Permission
31 from pylons_app.lib.utils import get_repo_slug
31 32 from sqlalchemy.exc import OperationalError
32 33 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
33 34 import crypt
34 35 import logging
36 from pylons import config
35 37 log = logging.getLogger(__name__)
36 38
37 39 def get_crypt_password(password):
@@ -64,16 +66,12 class AuthUser(object):
64 66 """
65 67 A simple object that handles a mercurial username for authentication
66 68 """
67 username = 'None'
68 user_id = None
69 is_authenticated = False
70 is_admin = False
71 permissions = set()
72 group = set()
73
74 69 def __init__(self):
75 pass
76
70 self.username = 'None'
71 self.user_id = None
72 self.is_authenticated = False
73 self.is_admin = False
74 self.permissions = {}
77 75
78 76
79 77 def set_available_permissions(config):
@@ -84,12 +82,60 def set_available_permissions(config):
84 82 ie. to decorate new views with the newly created permission
85 83 @param config:
86 84 """
87 from pylons_app.model.meta import Session
88 from pylons_app.model.db import Permission
89 logging.info('getting information about all available permissions')
90 sa = Session()
85 log.info('getting information about all available permissions')
86 sa = meta.Session
91 87 all_perms = sa.query(Permission).all()
92 config['pylons.app_globals'].available_permissions = [x.permission_name for x in all_perms]
88 config['available_permissions'] = [x.permission_name for x in all_perms]
89
90 def set_base_path(config):
91 config['base_path'] = config['pylons.app_globals'].base_path
92
93 def fill_perms(user):
94 sa = meta.Session
95 user.permissions['repositories'] = {}
96
97 #first fetch default permissions
98 default_perms = sa.query(Repo2Perm, Repository, Permission)\
99 .join((Repository, Repo2Perm.repository == Repository.repo_name))\
100 .join((Permission, Repo2Perm.permission_id == Permission.permission_id))\
101 .filter(Repo2Perm.user_id == sa.query(User).filter(User.username ==
102 'default').one().user_id).all()
103
104 if user.is_admin:
105 user.permissions['global'] = set(['hg.admin'])
106 #admin have all rights full
107 for perm in default_perms:
108 p = 'repository.admin'
109 user.permissions['repositories'][perm.Repo2Perm.repository] = p
110
111 else:
112 user.permissions['global'] = set()
113 for perm in default_perms:
114 if perm.Repository.private:
115 #disable defaults for private repos,
116 p = 'repository.none'
117 elif perm.Repository.user_id == user.user_id:
118 #set admin if owner
119 p = 'repository.admin'
120 else:
121 p = perm.Permission.permission_name
122
123 user.permissions['repositories'][perm.Repo2Perm.repository] = p
124
125
126 user_perms = sa.query(Repo2Perm, Permission, Repository)\
127 .join((Repository, Repo2Perm.repository == Repository.repo_name))\
128 .join((Permission, Repo2Perm.permission_id == Permission.permission_id))\
129 .filter(Repo2Perm.user_id == user.user_id).all()
130 #overwrite userpermissions with defaults
131 for perm in user_perms:
132 #set write if owner
133 if perm.Repository.user_id == user.user_id:
134 p = 'repository.write'
135 else:
136 p = perm.Permission.permission_name
137 user.permissions['repositories'][perm.Repo2Perm.repository] = p
138 return user
93 139
94 140 def get_user(session):
95 141 """
@@ -97,94 +143,243 def get_user(session):
97 143 @param session:
98 144 """
99 145 user = session.get('hg_app_user', AuthUser())
146
100 147 if user.is_authenticated:
101 sa = meta.Session
102 user.permissions = sa.query(Repo2Perm)\
103 .filter(Repo2Perm.user_id == user.user_id).all()
148 user = fill_perms(user)
104 149
150 session['hg_app_user'] = user
151 session.save()
105 152 return user
106 153
107 154 #===============================================================================
108 # DECORATORS
155 # CHECK DECORATORS
109 156 #===============================================================================
110 157 class LoginRequired(object):
111 158 """
112 159 Must be logged in to execute this function else redirect to login page
113 160 """
114 def __init__(self):
115 pass
116 161
117 162 def __call__(self, func):
118
119 163 @wraps(func)
120 164 def _wrapper(*fargs, **fkwargs):
121 165 user = session.get('hg_app_user', AuthUser())
122 log.info('Checking login required for user:%s', user.username)
166 log.debug('Checking login required for user:%s', user.username)
123 167 if user.is_authenticated:
124 log.info('user %s is authenticated', user.username)
168 log.debug('user %s is authenticated', user.username)
125 169 func(*fargs)
126 170 else:
127 logging.info('user %s not authenticated', user.username)
128 logging.info('redirecting to login page')
171 log.warn('user %s not authenticated', user.username)
172 log.debug('redirecting to login page')
129 173 return redirect(url('login_home'))
130 174
131 175 return _wrapper
132 176
133 177 class PermsDecorator(object):
178 """
179 Base class for decorators
180 """
134 181
135 def __init__(self, *perms):
136 available_perms = g.available_permissions
137 for perm in perms:
182 def __init__(self, *required_perms):
183 available_perms = config['available_permissions']
184 for perm in required_perms:
138 185 if perm not in available_perms:
139 raise Exception("'%s' permission in not defined" % perm)
140 self.required_perms = set(perms)
141 self.user_perms = set([])#propagate this list from somewhere.
186 raise Exception("'%s' permission is not defined" % perm)
187 self.required_perms = set(required_perms)
188 self.user_perms = None
142 189
143 190 def __call__(self, func):
144 191 @wraps(func)
145 def _wrapper(*args, **kwargs):
146 logging.info('checking %s permissions %s for %s',
147 self.__class__.__name__[-3:], self.required_perms, func.__name__)
192 def _wrapper(*fargs, **fkwargs):
193 self.user_perms = session.get('hg_app_user', AuthUser()).permissions
194 log.debug('checking %s permissions %s for %s',
195 self.__class__.__name__, self.required_perms, func.__name__)
148 196
149 197 if self.check_permissions():
150 logging.info('Permission granted for %s', func.__name__)
151 return func(*args, **kwargs)
198 log.debug('Permission granted for %s', func.__name__)
199 return func(*fargs)
152 200
153 201 else:
154 logging.warning('Permission denied for %s', func.__name__)
202 log.warning('Permission denied for %s', func.__name__)
155 203 #redirect with forbidden ret code
156 return redirect(url('access_denied'), 403)
204 return abort(403)
157 205 return _wrapper
158 206
159 207
160 208 def check_permissions(self):
161 209 """
162 Dummy function for overiding
210 Dummy function for overriding
163 211 """
164 212 raise Exception('You have to write this function in child class')
165 213
166 class CheckPermissionAll(PermsDecorator):
214 class HasPermissionAllDecorator(PermsDecorator):
167 215 """
168 216 Checks for access permission for all given predicates. All of them have to
169 217 be meet in order to fulfill the request
170 218 """
171 219
172 220 def check_permissions(self):
173 if self.required_perms.issubset(self.user_perms):
221 if self.required_perms.issubset(self.user_perms['global']):
174 222 return True
175 223 return False
176 224
177 225
178 class CheckPermissionAny(PermsDecorator):
226 class HasPermissionAnyDecorator(PermsDecorator):
179 227 """
180 228 Checks for access permission for any of given predicates. In order to
181 229 fulfill the request any of predicates must be meet
182 230 """
183 231
184 232 def check_permissions(self):
233 if self.required_perms.intersection(self.user_perms['global']):
234 return True
235 return False
236
237 class HasRepoPermissionAllDecorator(PermsDecorator):
238 """
239 Checks for access permission for all given predicates for specific
240 repository. All of them have to be meet in order to fulfill the request
241 """
242
243 def check_permissions(self):
244 repo_name = get_repo_slug(request)
245 user_perms = set([self.user_perms['repositories'][repo_name]])
246 if self.required_perms.issubset(user_perms):
247 return True
248 return False
249
250
251 class HasRepoPermissionAnyDecorator(PermsDecorator):
252 """
253 Checks for access permission for any of given predicates for specific
254 repository. In order to fulfill the request any of predicates must be meet
255 """
256
257 def check_permissions(self):
258 repo_name = get_repo_slug(request)
259
260 user_perms = set([self.user_perms['repositories'][repo_name]])
261 if self.required_perms.intersection(user_perms):
262 return True
263 return False
264 #===============================================================================
265 # CHECK FUNCTIONS
266 #===============================================================================
267
268 class PermsFunction(object):
269 """
270 Base function for other check functions
271 """
272
273 def __init__(self, *perms):
274 available_perms = config['available_permissions']
275
276 for perm in perms:
277 if perm not in available_perms:
278 raise Exception("'%s' permission in not defined" % perm)
279 self.required_perms = set(perms)
280 self.user_perms = None
281 self.granted_for = ''
282 self.repo_name = None
283
284 def __call__(self, check_Location=''):
285 user = session['hg_app_user']
286 self.user_perms = user.permissions
287 self.granted_for = user.username
288 log.debug('checking %s %s', self.__class__.__name__, self.required_perms)
289
290 if self.check_permissions():
291 log.debug('Permission granted for %s @%s', self.granted_for,
292 check_Location)
293 return True
294
295 else:
296 log.warning('Permission denied for %s @%s', self.granted_for,
297 check_Location)
298 return False
299
300 def check_permissions(self):
301 """
302 Dummy function for overriding
303 """
304 raise Exception('You have to write this function in child class')
305
306 class HasPermissionAll(PermsFunction):
307 def check_permissions(self):
308 if self.required_perms.issubset(self.user_perms['global']):
309 return True
310 return False
311
312 class HasPermissionAny(PermsFunction):
313 def check_permissions(self):
314 if self.required_perms.intersection(self.user_perms['global']):
315 return True
316 return False
317
318 class HasRepoPermissionAll(PermsFunction):
319
320 def __call__(self, repo_name=None, check_Location=''):
321 self.repo_name = repo_name
322 return super(HasRepoPermissionAll, self).__call__(check_Location)
323
324 def check_permissions(self):
325 if not self.repo_name:
326 self.repo_name = get_repo_slug(request)
327
328 self.user_perms = set([self.user_perms['repositories']\
329 .get(self.repo_name)])
330 self.granted_for = self.repo_name
331 if self.required_perms.issubset(self.user_perms):
332 return True
333 return False
334
335 class HasRepoPermissionAny(PermsFunction):
336
337
338 def __call__(self, repo_name=None, check_Location=''):
339 self.repo_name = repo_name
340 return super(HasRepoPermissionAny, self).__call__(check_Location)
341
342 def check_permissions(self):
343 if not self.repo_name:
344 self.repo_name = get_repo_slug(request)
345
346 self.user_perms = set([self.user_perms['repositories']\
347 .get(self.repo_name)])
348 self.granted_for = self.repo_name
185 349 if self.required_perms.intersection(self.user_perms):
186 350 return True
187 351 return False
188 352
353 #===============================================================================
354 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
355 #===============================================================================
189 356
357 class HasPermissionAnyMiddleware(object):
358 def __init__(self, *perms):
359 self.required_perms = set(perms)
190 360
361 def __call__(self, user, repo_name):
362 usr = AuthUser()
363 usr.user_id = user.user_id
364 usr.username = user.username
365 usr.is_admin = user.admin
366
367 try:
368 self.user_perms = set([fill_perms(usr)\
369 .permissions['repositories'][repo_name]])
370 except:
371 self.user_perms = set()
372 self.granted_for = ''
373 self.username = user.username
374 self.repo_name = repo_name
375 return self.check_permissions()
376
377 def check_permissions(self):
378 log.debug('checking mercurial protocol '
379 'permissions for user:%s repository:%s',
380 self.username, self.repo_name)
381 if self.required_perms.intersection(self.user_perms):
382 log.debug('permission granted')
383 return True
384 log.debug('permission denied')
385 return False
General Comments 0
You need to be logged in to leave comments. Login now