Changeset - 4c79659e11e5
[Not reviewed]
default
0 1 0
Mads Kiilerich (mads) - 6 years ago 2020-08-23 14:33:53
mads@kiilerich.com
auth: compute AuthUser.global_permissions lazily
1 file changed with 53 insertions and 54 deletions:
0 comments (0 inline, 0 general)
kallithea/lib/auth.py
Show inline comments
 
@@ -125,72 +125,62 @@ def bump_permission(permissions, key, ne
 
    has higher weight, else drop it and keep the old permission.
 
    """
 
    cur_perm = permissions[key]
 
    new_perm_val = PERM_WEIGHTS[new_perm]
 
    cur_perm_val = PERM_WEIGHTS[cur_perm]
 
    if new_perm_val > cur_perm_val:
 
        permissions[key] = new_perm
 

	
 
def get_user_permissions(user_id, user_is_admin):
 
    repository_permissions = {}
 
    repository_group_permissions = {}
 
    user_group_permissions = {}
 
    global_permissions = set()
 

	
 

	
 
    #======================================================================
 
    # fetch default permissions
 
    #======================================================================
 
    default_repo_perms = Permission.get_default_perms(kallithea.DEFAULT_USER_ID)
 
    default_repo_groups_perms = Permission.get_default_group_perms(kallithea.DEFAULT_USER_ID)
 
    default_user_group_perms = Permission.get_default_user_group_perms(kallithea.DEFAULT_USER_ID)
 

	
 
    if user_is_admin:
 
        #==================================================================
 
        # admin users have all rights;
 
        # based on default permissions, just set everything to admin
 
        #==================================================================
 
        global_permissions.add('hg.admin')
 

	
 
        # repositories
 
        for perm in default_repo_perms:
 
            r_k = perm.repository.repo_name
 
            p = 'repository.admin'
 
            repository_permissions[r_k] = p
 

	
 
        # repository groups
 
        for perm in default_repo_groups_perms:
 
            rg_k = perm.group.group_name
 
            p = 'group.admin'
 
            repository_group_permissions[rg_k] = p
 

	
 
        # user groups
 
        for perm in default_user_group_perms:
 
            u_k = perm.user_group.users_group_name
 
            p = 'usergroup.admin'
 
            user_group_permissions[u_k] = p
 
        return (repository_permissions, repository_group_permissions, user_group_permissions, global_permissions)
 
        return (repository_permissions, repository_group_permissions, user_group_permissions)
 

	
 
    #==================================================================
 
    # SET DEFAULTS GLOBAL, REPOS, REPOSITORY GROUPS
 
    #==================================================================
 

	
 
    # default global permissions taken from the default user
 
    default_global_perms = UserToPerm.query() \
 
        .filter(UserToPerm.user_id == kallithea.DEFAULT_USER_ID) \
 
        .options(joinedload(UserToPerm.permission))
 

	
 
    for perm in default_global_perms:
 
        global_permissions.add(perm.permission.permission_name)
 

	
 
    # defaults for repositories, taken from default user
 
    for perm in default_repo_perms:
 
        r_k = perm.repository.repo_name
 
        if perm.repository.owner_id == user_id:
 
            p = 'repository.admin'
 
        elif perm.repository.private:
 
            p = 'repository.none'
 
        else:
 
            p = perm.permission.permission_name
 
        repository_permissions[r_k] = p
 

	
 
    # defaults for repository groups taken from default user permission
 
@@ -199,65 +189,24 @@ def get_user_permissions(user_id, user_i
 
        rg_k = perm.group.group_name
 
        p = perm.permission.permission_name
 
        repository_group_permissions[rg_k] = p
 

	
 
    # defaults for user groups taken from default user permission
 
    # on given user group
 
    for perm in default_user_group_perms:
 
        u_k = perm.user_group.users_group_name
 
        p = perm.permission.permission_name
 
        user_group_permissions[u_k] = p
 

	
 
    #======================================================================
 
    # !! Augment GLOBALS with user permissions if any found !!
 
    #======================================================================
 

	
 
    # USER GROUPS comes first
 
    # user group global permissions
 
    user_perms_from_users_groups = Session().query(UserGroupToPerm) \
 
        .options(joinedload(UserGroupToPerm.permission)) \
 
        .join((UserGroupMember, UserGroupToPerm.users_group_id ==
 
               UserGroupMember.users_group_id)) \
 
        .filter(UserGroupMember.user_id == user_id) \
 
        .join((UserGroup, UserGroupMember.users_group_id ==
 
               UserGroup.users_group_id)) \
 
        .filter(UserGroup.users_group_active == True) \
 
        .order_by(UserGroupToPerm.users_group_id) \
 
        .all()
 
    # need to group here by groups since user can be in more than
 
    # one group
 
    _grouped = [[x, list(y)] for x, y in
 
                itertools.groupby(user_perms_from_users_groups,
 
                                  lambda x:x.users_group)]
 
    for gr, perms in _grouped:
 
        for perm in perms:
 
            global_permissions.add(perm.permission.permission_name)
 

	
 
    # user specific global permissions
 
    user_perms = Session().query(UserToPerm) \
 
            .options(joinedload(UserToPerm.permission)) \
 
            .filter(UserToPerm.user_id == user_id).all()
 

	
 
    for perm in user_perms:
 
        global_permissions.add(perm.permission.permission_name)
 

	
 
    # for each kind of global permissions, only keep the one with heighest weight
 
    kind_max_perm = {}
 
    for perm in sorted(global_permissions, key=lambda n: PERM_WEIGHTS.get(n, -1)):
 
        kind = perm.rsplit('.', 1)[0]
 
        kind_max_perm[kind] = perm
 
    global_permissions = set(kind_max_perm.values())
 
    ## END GLOBAL PERMISSIONS
 

	
 
    #======================================================================
 
    # !! PERMISSIONS FOR REPOSITORIES !!
 
    #======================================================================
 
    #======================================================================
 
    # check if user is part of user groups for this repository and
 
    # fill in his permission from it.
 
    #======================================================================
 

	
 
    # user group for repositories permissions
 
    user_repo_perms_from_users_groups = \
 
     Session().query(UserGroupRepoToPerm) \
 
        .join((UserGroup, UserGroupRepoToPerm.users_group_id ==
 
               UserGroup.users_group_id)) \
 
@@ -332,25 +281,25 @@ def get_user_permissions(user_id, user_i
 
    for perm in user_group_user_groups_perms:
 
        bump_permission(user_group_permissions,
 
            perm.target_user_group.users_group_name,
 
            perm.permission.permission_name)
 

	
 
    # user explicit permission for user groups
 
    user_user_groups_perms = Permission.get_default_user_group_perms(user_id)
 
    for perm in user_user_groups_perms:
 
        bump_permission(user_group_permissions,
 
            perm.user_group.users_group_name,
 
            perm.permission.permission_name)
 

	
 
    return (repository_permissions, repository_group_permissions, user_group_permissions, global_permissions)
 
    return (repository_permissions, repository_group_permissions, user_group_permissions)
 

	
 

	
 
class AuthUser(object):
 
    """
 
    Represents a Kallithea user, including various authentication and
 
    authorization information. Typically used to store the current user,
 
    but is also used as a generic user information data structure in
 
    parts of the code, e.g. user management.
 

	
 
    Constructed from a database `User` object, a user ID or cookie dict,
 
    it looks up the user (if needed) and copies all attributes to itself,
 
    adding various non-persistent data. If lookup fails but anonymous
 
@@ -421,28 +370,78 @@ class AuthUser(object):
 
        if dbuser.is_default_user and not dbuser.active:
 
            self.username = 'None'
 
            self.is_default_user = False
 
        else:
 
            # copy non-confidential database fields from a `db.User` to this `AuthUser`.
 
            for k, v in dbuser.get_dict().items():
 
                assert k not in ['api_keys', 'permissions']
 
                setattr(self, k, v)
 
            self.is_default_user = dbuser.is_default_user
 
        log.debug('Auth User is now %s', self)
 

	
 
        log.debug('Getting PERMISSION tree for %s', self)
 
        (self.repository_permissions, self.repository_group_permissions, self.user_group_permissions, self.global_permissions,
 
        (self.repository_permissions, self.repository_group_permissions, self.user_group_permissions,
 
        )= get_user_permissions(self.user_id, self.is_admin)
 

	
 
    @LazyProperty
 
    def global_permissions(self):
 
        log.debug('Getting global permissions for %s', self)
 

	
 
        if self.is_admin:
 
            return set(['hg.admin'])
 

	
 
        global_permissions = set()
 

	
 
        # default global permissions from the default user
 
        default_global_perms = UserToPerm.query() \
 
            .filter(UserToPerm.user_id == kallithea.DEFAULT_USER_ID) \
 
            .options(joinedload(UserToPerm.permission))
 
        for perm in default_global_perms:
 
            global_permissions.add(perm.permission.permission_name)
 

	
 
        # user group global permissions
 
        user_perms_from_users_groups = Session().query(UserGroupToPerm) \
 
            .options(joinedload(UserGroupToPerm.permission)) \
 
            .join((UserGroupMember, UserGroupToPerm.users_group_id ==
 
                   UserGroupMember.users_group_id)) \
 
            .filter(UserGroupMember.user_id == self.user_id) \
 
            .join((UserGroup, UserGroupMember.users_group_id ==
 
                   UserGroup.users_group_id)) \
 
            .filter(UserGroup.users_group_active == True) \
 
            .order_by(UserGroupToPerm.users_group_id) \
 
            .all()
 
        # need to group here by groups since user can be in more than
 
        # one group
 
        _grouped = [[x, list(y)] for x, y in
 
                    itertools.groupby(user_perms_from_users_groups,
 
                                      lambda x:x.users_group)]
 
        for gr, perms in _grouped:
 
            for perm in perms:
 
                global_permissions.add(perm.permission.permission_name)
 

	
 
        # user specific global permissions
 
        user_perms = Session().query(UserToPerm) \
 
                .options(joinedload(UserToPerm.permission)) \
 
                .filter(UserToPerm.user_id == self.user_id).all()
 
        for perm in user_perms:
 
            global_permissions.add(perm.permission.permission_name)
 

	
 
        # for each kind of global permissions, only keep the one with heighest weight
 
        kind_max_perm = {}
 
        for perm in sorted(global_permissions, key=lambda n: PERM_WEIGHTS.get(n, -1)):
 
            kind = perm.rsplit('.', 1)[0]
 
            kind_max_perm[kind] = perm
 
        return set(kind_max_perm.values())
 

	
 
    @LazyProperty
 
    def permissions(self):
 
        """dict with all 4 kind of permissions - mainly for backwards compatibility"""
 
        return {
 
            'global': self.global_permissions,
 
            'repositories': self.repository_permissions,
 
            'repositories_groups': self.repository_group_permissions,
 
            'user_groups': self.user_group_permissions,
 
        }
 

	
 
    def has_repository_permission_level(self, repo_name, level, purpose=None):
 
        required_perms = {
 
            'read': ['repository.read', 'repository.write', 'repository.admin'],
0 comments (0 inline, 0 general)