Changeset - 6eb5bb24a948
[Not reviewed]
beta
0 7 0
Marcin Kuzminski - 15 years ago 2011-03-09 16:34:29
marcin@python-works.com
Major rewrite of auth objects. Moved parts of filling user data into user model.
Rewrote AuthUser adding access by api key.
7 files changed with 253 insertions and 206 deletions:
0 comments (0 inline, 0 general)
rhodecode/controllers/admin/users.py
Show inline comments
 
@@ -33,14 +33,13 @@ from formencode import htmlfill
 
from pylons import request, session, tmpl_context as c, url, config
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
 
    fill_perms
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
 
from rhodecode.lib.base import BaseController, render
 

	
 
from rhodecode.model.db import User
 
from rhodecode.model.forms import UserForm
 
from rhodecode.model.user import UserModel
 

	
 
@@ -154,20 +153,21 @@ class UsersController(BaseController):
 
        # url('user', id=ID)
 

	
 

	
 
    def edit(self, id, format='html'):
 
        """GET /users/id/edit: Form to edit an existing item"""
 
        # url('edit_user', id=ID)
 
        c.user = self.sa.query(User).get(id)
 
        user_model = UserModel()
 
        c.user = user_model.get(id)
 
        if not c.user:
 
            return redirect(url('users'))
 
        if c.user.username == 'default':
 
            h.flash(_("You can't edit this user"), category='warning')
 
            return redirect(url('users'))
 
        c.user.permissions = {}
 
        c.granted_permissions = fill_perms(c.user).permissions['global']
 
        c.granted_permissions = user_model.fill_perms(c.user).permissions['global']
 

	
 
        defaults = c.user.get_dict()
 

	
 
        return htmlfill.render(
 
            render('admin/users/user_edit.html'),
 
            defaults=defaults,
rhodecode/controllers/admin/users_groups.py
Show inline comments
 
@@ -33,14 +33,13 @@ from formencode import htmlfill
 
from pylons import request, session, tmpl_context as c, url, config
 
from pylons.controllers.util import abort, redirect
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException
 
from rhodecode.lib import helpers as h
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
 
    fill_perms
 
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
 
from rhodecode.lib.base import BaseController, render
 

	
 
from rhodecode.model.db import User, UsersGroup
 
from rhodecode.model.forms import UserForm, UsersGroupForm
 
from rhodecode.model.user import UserModel
 
from rhodecode.model.users_group import UsersGroupModel
rhodecode/controllers/journal.py
Show inline comments
 
@@ -46,24 +46,25 @@ log = logging.getLogger(__name__)
 
class JournalController(BaseController):
 

	
 

	
 
    @LoginRequired()
 
    def __before__(self):
 
        super(JournalController, self).__before__()
 
        c.rhodecode_user = self.rhodecode_user
 
        self.title = _('%s public journal %s feed') % (c.rhodecode_name, '%s')
 
        self.language = 'en-us'
 
        self.ttl = "5"
 
        self.feed_nr = 20
 

	
 
    @NotAnonymous()
 
    def index(self):
 
        # Return a rendered template
 
        p = int(request.params.get('page', 1))
 

	
 
        c.following = self.sa.query(UserFollowing)\
 
            .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
 
            .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
 
            .options(joinedload(UserFollowing.follows_repository))\
 
            .all()
 

	
 
        journal = self._get_journal_data(c.following)
 

	
 
        c.journal_pager = Page(journal, page=p, items_per_page=20)
 
@@ -123,22 +124,22 @@ class JournalController(BaseController):
 
        if cur_token == token:
 

	
 
            user_id = request.POST.get('follows_user_id')
 
            if user_id:
 
                try:
 
                    self.scm_model.toggle_following_user(user_id,
 
                                                    c.rhodecode_user.user_id)
 
                                                    self.rhodecode_user.user_id)
 
                    return 'ok'
 
                except:
 
                    raise HTTPInternalServerError()
 

	
 
            repo_id = request.POST.get('follows_repo_id')
 
            if repo_id:
 
                try:
 
                    self.scm_model.toggle_following_repo(repo_id,
 
                                                    c.rhodecode_user.user_id)
 
                                                    self.rhodecode_user.user_id)
 
                    return 'ok'
 
                except:
 
                    raise HTTPInternalServerError()
 

	
 

	
 
        log.debug('token mismatch %s vs %s', cur_token, token)
 
