Ejemplo n.º 1
0
    def _determine_auth_user(api_key, bearer_token, session_authuser):
        """
        Create an `AuthUser` object given the API key/bearer token
        (if any) and the value of the authuser session cookie.
        """

        # Authenticate by bearer token
        if bearer_token is not None:
            api_key = bearer_token

        # Authenticate by API key
        if api_key is not None:
            au = AuthUser(dbuser=User.get_by_api_key(api_key),
                authenticating_api_key=api_key, is_external_auth=True)
            if au.is_anonymous:
                log.warning('API key ****%s is NOT valid', api_key[-4:])
                raise webob.exc.HTTPForbidden(_('Invalid API key'))
            return au

        # Authenticate by session cookie
        # In ancient login sessions, 'authuser' may not be a dict.
        # In that case, the user will have to log in again.
        # v0.3 and earlier included an 'is_authenticated' key; if present,
        # this must be True.
        if isinstance(session_authuser, dict) and session_authuser.get('is_authenticated', True):
            try:
                return AuthUser.from_cookie(session_authuser)
            except UserCreationError as e:
                # container auth or other auth functions that create users on
                # the fly can throw UserCreationError to signal issues with
                # user creation. Explanation should be provided in the
                # exception object.
                from kallithea.lib import helpers as h
                h.flash(e, 'error', logf=log.error)

        # Authenticate by auth_container plugin (if enabled)
        if any(
            plugin.is_container_auth
            for plugin in auth_modules.get_auth_plugins()
        ):
            try:
                user_info = auth_modules.authenticate('', '', request.environ)
            except UserCreationError as e:
                from kallithea.lib import helpers as h
                h.flash(e, 'error', logf=log.error)
            else:
                if user_info is not None:
                    username = user_info['username']
                    user = User.get_by_username(username, case_insensitive=True)
                    return log_in_user(user, remember=False,
                                       is_external_auth=True)

        # User is anonymous
        return AuthUser()
Ejemplo n.º 2
0
 def password_reset_confirmation(self):
     if request.GET and request.GET.get('key'):
         try:
             user = User.get_by_api_key(request.GET.get('key'))
             data = dict(email=user.email)
             UserModel().reset_password(data)
             h.flash(_('Your password reset was successful, '
                       'new password has been sent to your email'),
                         category='success')
         except Exception, e:
             log.error(e)
             return redirect(url('reset_password'))
Ejemplo n.º 3
0
 def password_reset_confirmation(self):
     if request.GET and request.GET.get('key'):
         try:
             user = User.get_by_api_key(request.GET.get('key'))
             data = dict(email=user.email)
             UserModel().reset_password(data)
             h.flash(_('Your password reset was successful, '
                       'new password has been sent to your email'),
                     category='success')
         except Exception, e:
             log.error(e)
             return redirect(url('reset_password'))
Ejemplo n.º 4
0
    def __call__(self, environ, context):
        try:
            ip_addr = _get_ip_addr(environ)
            self._basic_security_checks()

            api_key = request.GET.get('api_key')
            try:
                # Request.authorization may raise ValueError on invalid input
                type, params = request.authorization
            except (ValueError, TypeError):
                pass
            else:
                if type.lower() == 'bearer':
                    api_key = params  # bearer token is an api key too

            if api_key is None:
                authuser = self._determine_auth_user(
                    session.get('authuser'),
                    ip_addr=ip_addr,
                )
                needs_csrf_check = request.method not in ['GET', 'HEAD']

            else:
                dbuser = User.get_by_api_key(api_key)
                if dbuser is None:
                    log.info(
                        'No db user found for authentication with API key ****%s from %s',
                        api_key[-4:], ip_addr)
                authuser = AuthUser.make(dbuser=dbuser,
                                         is_external_auth=True,
                                         ip_addr=ip_addr)
                needs_csrf_check = False  # API key provides CSRF protection

            if authuser is None:
                log.info('No valid user found')
                raise webob.exc.HTTPForbidden()

            # set globals for auth user
            request.authuser = authuser
            request.ip_addr = ip_addr
            request.needs_csrf_check = needs_csrf_check

            log.info(
                'IP: %s User: %s Request: %s',
                request.ip_addr,
                request.authuser,
                get_path_info(environ),
            )
            return super(BaseController, self).__call__(environ, context)
        except webob.exc.HTTPException as e:
            return e
