##// END OF EJS Templates
Merge with 6aa7db1c083a1384ebff5c2bb3c943a035bb310d - celery branch
Merge with 6aa7db1c083a1384ebff5c2bb3c943a035bb310d - celery branch

File last commit:

r474:a3d9d24a celery
r499:ca41d544 merge rhodecode-0.0.0.8.3 default
Show More
auth.py
481 lines | 17.4 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
permission refactoring,...
r417 from pylons_app.model.db import User, RepoToPerm, Repository, Permission, \
UserToPerm
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
Changed password crypting scheme to bcrypt, added dependency for setup
r415 import bcrypt
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 password reset(forms/models/ tasks) and mailing tasks....
r474 import random
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
Implemented password reset(forms/models/ tasks) and mailing tasks....
r474 class PasswordGenerator(object):
"""This is a simple class for generating password from
different sets of characters
usage:
passwd_gen = PasswordGenerator()
#print 8-letter password containing only big and small letters of alphabet
print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
"""
ALPHABETS_NUM = r'''1234567890'''#[0]
ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''#[1]
ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''#[2]
ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' #[3]
ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_SPECIAL#[4]
ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM#[5]
ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
def __init__(self, passwd=''):
self.passwd = passwd
def gen_password(self, len, type):
self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
return self.passwd
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
Changed password crypting scheme to bcrypt, added dependency for setup
r415 """
return bcrypt.hashpw(password, bcrypt.gensalt(10))
def check_password(password, hashed):
return bcrypt.hashpw(password, hashed) == hashed
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):
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:
Changed password crypting scheme to bcrypt, added dependency for setup
r415 if user.username == username and check_password(password, user.password):
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
permission refactoring,...
r417 #===========================================================================
# fetch default permissions
#===========================================================================
fixes #30. Rewrite default permissions query + some other small fixes
r423 default_perms = sa.query(RepoToPerm, Repository, Permission)\
rename repo2perm into repo_to_perm...
r399 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
.join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
fixes #30. Rewrite default permissions query + some other small fixes
r423 .filter(RepoToPerm.user == sa.query(User).filter(User.username ==
'default').scalar()).all()
permission refactoring,...
r417
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 if user.is_admin:
permission refactoring,...
r417 #=======================================================================
fixes #30. Rewrite default permissions query + some other small fixes
r423 # #admin have all default rights set to admin
permission refactoring,...
r417 #=======================================================================
routes python 2.5 compatible...
r371 user.permissions['global'].add('hg.admin')
permission refactoring,...
r417
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:
permission refactoring,...
r417 #=======================================================================
# set default permissions
#=======================================================================
fixes #25 removed crypt based password hashing and changed it into sha1 based.
r412
permission refactoring,...
r417 #default global
fixes #30. Rewrite default permissions query + some other small fixes
r423 default_global_perms = sa.query(UserToPerm)\
.filter(UserToPerm.user == sa.query(User).filter(User.username ==
'default').one())
for perm in default_global_perms:
user.permissions['global'].add(perm.permission.permission_name)
added logic for changin defualt permissions, and option to overwrite all defualt permissions on each repository...
r418
permission refactoring,...
r417 #default repositories
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
permission refactoring,...
r417 #=======================================================================
# #overwrite default with user permissions if any
#=======================================================================
fixes #30. Rewrite default permissions query + some other small fixes
r423 user_perms = sa.query(RepoToPerm, Permission, Repository)\
rename repo2perm into repo_to_perm...
r399 .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
.join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
.filter(RepoToPerm.user_id == user.user_id).all()
permission refactoring,...
r417
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 for perm in user_perms:
permission refactoring,...
r417 if perm.Repository.user_id == user.user_id:#set admin if owner
p = 'repository.admin'
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 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)
Added redirection to page that request came from, after login in
r437
p = request.environ.get('PATH_INFO')
if request.environ.get('QUERY_STRING'):
Implemented password reset(forms/models/ tasks) and mailing tasks....
r474 p += '?' + request.environ.get('QUERY_STRING')
log.debug('redirecting to login page with %s', p)
return redirect(url('login_home', came_from=p))
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