@@ -149,13 +150,13 @@ class JournalController(BaseController):
 

	
 
    def public_journal(self):
 
        # Return a rendered template
 
        p = int(request.params.get('page', 1))
 

	
 
        c.following = self.sa.query(UserFollowing)\
 
            .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
 
            .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
 
            .options(joinedload(UserFollowing.follows_repository))\
 
            .all()
 

	
 
        journal = self._get_journal_data(c.following)
 

	
 
        c.journal_pager = Page(journal, page=p, items_per_page=20)
 
@@ -171,13 +172,13 @@ class JournalController(BaseController):
 

	
 
    def public_journal_atom(self):
 
        """
 
        Produce an atom-1.0 feed via feedgenerator module
 
        """
 
        c.following = self.sa.query(UserFollowing)\
 
            .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
 
            .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
 
            .options(joinedload(UserFollowing.follows_repository))\
 
            .all()
 

	
 
        journal = self._get_journal_data(c.following)
 

	
 
        feed = Atom1Feed(title=self.title % 'atom',
 
@@ -204,13 +205,13 @@ class JournalController(BaseController):
 

	
 
    def public_journal_rss(self):
 
        """
 
        Produce an rss2 feed via feedgenerator module
 
        """
 
        c.following = self.sa.query(UserFollowing)\
 
            .filter(UserFollowing.user_id == c.rhodecode_user.user_id)\
 
            .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
 
            .options(joinedload(UserFollowing.follows_repository))\
 
            .all()
 

	
 
        journal = self._get_journal_data(c.following)
 

	
 
        feed = Rss201rev2Feed(title=self.title % 'rss',
rhodecode/controllers/login.py
Show inline comments
 
@@ -59,25 +59,23 @@ class LoginController(BaseController):
 

	
 
        if request.POST:
 
            #import Login Form validator class
 
            login_form = LoginForm()
 
            try:
 
                c.form_result = login_form.to_python(dict(request.POST))
 
                #form checks for username/password, now we're authenticated
 
                username = c.form_result['username']
 
                user = UserModel().get_by_username(username, case_insensitive=True)
 
                auth_user = AuthUser()
 
                auth_user.username = user.username
 
                auth_user.is_authenticated = True
 
                auth_user.is_admin = user.admin
 
                auth_user.user_id = user.user_id
 
                auth_user.name = user.name
 
                auth_user.lastname = user.lastname
 
                user = UserModel().get_by_username(username,
 
                                                   case_insensitive=True)
 
                auth_user = AuthUser(user.user_id)
 
                auth_user.set_authenticated()
 
                session['rhodecode_user'] = auth_user
 
                session.save()
 
                log.info('user %s is now authenticated', username)
 

	
 
                log.info('user %s is now authenticated and stored in session',
 
                         username)
 
                user.update_lastlogin()
 

	
 
                if c.came_from:
 
                    return redirect(c.came_from)
 
                else:
 
                    return redirect(url('home'))
 
@@ -143,10 +141,10 @@ class LoginController(BaseController):
 
                    prefix_error=False,
 
                    encoding="UTF-8")
 

	
 
        return render('/password_reset.html')
 

	
 
    def logout(self):
 
        session['rhodecode_user'] = AuthUser()
 
        del session['rhodecode_user']
 
        session.save()
 
        log.info('Logging out and setting user as Empty')
 
        redirect(url('home'))
rhodecode/lib/auth.py
Show inline comments
 
@@ -39,25 +39,17 @@ from pylons.i18n.translation import _
 
from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
 
from rhodecode.lib.utils import get_repo_slug
 
from rhodecode.lib.auth_ldap import AuthLdap
 

	
 
from rhodecode.model import meta
 
from rhodecode.model.user import UserModel
 
from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
 
    UserToPerm, UsersGroupToPerm, UsersGroupMember
 
from rhodecode.model.db import Permission
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
PERM_WEIGHTS = {'repository.none':0,
 
                'repository.read':1,
 
                'repository.write':3,
 
                'repository.admin':3}
 

	
 

	
 
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
 
@@ -182,27 +174,72 @@ def authenticate(username, password):
 
            except (Exception,):
 
                log.error(traceback.format_exc())
 
                pass
 
    return False
 

	
 
class  AuthUser(object):
 
    """A simple object that handles a mercurial username for authentication
 
    """
 
    A simple object that handles all attributes of user in RhodeCode
 
    
 
    It does lookup based on API key,given user, or user present in session
 
    Then it fills all required information for such user. It also checks if 
 
    anonymous access is enabled and if so, it returns default user as logged
 
    in
 
    """
 

	
 
    def __init__(self):
 
    def __init__(self, user_id=None, api_key=None):
 

	
 
        self.user_id = user_id
 
        self.api_key = api_key
 

	
 
        self.username = 'None'
 
        self.name = ''
 
        self.lastname = ''
 
        self.email = ''
 
        self.user_id = None
 
        self.is_authenticated = False
 
        self.is_admin = False
 
        self.admin = False
 
        self.permissions = {}
 
        self.propagate_data()
 

	
 

	
 
    def propagate_data(self):
 
        user_model = UserModel()
 
        if self.api_key:
 
            #try go get user by api key
 
            log.debug('Auth User lookup by API KEY %s', self.api_key)
 
            user_model.fill_data(self, api_key=self.api_key)
 
        else:
 
            log.debug('Auth User lookup by USER ID %s', self.user_id)
 
            self.anonymous_user = user_model.get_by_username('default', cache=True)
 

	
 
            if self.user_id is not None and self.user_id != self.anonymous_user.user_id:
 
                user_model.fill_data(self, user_id=self.user_id)
 
            else:
 
                if self.anonymous_user.active is True:
 
                    user_model.fill_data(self, user_id=self.anonymous_user.user_id)
 
                    #then we set this user is logged in
 
                    self.is_authenticated = True
 
                else:
 
                    self.is_authenticated = False
 

	
 
        log.debug('Auth User is now %s', self)
 
        user_model.fill_perms(self)
 

	
 
    @property
 
    def is_admin(self):
 
        return self.admin
 

	
 
    def __repr__(self):
 
        return "<AuthUser('id:%s:%s')>" % (self.user_id, self.username)
 
        return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
 
                                              self.is_authenticated)
 

	
 
    def set_authenticated(self, authenticated=True):
 

	
 
        if self.user_id != self.anonymous_user.user_id:
 
            self.is_authenticated = authenticated
 

	
 

	
 
def set_available_permissions(config):
 
    """This function will propagate pylons globals with all available defined
 
    permission given in db. We don't want 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
 
@@ -218,150 +255,48 @@ def set_available_permissions(config):
 
        pass
 
    finally:
 
        meta.Session.remove()
 

	
 
    config['available_permissions'] = [x.permission_name for x in all_perms]
 

	
 
def fill_perms(user):
 
    """Fills user permission attribute with permissions taken from database
 
    works for permissions given for repositories, and for permissions that
 
    as part of beeing group member
 
    
 
    :param user: user instance to fill his perms
 
    """
 

	
 
    sa = meta.Session()
 
    user.permissions['repositories'] = {}
 
    user.permissions['global'] = set()
 

	
 
    #===========================================================================
 
    # fetch default permissions
 
    #===========================================================================
 
    default_user = UserModel().get_by_username('default', cache=True)
 

	
 
    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 == default_user).all()
 

	
 
    if user.is_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
 
        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 for 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, 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
 

	
 

	
 
        #=======================================================================
 
        # check if user is part of groups for this repository and fill in 
 
        # (or replace with higher) permissions
 
        #=======================================================================
 
        user_perms_from_users_groups = sa.query(UsersGroupToPerm, Permission, Repository,)\
 
            .join((Repository, UsersGroupToPerm.repository_id == Repository.repo_id))\
 
            .join((Permission, UsersGroupToPerm.permission_id == Permission.permission_id))\
 
            .join((UsersGroupMember, UsersGroupToPerm.users_group_id == UsersGroupMember.users_group_id))\
 
            .filter(UsersGroupMember.user_id == user.user_id).all()
 

	
 
        for perm in user_perms_from_users_groups:
 
            p = perm.Permission.permission_name
 
            cur_perm = user.permissions['repositories'][perm.UsersGroupToPerm.repository.repo_name]
 
            #overwrite permission only if it's greater than permission given from other sources
 
            if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
 
                user.permissions['repositories'][perm.UsersGroupToPerm.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('rhodecode_user', AuthUser())
 
    #if the user is not logged in we check for anonymous access
 
    #if user is logged and it's a default user check if we still have anonymous
 
    #access enabled
 
    if user.user_id is None or user.username == 'default':
 
        anonymous_user = UserModel().get_by_username('default', cache=True)
 
        if anonymous_user.active is True:
 
            #then we set this user is logged in
 
            user.is_authenticated = True
 
            user.user_id = anonymous_user.user_id
 
        else:
 
            user.is_authenticated = False
 

	
 
    if user.is_authenticated:
 
        user = UserModel().fill_data(user)
 

	
 
    user = fill_perms(user)
 
    session['rhodecode_user'] = user
 
    session.save()
 
    return user
 

	
 
#===============================================================================
 
# CHECK DECORATORS
 
#===============================================================================
 
class LoginRequired(object):
 
    """Must be logged in to execute this function else 
 
    redirect to login page"""
 
    """
 
    Must be logged in to execute this function else 
 
    redirect to login page
 
    
 
    :param api_access: if enabled this checks only for valid auth token
 
        and grants access based on valid token
 
    """
 

	
 
    def __init__(self, api_access=False):
 
        self.api_access = api_access
 

	
 
    def __call__(self, func):
 
        return decorator(self.__wrapper, func)
 

	
 
    def __wrapper(self, func, *fargs, **fkwargs):
 
        user = session.get('rhodecode_user', AuthUser())
 
        log.debug('Checking login required for user:%s', user.username)
 
        if user.is_authenticated:
 
        cls = fargs[0]
 
        user = cls.rhodecode_user
 

	
 
        api_access_ok = False
 
        if self.api_access:
 
            log.debug('Checking API KEY access for %s', cls)
 
            if user.api_key == request.GET.get('api_key'):
 
                api_access_ok = True
 
            else:
 
                log.debug("API KEY token not valid")
 

	
 
        log.debug('Checking if %s is authenticated @ %s', user.username, cls)
 
        if user.is_authenticated or api_access_ok:
 
            log.debug('user %s is authenticated', user.username)
 
            return func(*fargs, **fkwargs)
 
        else:
 
            log.warn('user %s not authenticated', user.username)
 
            log.warn('user %s NOT authenticated', user.username)
 

	
 
            p = ''
 
            if request.environ.get('SCRIPT_NAME') != '/':
 
                p += request.environ.get('SCRIPT_NAME')
 

	
 
            p += request.environ.get('PATH_INFO')
 
@@ -376,16 +311,18 @@ class NotAnonymous(object):
 
    redirect to login page"""
 

	
 
    def __call__(self, func):
 
        return decorator(self.__wrapper, func)
 

	
 
    def __wrapper(self, func, *fargs, **fkwargs):
 
        user = session.get('rhodecode_user', AuthUser())
 
        log.debug('Checking if user is not anonymous')
 
        cls = fargs[0]
 
        self.user = cls.rhodecode_user
 

	
 
        anonymous = user.username == 'default'
 
        log.debug('Checking if user is not anonymous @%s', cls)
 

	
 
        anonymous = self.user.username == 'default'
 

	
 
        if anonymous:
 
            p = ''
 
            if request.environ.get('SCRIPT_NAME') != '/':
 
                p += request.environ.get('SCRIPT_NAME')
 

	
 
@@ -398,13 +335,13 @@ class NotAnonymous(object):
 
                    category='warning')
 
            return redirect(url('login_home', came_from=p))
 
        else:
 
            return func(*fargs, **fkwargs)
 

	
 
class PermsDecorator(object):
 
    """Base class for decorators"""
 
    """Base class for controller 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)
 