Ejemplo n.º 5
0
    def _determine_auth_user(api_key, session_authuser):
        """
        Create an `AuthUser` object given the API key (if any) and the
        value of the authuser session cookie.
        """

        # Authenticate by API key
        if api_key:
            # when using API_KEY we are sure user exists.
            return AuthUser(dbuser=User.get_by_api_key(api_key),
                            is_external_auth=True)

        # Authenticate by session cookie
        # In ancient login sessions, 'authuser' may not be a dict.
        # In that case, the user will have to log in again.
        # v0.3 and earlier included an 'is_authenticated' key; if present,
        # this must be True.
        if isinstance(session_authuser, dict) and session_authuser.get('is_authenticated', True):
            try:
                return AuthUser.from_cookie(session_authuser)
            except UserCreationError as e:
                # container auth or other auth functions that create users on
                # the fly can throw UserCreationError to signal issues with
                # user creation. Explanation should be provided in the
                # exception object.
                from kallithea.lib import helpers as h
                h.flash(e, 'error', logf=log.error)

        # Authenticate by auth_container plugin (if enabled)
        if any(
            auth_modules.importplugin(name).is_container_auth
            for name in Setting.get_auth_plugins()
        ):
            try:
                user_info = auth_modules.authenticate('', '', request.environ)
            except UserCreationError as e:
                from kallithea.lib import helpers as h
                h.flash(e, 'error', logf=log.error)
            else:
                if user_info is not None:
                    username = user_info['username']
                    user = User.get_by_username(username, case_insensitive=True)
                    return log_in_user(user, remember=False,
                                       is_external_auth=True)

        # User is anonymous
        return AuthUser()
Ejemplo n.º 6
0
            self._req_method = json_body['method']
            self._request_params = json_body['args']
            if not isinstance(self._request_params, dict):
                self._request_params = {}

            log.debug(
                'method: %s, params: %s' % (self._req_method,
                                            self._request_params)
            )
        except KeyError, e:
            return jsonrpc_error(retid=self._req_id,
                                 message='Incorrect JSON query missing %s' % e)

        # check if we can find this session using api_key
        try:
            u = User.get_by_api_key(self._req_api_key)
            if u is None:
                return jsonrpc_error(retid=self._req_id,
                                     message='Invalid API KEY')

            #check if we are allowed to use this IP
            auth_u = AuthUser(u.user_id, self._req_api_key, ip_addr=ip_addr)
            if not auth_u.ip_allowed:
                return jsonrpc_error(retid=self._req_id,
                        message='request from IP:%s not allowed' % (ip_addr,))
            else:
                log.info('Access for IP:%s allowed' % (ip_addr,))

        except Exception, e:
            return jsonrpc_error(retid=self._req_id,
                                 message='Invalid API KEY')
Ejemplo n.º 7
0
 def get_by_api_key(self, api_key, cache=False):
     return User.get_by_api_key(api_key, cache)
