Changeset - 41e70d120a5e
[Not reviewed]
default
0 2 0
Mads Kiilerich - 9 years ago 2016-09-12 17:41:19
madski@unity3d.com
api: set authuser in the thread global request instace - and temporarily verify that it matches what is passed explicitly to auth methods

This makes it more like what middleware / controllers do for "normal" HTTP requests.
2 files changed with 14 insertions and 15 deletions:
0 comments (0 inline, 0 general)
kallithea/controllers/api/__init__.py
Show inline comments
 
@@ -25,24 +25,25 @@ Original author and date, and relevant c
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import inspect
 
import logging
 
import types
 
import traceback
 
import time
 
import itertools
 

	
 
from paste.response import replace_header
 
from pylons.controllers import WSGIController
 
from pylons import request
 

	
 
from webob.exc import HTTPError
 

	
 
from kallithea.model.db import User
 
from kallithea.model import meta
 
from kallithea.lib.compat import json
 
from kallithea.lib.auth import AuthUser
 
from kallithea.lib.base import _get_ip_addr as _get_ip, _get_access_path
 
from kallithea.lib.utils2 import safe_unicode, safe_str
 

	
 
log = logging.getLogger('JSONRPC')
 

	
 
@@ -181,25 +182,25 @@ class JSONRPCController(WSGIController):
 
        argspec = inspect.getargspec(self._func)
 
        arglist = argspec[0][1:]
 
        defaults = map(type, argspec[3] or [])
 
        default_empty = types.NotImplementedType
 

	
 
        # kw arguments required by this method
 
        func_kwargs = dict(itertools.izip_longest(reversed(arglist), reversed(defaults),
 
                                                  fillvalue=default_empty))
 

	
 
        # this is little trick to inject logged in user for
 
        # perms decorators to work they expect the controller class to have
 
        # authuser attribute set
 
        self.authuser = auth_u
 
        self.authuser = request.user = auth_u
 

	
 
        # This attribute will need to be first param of a method that uses
 
        # api_key, which is translated to instance of user at that name
 
        USER_SESSION_ATTR = 'apiuser'
 

	
 
        if USER_SESSION_ATTR not in arglist:
 
            return jsonrpc_error(
 
                retid=self._req_id,
 
                message='This method [%s] does not support '
 
                         'authentication (missing %s param)' % (
 
                                    self._func.__name__, USER_SESSION_ATTR)
 
            )
kallithea/lib/auth.py
Show inline comments
 
@@ -931,40 +931,36 @@ class PermsFunction(object):
 
        self.user_perms = None
 
        self.repo_name = None
 
        self.group_name = None
 

	
 
    def __nonzero__(self):
 
        """ Defend against accidentally forgetting to call the object
 
            and instead evaluating it directly in a boolean context,
 
            which could have security implications.
 
        """
 
        raise AssertionError(self.__class__.__name__ + ' is not a bool and must be called!')
 

	
 
    def __call__(self, check_location='unspecified location', user=None):
 
        if not user:
 
            #TODO: remove this someday,put as user as attribute here
 
            user = request.user
 
        if user:
 
            assert user.user_id == request.user.user_id, (user, request.user)
 

	
 
        # init auth user if not already given
 
        if not isinstance(user, AuthUser):
 
            user = AuthUser(user.user_id)
 
        user = request.user
 
        assert user
 
        assert isinstance(user, AuthUser), user
 

	
 
        cls_name = self.__class__.__name__
 
        check_scope = self._scope()
 
        log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name,
 
                  self.required_perms, user, check_scope,
 
                  check_location)
 
        if not user:
 
            log.debug('Empty request user')
 
            return False
 
        self.user_perms = user.permissions
 

	
 
        result = self.check_permissions()
 
        result_text = 'granted' if result else 'denied'
 
        log.debug('Permission to %s %s for user: %s @ %s',
 
            check_scope, result_text, user, check_location)
 
        return result
 

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

	
 
@@ -1072,41 +1068,43 @@ class HasPermissionAnyMiddleware(object)
 
        return False
 

	
 

	
 
#==============================================================================
 
# SPECIAL VERSION TO HANDLE API AUTH
 
#==============================================================================
 
class _BaseApiPerm(object):
 
    def __init__(self, *perms):
 
        self.required_perms = set(perms)
 

	
 
    def __call__(self, check_location=None, user=None, repo_name=None,
 
                 group_name=None):
 
        assert user
 
        assert user.user_id == request.user.user_id, (user, request.user)
 

	
 
        user = request.user
 
        assert user
 
        assert isinstance(user, AuthUser), user
 

	
 
        cls_name = self.__class__.__name__
 
        check_scope = 'user:%s' % (user)
 
        if repo_name:
 
            check_scope += ', repo:%s' % (repo_name)
 

	
 
        if group_name:
 
            check_scope += ', repo group:%s' % (group_name)
 

	
 
        log.debug('checking cls:%s %s %s @ %s',
 
                  cls_name, self.required_perms, check_scope, check_location)
 
        if not user:
 
            log.debug('Empty User passed into arguments')
 
            return False
 

	
 
        ## process user
 
        if not isinstance(user, AuthUser):
 
            user = AuthUser(user.user_id)
 
        if not check_location:
 
            check_location = 'unspecified'
 
        if self.check_permissions(user.permissions, repo_name, group_name):
 
            log.debug('Permission to %s granted for user: %s @ %s',
 
                      check_scope, user, check_location)
 
            return True
 

	
 
        else:
 
            log.debug('Permission to %s denied for user: %s @ %s',
 
                      check_scope, user, check_location)
 
            return False
 

	
0 comments (0 inline, 0 general)