@@ -413,28 +350,25 @@ class PermsDecorator(object):
 

	
 
    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 = session.get('rhodecode_user', AuthUser())
 
        cls = fargs[0]
 
        self.user = cls.rhodecode_user
 
        self.user_perms = self.user.permissions
 
        log.debug('checking %s permissions %s for %s %s',
 
           self.__class__.__name__, self.required_perms, func.__name__,
 
           self.__class__.__name__, self.required_perms, cls,
 
               self.user)
 

	
 
        if self.check_permissions():
 
            log.debug('Permission granted for %s %s', func.__name__, self.user)
 

	
 
            log.debug('Permission granted for %s %s', cls, self.user)
 
            return func(*fargs, **fkwargs)
 

	
 
        else:
 
            log.warning('Permission denied for %s %s', func.__name__, self.user)
 
            log.warning('Permission denied for %s %s', cls, self.user)
 
            #redirect with forbidden ret code
 
            return abort(403)
 

	
 

	
 

	
 
    def check_permissions(self):
 
@@ -513,24 +447,24 @@ class PermsFunction(object):
 

	
 
    def __call__(self, check_Location=''):
 
        user = session.get('rhodecode_user', False)
 
        if not user:
 
            return False
 
        self.user_perms = user.permissions
 
        self.granted_for = user.username
 
        self.granted_for = user
 
        log.debug('checking %s %s %s', self.__class__.__name__,
 
                  self.required_perms, user)
 

	
 
        if self.check_permissions():
 
            log.debug('Permission granted for %s @ %s %s', self.granted_for,
 
                      check_Location, user)
 
            log.debug('Permission granted %s @ %s', self.granted_for,
 
                      check_Location or 'unspecified location')
 
            return True
 

	
 
        else:
 
            log.warning('Permission denied for %s @ %s %s', self.granted_for,
 
                        check_Location, user)
 
            log.warning('Permission denied for %s @ %s', self.granted_for,
 
                        check_Location or 'unspecified location')
 
            return False
 

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

	
 