Ejemplo n.º 8
0
    def _handle_request(self, environ, start_response):
        start = time.time()
        ip_addr = self.ip_addr = self._get_ip_addr(environ)
        self._req_id = None
        if 'CONTENT_LENGTH' not in environ:
            log.debug("No Content-Length")
            return jsonrpc_error(retid=self._req_id,
                                 message="No Content-Length in request")
        else:
            length = environ['CONTENT_LENGTH'] or 0
            length = int(environ['CONTENT_LENGTH'])
            log.debug('Content-Length: %s', length)

        if length == 0:
            log.debug("Content-Length is 0")
            return jsonrpc_error(retid=self._req_id,
                                 message="Content-Length is 0")

        raw_body = environ['wsgi.input'].read(length)

        try:
            json_body = json.loads(raw_body)
        except ValueError as e:
            # catch JSON errors Here
            return jsonrpc_error(retid=self._req_id,
                                 message="JSON parse error ERR:%s RAW:%r"
                                 % (e, raw_body))

        # check AUTH based on API key
        try:
            self._req_api_key = json_body['api_key']
            self._req_id = json_body['id']
            self._req_method = json_body['method']
            self._request_params = json_body['args']
            if not isinstance(self._request_params, dict):
                self._request_params = {}

            log.debug(
                'method: %s, params: %s', self._req_method,
                                            self._request_params
            )
        except KeyError as e:
            return jsonrpc_error(retid=self._req_id,
                                 message='Incorrect JSON query missing %s' % e)

        # check if we can find this session using api_key
        try:
            u = User.get_by_api_key(self._req_api_key)
            if u is None:
                return jsonrpc_error(retid=self._req_id,
                                     message='Invalid API key')

            auth_u = AuthUser(dbuser=u)
            if not AuthUser.check_ip_allowed(auth_u, ip_addr):
                return jsonrpc_error(retid=self._req_id,
                        message='request from IP:%s not allowed' % (ip_addr,))
            else:
                log.info('Access for IP:%s allowed', ip_addr)

        except Exception as e:
            return jsonrpc_error(retid=self._req_id,
                                 message='Invalid API key')

        self._error = None
        try:
            self._func = self._find_method()
        except AttributeError as e:
            return jsonrpc_error(retid=self._req_id,
                                 message=str(e))

        # now that we have a method, add self._req_params to
        # self.kargs and dispatch control to WGIController
        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(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

        # 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)
            )

        # get our arglist and check if we provided them as args
        for arg, default in func_kwargs.iteritems():
            if arg == USER_SESSION_ATTR:
                # USER_SESSION_ATTR is something translated from API key and
                # this is checked before so we don't need validate it
                continue

            # skip the required param check if it's default value is
            # NotImplementedType (default_empty)
            if default == default_empty and arg not in self._request_params:
                return jsonrpc_error(
                    retid=self._req_id,
                    message=(
                        'Missing non optional `%s` arg in JSON DATA' % arg
                    )
                )

        self._rpc_args = {USER_SESSION_ATTR: u}

        self._rpc_args.update(self._request_params)

        self._rpc_args['action'] = self._req_method
        self._rpc_args['environ'] = environ
        self._rpc_args['start_response'] = start_response

        status = []
        headers = []
        exc_info = []

        def change_content(new_status, new_headers, new_exc_info=None):
            status.append(new_status)
            headers.extend(new_headers)
            exc_info.append(new_exc_info)

        output = WSGIController.__call__(self, environ, change_content)
        output = list(output)
        headers.append(('Content-Length', str(len(output[0]))))
        replace_header(headers, 'Content-Type', 'application/json')
        start_response(status[0], headers, exc_info[0])
        log.info('IP: %s Request to %s time: %.3fs' % (
            self._get_ip_addr(environ),
            safe_unicode(_get_access_path(environ)), time.time() - start)
        )
        return output
