Changeset - 16253f330094
[Not reviewed]
default
0 1 0
Marcin Kuzminski - 15 years ago 2010-08-25 18:15:50
marcin@python-works.com
fixes #30. Rewrite default permissions query + some other small fixes
1 file changed with 11 insertions and 9 deletions:
0 comments (0 inline, 0 general)
pylons_app/lib/auth.py
Show inline comments
 
@@ -48,236 +48,238 @@ def check_password(password, hashed):
 

	
 
@cache_region('super_short_term', 'cached_user')
 
def get_user_cached(username):
 
    sa = meta.Session
 
    try:
 
        user = sa.query(User).filter(User.username == username).one()
 
    finally:
 
        meta.Session.remove()
 
    return user
 

	
 
def authfunc(environ, username, password):
 
    try:
 
        user = get_user_cached(username)
 
    except (NoResultFound, MultipleResultsFound, OperationalError) as e:
 
        log.error(e)
 
        user = None
 
        
 
    if user:
 
        if user.active:
 
            if user.username == username and check_password(password, user.password):
 
                log.info('user %s authenticated correctly', username)
 
                return True
 
        else:
 
            log.error('user %s is disabled', username)
 
            
 
    return False
 

	
 
class  AuthUser(object):
 
    """
 
    A simple object that handles a mercurial username for authentication
 
    """
 
    def __init__(self):
 
        self.username = 'None'
 
        self.name = ''
 
        self.lastname = ''
 
        self.email = ''
 
        self.user_id = None
 
        self.is_authenticated = False
 
        self.is_admin = False
 
        self.permissions = {}
 

	
 

	
 
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:
 
    """
 
    log.info('getting information about all available permissions')
 
    try:
 
        sa = meta.Session
 
        all_perms = sa.query(Permission).all()
 
    finally:
 
        meta.Session.remove()
 
    
 
    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_data(user):
 
    """
 
    Fills user data with those from database and log out user if not present
 
    in database
 
    @param user:
 
    """
 
    sa = meta.Session
 
    dbuser = sa.query(User).get(user.user_id)
 
    if dbuser:
 
        user.username = dbuser.username
 
        user.is_admin = dbuser.admin
 
        user.name = dbuser.name
 
        user.lastname = dbuser.lastname
 
        user.email = dbuser.email
 
    else:
 
        user.is_authenticated = False
 
    meta.Session.remove()
 
    from pprint import pprint
 
    pprint(user.permissions)
 
    return user
 
            
 
def fill_perms(user):
 
    """
 
    Fills user permission attribute with permissions taken from database
 
    @param user:
 
    """
 
    
 
    sa = meta.Session
 
    user.permissions['repositories'] = {}
 
    user.permissions['global'] = set()
 
    
 
    #===========================================================================
 
    # fetch default permissions
 
    #===========================================================================
 
    default_perms = sa.query(RepoToPerm, UserToPerm, Repository, Permission)\
 
        .outerjoin((UserToPerm, RepoToPerm.user_id == UserToPerm.user_id))\
 
    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 == 
 
                                            'default').one().user_id).all()
 
        .filter(RepoToPerm.user == sa.query(User).filter(User.username == 
 
                                            'default').scalar()).all()
 
                                            
 
    if user.is_admin:
 
        #=======================================================================
 
        # #admin have all rights set to admin        
 
        # #admin have all default rights set to admin        
 
        #=======================================================================
 
        user.permissions['global'].add('hg.admin')
 
        
 
        for perm in default_perms:
 
            p = 'repository.admin'
 
            user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
 
    
 
    else:
 
        #=======================================================================
 
        # set default permissions
 
        #=======================================================================
 
        
 
        #default global
 
        for perm in default_perms:
 
            user.permissions['global'].add(perm.UserToPerm.permission.permission_name)
 
        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)
 
                    
 
        #default repositories
 
        for perm in default_perms:
 
            if perm.Repository.private and not perm.Repository.user_id == user.user_id:
 
                #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.RepoToPerm.repository.repo_name] = p
 
                                                
 
        #=======================================================================
 
        # #overwrite default with user permissions if any
 
        #=======================================================================
 
        user_perms = sa.query(RepoToPerm, UserToPerm, Permission, Repository)\
 
            .outerjoin((UserToPerm, RepoToPerm.user_id == UserToPerm.user_id))\
 
        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()
 
            
 
        for perm in user_perms:
 
            if perm.Repository.user_id == user.user_id:#set admin if owner
 
                p = 'repository.admin'
 
            else:
 
                p = perm.Permission.permission_name
 
            user.permissions['repositories'][perm.RepoToPerm.repository.repo_name] = p
 
    meta.Session.remove()         
 
    return user
 
    
 
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:
 
        user = fill_data(user)
 
    user = fill_perms(user)
 
    session['hg_app_user'] = user
 
    session.save()
 
    return user
 
        
 
#===============================================================================
 
# CHECK DECORATORS
 
#===============================================================================
 
class LoginRequired(object):
 
    """Must be logged in to execute this function else redirect to login page"""
 
   
 
    def __call__(self, func):
 
        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'))
 

	
 
class PermsDecorator(object):
 
    """Base class for decorators"""
 
    
 
    def __init__(self, *required_perms):
 
        available_perms = config['available_permissions']
 
        for perm in required_perms:
 
            if perm not in available_perms:
 
                raise Exception("'%s' permission is not defined" % perm)
 
        self.required_perms = set(required_perms)
 
        self.user_perms = None
 
        
 
    def __call__(self, func):
 
        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__)
 
            
 
            return func(*fargs, **fkwargs)
 
        
 
        else:
 
            log.warning('Permission denied for %s', func.__name__)
 
            #redirect with forbidden ret code
 
            return abort(403)
 

	
 
        
 
        
 
    def check_permissions(self):
 
        """Dummy function for overriding"""
 
        raise Exception('You have to write this function in child class')
 

	
 
class HasPermissionAllDecorator(PermsDecorator):
 
    """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):
 
        if self.required_perms.issubset(self.user_perms.get('global')):
 
            return True
 
        return False
 
            
0 comments (0 inline, 0 general)