@@ -592,20 +526,15 @@ class HasRepoPermissionAny(PermsFunction
 

	
 
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
 

	
 
        usr = AuthUser(user.user_id)
 
        try:
 
            self.user_perms = set([fill_perms(usr)\
 
                                   .permissions['repositories'][repo_name]])
 
            self.user_perms = set([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()
rhodecode/lib/base.py
Show inline comments
 
@@ -3,13 +3,13 @@
 
Provides the BaseController class for subclassing.
 
"""
 
from pylons import config, tmpl_context as c, request, session
 
from pylons.controllers import WSGIController
 
from pylons.templating import render_mako as render
 
from rhodecode import __version__
 
from rhodecode.lib import auth
 
from rhodecode.lib.auth import AuthUser
 
from rhodecode.lib.utils import get_repo_slug
 
from rhodecode.model import meta
 
from rhodecode.model.scm import ScmModel
 
from rhodecode import BACKENDS
 

	
 
class BaseController(WSGIController):
 
@@ -31,13 +31,20 @@ class BaseController(WSGIController):
 
        """Invoke the Controller"""
 
        # WSGIController.__call__ dispatches to the Controller method
 
        # the request is routed to. This routing information is
 
        # available in environ['pylons.routes_dict']
 
        try:
 
            #putting this here makes sure that we update permissions every time
 
            self.rhodecode_user = c.rhodecode_user = auth.get_user(session)
 
            api_key = request.GET.get('api_key')
 
            user_id = getattr(session.get('rhodecode_user'), 'user_id', None)
 
            self.rhodecode_user = c.rhodecode_user = AuthUser(user_id, api_key)
 
            self.rhodecode_user.set_authenticated(
 
                                        getattr(session.get('rhodecode_user'),
 
                                       'is_authenticated', False))
 
            session['rhodecode_user'] = self.rhodecode_user
 
            session.save()
 
            return WSGIController.__call__(self, environ, start_response)
 
        finally:
 
            meta.Session.remove()
 

	
 

	
 
class BaseRepoController(BaseController):
rhodecode/model/user.py
Show inline comments
 
@@ -29,21 +29,26 @@ import logging
 
import traceback
 

	
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.caching_query import FromCache
 
from rhodecode.model.db import User
 

	
 
from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \
 
    UserToPerm, UsersGroupToPerm, UsersGroupMember
 
from rhodecode.lib.exceptions import DefaultUserException, UserOwnsReposException
 

	
 
from sqlalchemy.exc import DatabaseError
 
from rhodecode.lib import generate_api_key
 

	
 
log = logging.getLogger(__name__)
 

	
 
PERM_WEIGHTS = {'repository.none':0,
 
                'repository.read':1,
 
                'repository.write':3,
 
                'repository.admin':3}
 

	
 
class UserModel(BaseModel):
 

	
 
    def get(self, user_id, cache=False):
 
        user = self.sa.query(User)
 
        if cache:
 
            user = user.options(FromCache("sql_cache_short",
 
@@ -60,12 +65,22 @@ class UserModel(BaseModel):
 
                .filter(User.username == username)
 
        if cache:
 
            user = user.options(FromCache("sql_cache_short",
 
                                          "get_user_%s" % username))
 
        return user.scalar()
 

	
 

	
 
    def get_by_api_key(self, api_key, cache=False):
 

	
 
        user = self.sa.query(User)\
 
                .filter(User.api_key == api_key)
 
        if cache:
 
            user = user.options(FromCache("sql_cache_short",
 
                                          "get_user_%s" % api_key))
 
        return user.scalar()
 

	
 
    def create(self, form_data):
 
        try:
 
            new_user = User()
 
            for k, v in form_data.items():
 
                setattr(new_user, k, v)
 

	
 
@@ -201,30 +216,128 @@ class UserModel(BaseModel):
 

	
 
    def reset_password(self, data):
 
        from rhodecode.lib.celerylib import tasks, run_task
 
        run_task(tasks.reset_user_password, data['email'])
 

	
 

	
 
    def fill_data(self, user):
 
    def fill_data(self, auth_user, user_id=None, api_key=None):
 
        """
 
        Fills user data with those from database and log out user if not 
 
        Fetches auth_user by user_id,or api_key if present.
 
        Fills auth_user attributes with those taken from database.
 
        Additionally set's is_authenitated if lookup fails 
 
        present in database
 
        :param user:
 
        
 
        :param auth_user: instance of user to set attributes
 
        :param user_id: user id to fetch by
 
        :param api_key: api key to fetch by
 
        """
 
        if not user_id and not not api_key:
 
            raise Exception('You need to pass user_id or api_key')
 

	
 
        if not hasattr(user, 'user_id') or user.user_id is None:
 
            raise Exception('passed in user has to have the user_id attribute')
 
        try:
 
            if api_key:
 
                dbuser = self.get_by_api_key(api_key)
 
            else:
 
                dbuser = self.get(user_id)
 

	
 
            log.debug('filling %s data', dbuser)
 
            for k, v in dbuser.get_dict().items():
 
                setattr(auth_user, k, v)
 

	
 
        except:
 
            log.error(traceback.format_exc())
 
            auth_user.is_authenticated = False
 

	
 
        return auth_user
 

	
 

	
 
        log.debug('filling auth user data')
 
        try:
 
            dbuser = self.get(user.user_id)
 
            user.username = dbuser.username
 
            user.is_admin = dbuser.admin
 
            user.name = dbuser.name
 
            user.lastname = dbuser.lastname
 
            user.email = dbuser.email
 
        except:
 
            log.error(traceback.format_exc())
 
            user.is_authenticated = False
 
    def fill_perms(self, user):
 
        """Fills user permission attribute with permissions taken from database
 
        works for permissions given for repositories, and for permissions that
 
        as part of beeing group member
 
        
 
        :param user: user instance to fill his perms
 
        """
 

	
 
        user.permissions['repositories'] = {}
 
        user.permissions['global'] = set()
 

	
 
        #===========================================================================
 
        # fetch default permissions
 
        #===========================================================================
 
        default_user = self.get_by_username('default', cache=True)
 

	
 
        default_perms = self.sa.query(RepoToPerm, Repository, Permission)\
 
            .join((Repository, RepoToPerm.repository_id == Repository.repo_id))\
 
            .join((Permission, RepoToPerm.permission_id == Permission.permission_id))\
 
            .filter(RepoToPerm.user == default_user).all()
 

	
 
        if user.is_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
 
            default_global_perms = self.sa.query(UserToPerm)\
 
                .filter(UserToPerm.user == self.sa.query(User)\
 
                       .filter(User.username == 'default').one())
 

	
 
            for perm in default_global_perms:
 
                user.permissions['global'].add(perm.permission.permission_name)
 

	
 
            #default for repositories
 
            for perm in default_perms:
 
                if perm.Repository.private and not perm.Repository.user_id == user.user_id:
 
                    #diself.sable 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 = self.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
 

	
 

	
 
            #=======================================================================
 
            # check if user is part of groups for this repository and fill in 
 
            # (or replace with higher) permissions
 
            #=======================================================================
 
            user_perms_from_users_groups = self.sa.query(UsersGroupToPerm, Permission, Repository,)\
 
                .join((Repository, UsersGroupToPerm.repository_id == Repository.repo_id))\
 
                .join((Permission, UsersGroupToPerm.permission_id == Permission.permission_id))\
 
                .join((UsersGroupMember, UsersGroupToPerm.users_group_id == UsersGroupMember.users_group_id))\
 
                .filter(UsersGroupMember.user_id == user.user_id).all()
 

	
 
            for perm in user_perms_from_users_groups:
 
                p = perm.Permission.permission_name
 
                cur_perm = user.permissions['repositories'][perm.UsersGroupToPerm.repository.repo_name]
 
                #overwrite permission only if it's greater than permission given from other sources
 
                if PERM_WEIGHTS[p] > PERM_WEIGHTS[cur_perm]:
 
                    user.permissions['repositories'][perm.UsersGroupToPerm.repository.repo_name] = p
 

	
 
        return user
0 comments (0 inline, 0 general)