Ejemplo n.º 9
0
    def _dispatch(self, state, remainder=None):
        """
        Parse the request body as JSON, look up the method on the
        controller and if it exists, dispatch to it.
        """
        # Since we are here we should respond as JSON
        response.content_type = 'application/json'

        environ = state.request.environ
        start = time.time()
        ip_addr = request.ip_addr = self._get_ip_addr(environ)
        self._req_id = None
        if 'CONTENT_LENGTH' not in environ:
            log.debug("No Content-Length")
            raise JSONRPCErrorResponse(retid=self._req_id,
                                       message="No Content-Length in request")
        else:
            length = environ['CONTENT_LENGTH'] or 0
            length = int(environ['CONTENT_LENGTH'])
            log.debug('Content-Length: %s', length)

        if length == 0:
            raise JSONRPCErrorResponse(retid=self._req_id,
                                       message="Content-Length is 0")

        raw_body = environ['wsgi.input'].read(length)

        try:
            json_body = json.loads(raw_body)
        except ValueError as e:
            # catch JSON errors Here
            raise JSONRPCErrorResponse(
                retid=self._req_id,
                message="JSON parse error ERR:%s RAW:%r" % (e, raw_body))

        # check AUTH based on API key
        try:
            self._req_api_key = json_body['api_key']
            self._req_id = json_body['id']
            self._req_method = json_body['method']
            self._request_params = json_body['args']
            if not isinstance(self._request_params, dict):
                self._request_params = {}

            log.debug('method: %s, params: %s', self._req_method,
                      self._request_params)
        except KeyError as e:
            raise JSONRPCErrorResponse(
                retid=self._req_id,
                message='Incorrect JSON query missing %s' % e)

        # check if we can find this session using api_key
        try:
            u = User.get_by_api_key(self._req_api_key)
            if u is None:
                raise JSONRPCErrorResponse(retid=self._req_id,
                                           message='Invalid API key')

            auth_u = AuthUser(dbuser=u)
            if not AuthUser.check_ip_allowed(auth_u, ip_addr):
                raise JSONRPCErrorResponse(
                    retid=self._req_id,
                    message='request from IP:%s not allowed' % (ip_addr, ))
            else:
                log.info('Access for IP:%s allowed', ip_addr)

        except Exception as e:
            raise JSONRPCErrorResponse(retid=self._req_id,
                                       message='Invalid API key')

        self._error = None
        try:
            self._func = self._find_method()
        except AttributeError as e:
            raise JSONRPCErrorResponse(retid=self._req_id, message=str(e))

        # now that we have a method, add self._req_params to
        # self.kargs and dispatch control to WGIController
        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
        request.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'

        # get our arglist and check if we provided them as args
        for arg, default in func_kwargs.iteritems():
            if arg == USER_SESSION_ATTR:
                # USER_SESSION_ATTR is something translated from API key and
                # this is checked before so we don't need validate it
                continue

            # skip the required param check if it's default value is
            # NotImplementedType (default_empty)
            if default == default_empty and arg not in self._request_params:
                raise JSONRPCErrorResponse(
                    retid=self._req_id,
                    message='Missing non optional `%s` arg in JSON DATA' % arg,
                )

        extra = set(self._request_params).difference(func_kwargs)
        if extra:
            raise JSONRPCErrorResponse(
                retid=self._req_id,
                message='Unknown %s arg in JSON DATA' %
                ', '.join('`%s`' % arg for arg in extra),
            )

        self._rpc_args = {}
        self._rpc_args.update(self._request_params)
        self._rpc_args['action'] = self._req_method
        self._rpc_args['environ'] = environ

        log.info(
            'IP: %s Request to %s time: %.3fs' %
            (self._get_ip_addr(environ), safe_unicode(
                _get_access_path(environ)), time.time() - start))

        state.set_action(self._rpc_call, [])
        state.set_params(self._rpc_args)
        return state
