Mercurial > public > src > rhodecode
comparison pylons_app/lib/auth.py @ 409:bd8b25ad058d
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Sat, 31 Jul 2010 18:47:43 +0200 |
parents | 5cd6616b8673 |
children | ca54622e39a1 |
comparison
equal
deleted
inserted
replaced
408:7fbf81447c6c | 409:bd8b25ad058d |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # encoding: utf-8 | 2 # encoding: utf-8 |
3 # authentication and permission libraries | 3 # authentication and permission libraries |
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> | 4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> |
5 | 5 # |
6 # This program is free software; you can redistribute it and/or | 6 # This program is free software; you can redistribute it and/or |
7 # modify it under the terms of the GNU General Public License | 7 # modify it under the terms of the GNU General Public License |
8 # as published by the Free Software Foundation; version 2 | 8 # as published by the Free Software Foundation; version 2 |
9 # of the License or (at your opinion) any later version of the license. | 9 # of the License or (at your opinion) any later version of the license. |
10 # | 10 # |
15 # | 15 # |
16 # You should have received a copy of the GNU General Public License | 16 # You should have received a copy of the GNU General Public License |
17 # along with this program; if not, write to the Free Software | 17 # along with this program; if not, write to the Free Software |
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
19 # MA 02110-1301, USA. | 19 # MA 02110-1301, USA. |
20 """ | |
21 Created on April 4, 2010 | |
22 | |
23 @author: marcink | |
24 """ | |
25 from beaker.cache import cache_region | 20 from beaker.cache import cache_region |
26 from functools import wraps | |
27 from pylons import config, session, url, request | 21 from pylons import config, session, url, request |
28 from pylons.controllers.util import abort, redirect | 22 from pylons.controllers.util import abort, redirect |
29 from pylons_app.lib.utils import get_repo_slug | 23 from pylons_app.lib.utils import get_repo_slug |
30 from pylons_app.model import meta | 24 from pylons_app.model import meta |
31 from pylons_app.model.db import User, Repo2Perm, Repository, Permission | 25 from pylons_app.model.db import User, Repo2Perm, Repository, Permission |
32 from sqlalchemy.exc import OperationalError | 26 from sqlalchemy.exc import OperationalError |
33 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound | 27 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound |
34 import crypt | 28 import crypt |
29 from decorator import decorator | |
35 import logging | 30 import logging |
31 """ | |
32 Created on April 4, 2010 | |
33 | |
34 @author: marcink | |
35 """ | |
36 | 36 |
37 log = logging.getLogger(__name__) | 37 log = logging.getLogger(__name__) |
38 | 38 |
39 def get_crypt_password(password): | 39 def get_crypt_password(password): |
40 """ | 40 """ |
144 for perm in default_perms: | 144 for perm in default_perms: |
145 p = 'repository.admin' | 145 p = 'repository.admin' |
146 user.permissions['repositories'][perm.Repo2Perm.repository.repo_name] = p | 146 user.permissions['repositories'][perm.Repo2Perm.repository.repo_name] = p |
147 | 147 |
148 else: | 148 else: |
149 user.permissions['global'].add('') | 149 user.permissions['global'].add('repository.create') |
150 for perm in default_perms: | 150 for perm in default_perms: |
151 if perm.Repository.private: | 151 if perm.Repository.private: |
152 #disable defaults for private repos, | 152 #disable defaults for private repos, |
153 p = 'repository.none' | 153 p = 'repository.none' |
154 elif perm.Repository.user_id == user.user_id: | 154 elif perm.Repository.user_id == user.user_id: |
190 | 190 |
191 #=============================================================================== | 191 #=============================================================================== |
192 # CHECK DECORATORS | 192 # CHECK DECORATORS |
193 #=============================================================================== | 193 #=============================================================================== |
194 class LoginRequired(object): | 194 class LoginRequired(object): |
195 """ | 195 """Must be logged in to execute this function else redirect to login page""" |
196 Must be logged in to execute this function else redirect to login page | |
197 """ | |
198 | 196 |
199 def __call__(self, func): | 197 def __call__(self, func): |
200 @wraps(func) | 198 return decorator(self.__wrapper, func) |
201 def _wrapper(*fargs, **fkwargs): | 199 |
202 user = session.get('hg_app_user', AuthUser()) | 200 def __wrapper(self, func, *fargs, **fkwargs): |
203 log.debug('Checking login required for user:%s', user.username) | 201 user = session.get('hg_app_user', AuthUser()) |
204 if user.is_authenticated: | 202 log.debug('Checking login required for user:%s', user.username) |
205 log.debug('user %s is authenticated', user.username) | 203 if user.is_authenticated: |
206 func(*fargs) | 204 log.debug('user %s is authenticated', user.username) |
207 else: | 205 return func(*fargs, **fkwargs) |
208 log.warn('user %s not authenticated', user.username) | 206 else: |
209 log.debug('redirecting to login page') | 207 log.warn('user %s not authenticated', user.username) |
210 return redirect(url('login_home')) | 208 log.debug('redirecting to login page') |
211 | 209 return redirect(url('login_home')) |
212 return _wrapper | |
213 | 210 |
214 class PermsDecorator(object): | 211 class PermsDecorator(object): |
215 """ | 212 """Base class for decorators""" |
216 Base class for decorators | |
217 """ | |
218 | 213 |
219 def __init__(self, *required_perms): | 214 def __init__(self, *required_perms): |
220 available_perms = config['available_permissions'] | 215 available_perms = config['available_permissions'] |
221 for perm in required_perms: | 216 for perm in required_perms: |
222 if perm not in available_perms: | 217 if perm not in available_perms: |
223 raise Exception("'%s' permission is not defined" % perm) | 218 raise Exception("'%s' permission is not defined" % perm) |
224 self.required_perms = set(required_perms) | 219 self.required_perms = set(required_perms) |
225 self.user_perms = None | 220 self.user_perms = None |
226 | 221 |
227 def __call__(self, func): | 222 def __call__(self, func): |
228 @wraps(func) | 223 return decorator(self.__wrapper, func) |
229 def _wrapper(*fargs, **fkwargs): | 224 |
230 self.user_perms = session.get('hg_app_user', AuthUser()).permissions | 225 |
231 log.debug('checking %s permissions %s for %s', | 226 def __wrapper(self, func, *fargs, **fkwargs): |
232 self.__class__.__name__, self.required_perms, func.__name__) | 227 # _wrapper.__name__ = func.__name__ |
233 | 228 # _wrapper.__dict__.update(func.__dict__) |
234 if self.check_permissions(): | 229 # _wrapper.__doc__ = func.__doc__ |
235 log.debug('Permission granted for %s', func.__name__) | 230 |
236 return func(*fargs) | 231 self.user_perms = session.get('hg_app_user', AuthUser()).permissions |
237 | 232 log.debug('checking %s permissions %s for %s', |
238 else: | 233 self.__class__.__name__, self.required_perms, func.__name__) |
239 log.warning('Permission denied for %s', func.__name__) | 234 |
240 #redirect with forbidden ret code | 235 if self.check_permissions(): |
241 return abort(403) | 236 log.debug('Permission granted for %s', func.__name__) |
242 return _wrapper | 237 |
243 | 238 return func(*fargs, **fkwargs) |
244 | 239 |
245 def check_permissions(self): | 240 else: |
246 """ | 241 log.warning('Permission denied for %s', func.__name__) |
247 Dummy function for overriding | 242 #redirect with forbidden ret code |
248 """ | 243 return abort(403) |
244 | |
245 | |
246 | |
247 def check_permissions(self): | |
248 """Dummy function for overriding""" | |
249 raise Exception('You have to write this function in child class') | 249 raise Exception('You have to write this function in child class') |
250 | 250 |
251 class HasPermissionAllDecorator(PermsDecorator): | 251 class HasPermissionAllDecorator(PermsDecorator): |
252 """ | 252 """Checks for access permission for all given predicates. All of them |
253 Checks for access permission for all given predicates. All of them have to | 253 have to be meet in order to fulfill the request |
254 be meet in order to fulfill the request | |
255 """ | 254 """ |
256 | 255 |
257 def check_permissions(self): | 256 def check_permissions(self): |
258 if self.required_perms.issubset(self.user_perms.get('global')): | 257 if self.required_perms.issubset(self.user_perms.get('global')): |
259 return True | 258 return True |
260 return False | 259 return False |
261 | 260 |
262 | 261 |
263 class HasPermissionAnyDecorator(PermsDecorator): | 262 class HasPermissionAnyDecorator(PermsDecorator): |
264 """ | 263 """Checks for access permission for any of given predicates. In order to |
265 Checks for access permission for any of given predicates. In order to | |
266 fulfill the request any of predicates must be meet | 264 fulfill the request any of predicates must be meet |
267 """ | 265 """ |
268 | 266 |
269 def check_permissions(self): | 267 def check_permissions(self): |
270 if self.required_perms.intersection(self.user_perms.get('global')): | 268 if self.required_perms.intersection(self.user_perms.get('global')): |
271 return True | 269 return True |
272 return False | 270 return False |
273 | 271 |
274 class HasRepoPermissionAllDecorator(PermsDecorator): | 272 class HasRepoPermissionAllDecorator(PermsDecorator): |
275 """ | 273 """Checks for access permission for all given predicates for specific |
276 Checks for access permission for all given predicates for specific | |
277 repository. All of them have to be meet in order to fulfill the request | 274 repository. All of them have to be meet in order to fulfill the request |
278 """ | 275 """ |
279 | 276 |
280 def check_permissions(self): | 277 def check_permissions(self): |
281 repo_name = get_repo_slug(request) | 278 repo_name = get_repo_slug(request) |
287 return True | 284 return True |
288 return False | 285 return False |
289 | 286 |
290 | 287 |
291 class HasRepoPermissionAnyDecorator(PermsDecorator): | 288 class HasRepoPermissionAnyDecorator(PermsDecorator): |
292 """ | 289 """Checks for access permission for any of given predicates for specific |
293 Checks for access permission for any of given predicates for specific | |
294 repository. In order to fulfill the request any of predicates must be meet | 290 repository. In order to fulfill the request any of predicates must be meet |
295 """ | 291 """ |
296 | 292 |
297 def check_permissions(self): | 293 def check_permissions(self): |
298 repo_name = get_repo_slug(request) | 294 repo_name = get_repo_slug(request) |
307 #=============================================================================== | 303 #=============================================================================== |
308 # CHECK FUNCTIONS | 304 # CHECK FUNCTIONS |
309 #=============================================================================== | 305 #=============================================================================== |
310 | 306 |
311 class PermsFunction(object): | 307 class PermsFunction(object): |
312 """ | 308 """Base function for other check functions""" |
313 Base function for other check functions | |
314 """ | |
315 | 309 |
316 def __init__(self, *perms): | 310 def __init__(self, *perms): |
317 available_perms = config['available_permissions'] | 311 available_perms = config['available_permissions'] |
318 | 312 |
319 for perm in perms: | 313 for perm in perms: |
341 log.warning('Permission denied for %s @%s', self.granted_for, | 335 log.warning('Permission denied for %s @%s', self.granted_for, |
342 check_Location) | 336 check_Location) |
343 return False | 337 return False |
344 | 338 |
345 def check_permissions(self): | 339 def check_permissions(self): |
346 """ | 340 """Dummy function for overriding""" |
347 Dummy function for overriding | |
348 """ | |
349 raise Exception('You have to write this function in child class') | 341 raise Exception('You have to write this function in child class') |
350 | 342 |
351 class HasPermissionAll(PermsFunction): | 343 class HasPermissionAll(PermsFunction): |
352 def check_permissions(self): | 344 def check_permissions(self): |
353 if self.required_perms.issubset(self.user_perms.get('global')): | 345 if self.required_perms.issubset(self.user_perms.get('global')): |
379 if self.required_perms.issubset(self.user_perms): | 371 if self.required_perms.issubset(self.user_perms): |
380 return True | 372 return True |
381 return False | 373 return False |
382 | 374 |
383 class HasRepoPermissionAny(PermsFunction): | 375 class HasRepoPermissionAny(PermsFunction): |
384 | |
385 | 376 |
386 def __call__(self, repo_name=None, check_Location=''): | 377 def __call__(self, repo_name=None, check_Location=''): |
387 self.repo_name = repo_name | 378 self.repo_name = repo_name |
388 return super(HasRepoPermissionAny, self).__call__(check_Location) | 379 return super(HasRepoPermissionAny, self).__call__(check_Location) |
389 | 380 |