##// END OF EJS Templates
added jump to revision from file history.
added jump to revision from file history.

File last commit:

r412:b6a25169 default
r413:0ebec9b8 default
Show More
auth.py
432 lines | 15.0 KiB | text/x-python | PythonLexer
licensing updates, code cleanups
r252 #!/usr/bin/env python
# encoding: utf-8
# authentication and permission libraries
# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
r377 #
licensing updates, code cleanups
r252 # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 2
# of the License or (at your opinion) any later version of the license.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
cleared global application settings....
r381 """
Created on April 4, 2010
@author: marcink
"""
implemented cache for repeated queries in simplehg mercurial requests
r343 from beaker.cache import cache_region
from pylons import config, session, url, request
implemented autentication
r52 from pylons.controllers.util import abort, redirect
implemented cache for repeated queries in simplehg mercurial requests
r343 from pylons_app.lib.utils import get_repo_slug
Marcin Kuzminski
Changed auth lib for sqlalchemy
r64 from pylons_app.model import meta
rename repo2perm into repo_to_perm...
r399 from pylons_app.model.db import User, RepoToPerm, Repository, Permission
Added LoginRequired decorator, empty User data container, hash functions
r190 from sqlalchemy.exc import OperationalError
Marcin Kuzminski
Changed auth lib for sqlalchemy
r64 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
fixes #25 removed crypt based password hashing and changed it into sha1 based.
r412 import hashlib
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
r377 from decorator import decorator
Added LoginRequired decorator, empty User data container, hash functions
r190 import logging
implemented cache for repeated queries in simplehg mercurial requests
r343
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 log = logging.getLogger(__name__)
Marcin Kuzminski
Added app basic auth....
r41
Marcin Kuzminski
Changed auth lib for sqlalchemy
r64 def get_crypt_password(password):
fixes #25 removed crypt based password hashing and changed it into sha1 based.
r412 """Cryptographic function used for password hashing based on sha1
Added LoginRequired decorator, empty User data container, hash functions
r190 @param password: password to hash
"""
fixes #25 removed crypt based password hashing and changed it into sha1 based.
r412 hashed = hashlib.sha1(password).hexdigest()
return hashed[3:] + hashed[:3]
implemented cache for repeated queries in simplehg mercurial requests
r343
@cache_region('super_short_term', 'cached_user')
def get_user_cached(username):
sa = meta.Session
Added application settings, are now customizable from database...
r350 try:
user = sa.query(User).filter(User.username == username).one()
finally:
meta.Session.remove()
implemented cache for repeated queries in simplehg mercurial requests
r343 return user
Marcin Kuzminski
Added app basic auth....
r41 def authfunc(environ, username, password):
Marcin Kuzminski
Changed auth lib for sqlalchemy
r64 password_crypt = get_crypt_password(password)
try except error on non existing user table
r42 try:
implemented cache for repeated queries in simplehg mercurial requests
r343 user = get_user_cached(username)
Marcin Kuzminski
Changed auth lib for sqlalchemy
r64 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
try except error on non existing user table
r42 log.error(e)
Marcin Kuzminski
Changed auth lib for sqlalchemy
r64 user = None
if user:
if user.active:
if user.username == username and user.password == password_crypt:
Marcin Kuzminski
Added app basic auth....
r41 log.info('user %s authenticated correctly', username)
return True
else:
log.error('user %s is disabled', username)
return False
Added LoginRequired decorator, empty User data container, hash functions
r190 class AuthUser(object):
"""
A simple object that handles a mercurial username for authentication
"""
def __init__(self):
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 self.username = 'None'
added session remove in forms, and added name and lastname to auth user
r355 self.name = ''
self.lastname = ''
fixed user email for gravatars
r404 self.email = ''
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 self.user_id = None
self.is_authenticated = False
self.is_admin = False
self.permissions = {}
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239
def set_available_permissions(config):
"""
This function will propagate pylons globals with all available defined
permission given in db. We don't wannt to check each time from db for new
permissions since adding a new permission also requires application restart
ie. to decorate new views with the newly created permission
@param config:
"""
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 log.info('getting information about all available permissions')
Added application settings, are now customizable from database...
r350 try:
sa = meta.Session
all_perms = sa.query(Permission).all()
finally:
meta.Session.remove()
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 config['available_permissions'] = [x.permission_name for x in all_perms]
def set_base_path(config):
config['base_path'] = config['pylons.app_globals'].base_path
routes python 2.5 compatible...
r371
def fill_data(user):
"""
auth functions little fix
r382 Fills user data with those from database and log out user if not present
in database
routes python 2.5 compatible...
r371 @param user:
"""
sa = meta.Session
dbuser = sa.query(User).get(user.user_id)
auth functions little fix
r382 if dbuser:
user.username = dbuser.username
user.is_admin = dbuser.admin
user.name = dbuser.name
user.lastname = dbuser.lastname
fixed user email for gravatars
r404 user.email = dbuser.email
auth functions little fix
r382 else:
user.is_authenticated = False
routes python 2.5 compatible...
r371 meta.Session.remove()
return user
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 def fill_perms(user):
fixes issue #16 reimplementation of database repository, for using generic pk instead of repo naming as pk. Which caused to many problems....
r367 """
Fills user permission attribute with permissions taken from database
@param user:
"""
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 sa = meta.Session
user.permissions['repositories'] = {}
routes python 2.5 compatible...
r371 user.permissions['global'] = set()
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316
#first fetch default permissions
rename repo2perm into repo_to_perm...
r399 default_perms = sa.query(RepoToPerm, Repository, Permission)\
.join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
.join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
.filter(RepoToPerm.user_id == sa.query(User).filter(User.username ==
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 'default').one().user_id).all()
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 if user.is_admin:
routes python 2.5 compatible...
r371 user.permissions['global'].add('hg.admin')
Added separate create repository views for non administrative users....
r380 #admin have all rights set to admin
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 for perm in default_perms:
p = 'repository.admin'
rename repo2perm into repo_to_perm...
r399 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316
else:
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
r377 user.permissions['global'].add('repository.create')
fixes #25 removed crypt based password hashing and changed it into sha1 based.
r412 user.permissions['global'].add('hg.register')
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 for perm in default_perms:
Added separate create repository views for non administrative users....
r380 if perm.Repository.private and not perm.Repository.user_id == user.user_id:
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 #disable defaults for private repos,
p = 'repository.none'
elif perm.Repository.user_id == user.user_id:
#set admin if owner
p = 'repository.admin'
else:
p = perm.Permission.permission_name
rename repo2perm into repo_to_perm...
r399 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316
rename repo2perm into repo_to_perm...
r399 user_perms = sa.query(RepoToPerm, Permission, Repository)\
.join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
.join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
.filter(RepoToPerm.user_id == user.user_id).all()
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 #overwrite userpermissions with defaults
for perm in user_perms:
#set write if owner
if perm.Repository.user_id == user.user_id:
p = 'repository.write'
else:
p = perm.Permission.permission_name
rename repo2perm into repo_to_perm...
r399 user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
Added application settings, are now customizable from database...
r350 meta.Session.remove()
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 return user
repos crud controllers - change id into repo_name for compatability, added ajax repo perm user function variuos html fixes, permissions forms and managment fixes....
r299 def get_user(session):
"""
Gets user from session, and wraps permissions into user
@param session:
"""
user = session.get('hg_app_user', AuthUser())
if user.is_authenticated:
routes python 2.5 compatible...
r371 user = fill_data(user)
fixes #25 removed crypt based password hashing and changed it into sha1 based.
r412 user = fill_perms(user)
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 session['hg_app_user'] = user
session.save()
repos crud controllers - change id into repo_name for compatability, added ajax repo perm user function variuos html fixes, permissions forms and managment fixes....
r299 return user
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239
Added LoginRequired decorator, empty User data container, hash functions
r190 #===============================================================================
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 # CHECK DECORATORS
Added LoginRequired decorator, empty User data container, hash functions
r190 #===============================================================================
class LoginRequired(object):
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
r377 """Must be logged in to execute this function else redirect to login page"""
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316
Added LoginRequired decorator, empty User data container, hash functions
r190 def __call__(self, func):
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
r377 return decorator(self.__wrapper, func)
def __wrapper(self, func, *fargs, **fkwargs):
user = session.get('hg_app_user', AuthUser())
log.debug('Checking login required for user:%s', user.username)
if user.is_authenticated:
log.debug('user %s is authenticated', user.username)
return func(*fargs, **fkwargs)
else:
log.warn('user %s not authenticated', user.username)
log.debug('redirecting to login page')
return redirect(url('login_home'))
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239
class PermsDecorator(object):
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
r377 """Base class for decorators"""
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 def __init__(self, *required_perms):
available_perms = config['available_permissions']
for perm in required_perms:
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239 if perm not in available_perms:
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 raise Exception("'%s' permission is not defined" % perm)
self.required_perms = set(required_perms)
self.user_perms = None
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 def __call__(self, func):
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
r377 return decorator(self.__wrapper, func)
def __wrapper(self, func, *fargs, **fkwargs):
# _wrapper.__name__ = func.__name__
# _wrapper.__dict__.update(func.__dict__)
# _wrapper.__doc__ = func.__doc__
self.user_perms = session.get('hg_app_user', AuthUser()).permissions
log.debug('checking %s permissions %s for %s',
self.__class__.__name__, self.required_perms, func.__name__)
if self.check_permissions():
log.debug('Permission granted for %s', func.__name__)
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
r377 return func(*fargs, **fkwargs)
else:
log.warning('Permission denied for %s', func.__name__)
#redirect with forbidden ret code
return abort(403)
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239
def check_permissions(self):
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
r377 """Dummy function for overriding"""
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239 raise Exception('You have to write this function in child class')
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 class HasPermissionAllDecorator(PermsDecorator):
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
r377 """Checks for access permission for all given predicates. All of them
have to be meet in order to fulfill the request
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239 """
def check_permissions(self):
some extra checks for auth lib
r339 if self.required_perms.issubset(self.user_perms.get('global')):
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239 return True
return False
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 class HasPermissionAnyDecorator(PermsDecorator):
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
r377 """Checks for access permission for any of given predicates. In order to
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239 fulfill the request any of predicates must be meet
"""
def check_permissions(self):
some extra checks for auth lib
r339 if self.required_perms.intersection(self.user_perms.get('global')):
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 return True
return False
class HasRepoPermissionAllDecorator(PermsDecorator):
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
r377 """Checks for access permission for all given predicates for specific
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 repository. All of them have to be meet in order to fulfill the request
"""
def check_permissions(self):
repo_name = get_repo_slug(request)
some extra checks for auth lib
r339 try:
user_perms = set([self.user_perms['repositories'][repo_name]])
except KeyError:
return False
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 if self.required_perms.issubset(user_perms):
return True
return False
class HasRepoPermissionAnyDecorator(PermsDecorator):
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
r377 """Checks for access permission for any of given predicates for specific
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 repository. In order to fulfill the request any of predicates must be meet
"""
def check_permissions(self):
repo_name = get_repo_slug(request)
some extra checks for auth lib
r339 try:
user_perms = set([self.user_perms['repositories'][repo_name]])
except KeyError:
return False
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 if self.required_perms.intersection(user_perms):
return True
return False
#===============================================================================
# CHECK FUNCTIONS
#===============================================================================
class PermsFunction(object):
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
r377 """Base function for other check functions"""
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316
def __init__(self, *perms):
available_perms = config['available_permissions']
for perm in perms:
if perm not in available_perms:
raise Exception("'%s' permission in not defined" % perm)
self.required_perms = set(perms)
self.user_perms = None
self.granted_for = ''
self.repo_name = None
def __call__(self, check_Location=''):
fixed auth bug
r333 user = session.get('hg_app_user', False)
if not user:
return False
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 self.user_perms = user.permissions
self.granted_for = user.username
log.debug('checking %s %s', self.__class__.__name__, self.required_perms)
if self.check_permissions():
log.debug('Permission granted for %s @%s', self.granted_for,
check_Location)
return True
else:
log.warning('Permission denied for %s @%s', self.granted_for,
check_Location)
return False
def check_permissions(self):
Fixed decorators bug when using them with keyworded arguments,new implementation takes new approach that is more flexible
r377 """Dummy function for overriding"""
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 raise Exception('You have to write this function in child class')
class HasPermissionAll(PermsFunction):
def check_permissions(self):
some extra checks for auth lib
r339 if self.required_perms.issubset(self.user_perms.get('global')):
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 return True
return False
class HasPermissionAny(PermsFunction):
def check_permissions(self):
some extra checks for auth lib
r339 if self.required_perms.intersection(self.user_perms.get('global')):
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 return True
return False
class HasRepoPermissionAll(PermsFunction):
def __call__(self, repo_name=None, check_Location=''):
self.repo_name = repo_name
return super(HasRepoPermissionAll, self).__call__(check_Location)
def check_permissions(self):
if not self.repo_name:
self.repo_name = get_repo_slug(request)
some extra checks for auth lib
r339 try:
self.user_perms = set([self.user_perms['repositories']\
[self.repo_name]])
except KeyError:
return False
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 self.granted_for = self.repo_name
if self.required_perms.issubset(self.user_perms):
return True
return False
class HasRepoPermissionAny(PermsFunction):
def __call__(self, repo_name=None, check_Location=''):
self.repo_name = repo_name
return super(HasRepoPermissionAny, self).__call__(check_Location)
def check_permissions(self):
if not self.repo_name:
self.repo_name = get_repo_slug(request)
some extra checks for auth lib
r339 try:
self.user_perms = set([self.user_perms['repositories']\
[self.repo_name]])
except KeyError:
return False
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 self.granted_for = self.repo_name
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239 if self.required_perms.intersection(self.user_perms):
return True
return False
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 #===============================================================================
# SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
#===============================================================================
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 class HasPermissionAnyMiddleware(object):
def __init__(self, *perms):
self.required_perms = set(perms)
def __call__(self, user, repo_name):
usr = AuthUser()
usr.user_id = user.user_id
usr.username = user.username
usr.is_admin = user.admin
try:
self.user_perms = set([fill_perms(usr)\
.permissions['repositories'][repo_name]])
except:
self.user_perms = set()
self.granted_for = ''
self.username = user.username
self.repo_name = repo_name
return self.check_permissions()
def check_permissions(self):
log.debug('checking mercurial protocol '
'permissions for user:%s repository:%s',
self.username, self.repo_name)
if self.required_perms.intersection(self.user_perms):
log.debug('permission granted')
return True
log.debug('permission denied')
return False