Ejemplo n.º 10
0
    def _dispatch(self, state, remainder=None):
        """
        Parse the request body as JSON, look up the method on the
        controller and if it exists, dispatch to it.
        """
        # Since we are here we should respond as JSON
        response.content_type = 'application/json'

        environ = state.request.environ
        start = time.time()
        ip_addr = request.ip_addr = self._get_ip_addr(environ)
        self._req_id = None
        if 'CONTENT_LENGTH' not in environ:
            log.debug("No Content-Length")
            raise JSONRPCErrorResponse(retid=self._req_id,
                                       message="No Content-Length in request")
        else:
            length = environ['CONTENT_LENGTH'] or 0
            length = int(environ['CONTENT_LENGTH'])
            log.debug('Content-Length: %s', length)

        if length == 0:
            raise JSONRPCErrorResponse(retid=self._req_id,
                                       message="Content-Length is 0")

        raw_body = environ['wsgi.input'].read(length)

        try:
            json_body = json.loads(raw_body)
        except ValueError as e:
            # catch JSON errors Here
            raise JSONRPCErrorResponse(retid=self._req_id,
                                       message="JSON parse error ERR:%s RAW:%r"
                                                % (e, raw_body))

        # check AUTH based on API key
        try:
            self._req_api_key = json_body['api_key']
            self._req_id = json_body['id']
            self._req_method = json_body['method']
            self._request_params = json_body['args']
            if not isinstance(self._request_params, dict):
                self._request_params = {}

            log.debug('method: %s, params: %s',
                      self._req_method, self._request_params)
        except KeyError as e:
            raise JSONRPCErrorResponse(retid=self._req_id,
                                       message='Incorrect JSON query missing %s' % e)

        # check if we can find this session using api_key
        try:
            u = User.get_by_api_key(self._req_api_key)
            if u is None:
                raise JSONRPCErrorResponse(retid=self._req_id,
                                           message='Invalid API key')

            auth_u = AuthUser(dbuser=u)
            if not AuthUser.check_ip_allowed(auth_u, ip_addr):
                raise JSONRPCErrorResponse(retid=self._req_id,
                                           message='request from IP:%s not allowed' % (ip_addr,))
            else:
                log.info('Access for IP:%s allowed', ip_addr)

        except Exception as e:
            raise JSONRPCErrorResponse(retid=self._req_id,
                                       message='Invalid API key')

        self._error = None
        try:
            self._func = self._find_method()
        except AttributeError as e:
            raise JSONRPCErrorResponse(retid=self._req_id,
                                       message=str(e))

        # now that we have a method, add self._req_params to
        # self.kargs and dispatch control to WGIController
        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
        request.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'

        # get our arglist and check if we provided them as args
        for arg, default in func_kwargs.iteritems():
            if arg == USER_SESSION_ATTR:
                # USER_SESSION_ATTR is something translated from API key and
                # this is checked before so we don't need validate it
                continue

            # skip the required param check if it's default value is
            # NotImplementedType (default_empty)
            if default == default_empty and arg not in self._request_params:
                raise JSONRPCErrorResponse(
                    retid=self._req_id,
                    message='Missing non optional `%s` arg in JSON DATA' % arg,
                )

        extra = set(self._request_params).difference(func_kwargs)
        if extra:
                raise JSONRPCErrorResponse(
                    retid=self._req_id,
                    message='Unknown %s arg in JSON DATA' %
                            ', '.join('`%s`' % arg for arg in extra),
                )

        self._rpc_args = {}
        self._rpc_args.update(self._request_params)
        self._rpc_args['action'] = self._req_method
        self._rpc_args['environ'] = environ

        log.info('IP: %s Request to %s time: %.3fs' % (
            self._get_ip_addr(environ),
            safe_unicode(_get_access_path(environ)), time.time() - start)
        )

        state.set_action(self._rpc_call, [])
        state.set_params(self._rpc_args)
        return state
Ejemplo n.º 11
0
            self._req_api_key = json_body['api_key']
            self._req_id = json_body['id']
            self._req_method = json_body['method']
            self._request_params = json_body['args']
            if not isinstance(self._request_params, dict):
                self._request_params = {}

            log.debug('method: %s, params: %s' %
                      (self._req_method, self._request_params))
        except KeyError, e:
            return jsonrpc_error(retid=self._req_id,
                                 message='Incorrect JSON query missing %s' % e)

        # check if we can find this session using api_key
        try:
            u = User.get_by_api_key(self._req_api_key)
            if u is None:
                return jsonrpc_error(retid=self._req_id,
                                     message='Invalid API KEY')

            #check if we are allowed to use this IP
            auth_u = AuthUser(u.user_id, self._req_api_key, ip_addr=ip_addr)
            if not auth_u.ip_allowed:
                return jsonrpc_error(retid=self._req_id,
                                     message='request from IP:%s not allowed' %
                                     (ip_addr, ))
            else:
                log.info('Access for IP:%s allowed' % (ip_addr, ))

        except Exception, e:
            return jsonrpc_error(retid=self._req_id, message='Invalid API KEY')