##// END OF EJS Templates
Disabled special 404 page. That function was really not needed
Disabled special 404 page. That function was really not needed

File last commit:

r350:664a5b8c default
r354:7a086a83 default
Show More
auth.py
413 lines | 14.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>
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316
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.
"""
Created on April 4, 2010
@author: marcink
"""
implemented cache for repeated queries in simplehg mercurial requests
r343 from beaker.cache import cache_region
Added LoginRequired decorator, empty User data container, hash functions
r190 from functools import wraps
implemented cache for repeated queries in simplehg mercurial requests
r343 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
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 from pylons_app.model.db import User, Repo2Perm, 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
Added LoginRequired decorator, empty User data container, hash functions
r190 import crypt
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):
Added LoginRequired decorator, empty User data container, hash functions
r190 """
Cryptographic function used for password hashing
@param password: password to hash
"""
Marcin Kuzminski
Changed auth lib for sqlalchemy
r64 return crypt.crypt(password, '6a')
Marcin Kuzminski
Static files for production fixed...
r46
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'
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
def fill_perms(user):
sa = meta.Session
user.permissions['repositories'] = {}
#first fetch default permissions
default_perms = sa.query(Repo2Perm, Repository, Permission)\
.join((Repository, Repo2Perm.repository == Repository.repo_name))\
.join((Permission, Repo2Perm.permission_id == Permission.permission_id))\
.filter(Repo2Perm.user_id == sa.query(User).filter(User.username ==
'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:
user.permissions['global'] = set(['hg.admin'])
#admin have all rights full
for perm in default_perms:
p = 'repository.admin'
user.permissions['repositories'][perm.Repo2Perm.repository] = p
else:
user.permissions['global'] = set()
for perm in default_perms:
if perm.Repository.private:
#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
user.permissions['repositories'][perm.Repo2Perm.repository] = p
user_perms = sa.query(Repo2Perm, Permission, Repository)\
.join((Repository, Repo2Perm.repository == Repository.repo_name))\
.join((Permission, Repo2Perm.permission_id == Permission.permission_id))\
.filter(Repo2Perm.user_id == user.user_id).all()
#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
Added application settings, are now customizable from database...
r350 user.permissions['repositories'][perm.Repo2Perm.repository] = p
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())
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316
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 if user.is_authenticated:
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 user = fill_perms(user)
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):
"""
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):
@wraps(func)
def _wrapper(*fargs, **fkwargs):
moved checking for user in session to wrapper function of LoginRequired decorator since it was working quite strange.
r199 user = session.get('hg_app_user', AuthUser())
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 log.debug('Checking login required for user:%s', user.username)
Added LoginRequired decorator, empty User data container, hash functions
r190 if user.is_authenticated:
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 log.debug('user %s is authenticated', user.username)
func(*fargs)
Added LoginRequired decorator, empty User data container, hash functions
r190 else:
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 log.warn('user %s not authenticated', user.username)
log.debug('redirecting to login page')
Added LoginRequired decorator, empty User data container, hash functions
r190 return redirect(url('login_home'))
implemented autentication
r52
Added LoginRequired decorator, empty User data container, hash functions
r190 return _wrapper
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239
class PermsDecorator(object):
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 """
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):
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239 @wraps(func)
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 def _wrapper(*fargs, **fkwargs):
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__)
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239
if self.check_permissions():
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 log.debug('Permission granted for %s', func.__name__)
return func(*fargs)
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239
else:
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 log.warning('Permission denied for %s', func.__name__)
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239 #redirect with forbidden ret code
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 return abort(403)
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239 return _wrapper
def check_permissions(self):
"""
Full rewrite of auth module, new functions/decorators. FIxed auth user
r316 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):
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239 """
Checks for access permission for all given predicates. All of them have to
be meet in order to fulfill the request
"""
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):
Adde draft for permissions systems, made all needed decorators, and checks. For future usage in the system.
r239 """
Checks for access permission for any of given predicates. In order to
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):
"""
Checks for access permission for all given predicates for specific
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):
"""
Checks for access permission for any of given predicates for specific
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):
"""
Base function for other check functions
"""
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):
"""
Dummy function for overriding
"""
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