Example #1
0
    def dispatch(self, obj, action, *args, **kwargs):
        """Find action-specific method on self and call it."""
        try:
            method = getattr(obj, action)
            if isinstance(args[0], Request):
                ser_name = "%s[%s]" % (method.__module__, method.__name__)
                tomograph.start_http(ser_name, method.__name__, args[0])
                tomograph.stop(method.__name__)
        except AttributeError:
            method = getattr(obj, 'default')

        return method(*args, **kwargs)
Example #2
0
    def process_request(self, request):
        """Process request.

        Evaluate the headers in a request and attempt to authenticate the
        request against the identity server. If authenticated then additional
        headers are added to the request for use by applications. If not
        authenticated the request will be rejected or marked unauthenticated
        depending on configuration.
        """
        # pdb.set_trace()
        tomograph.start_http(
            "keystonemiddleware.auth_token.AuthProtocol[process_request]",
            "process_request", request)
        tomograph.add_trace_info_header(request.headers)

        self._token_cache.initialize(request.environ)

        resp = super(AuthProtocol, self).process_request(request)

        tomograph.stop("process_request")

        if resp:
            return resp

        if not request.user_token:
            # if no user token is present then that's an invalid request
            request.user_token_valid = False

        # NOTE(jamielennox): The service status is allowed to be missing if a
        # service token is not passed. If the service status is missing that's
        # a valid request. We should find a better way to expose this from the
        # request object.
        user_status = request.user_token and request.user_token_valid
        service_status = request.headers.get('X-Service-Identity-Status',
                                             'Confirmed')

        if not (user_status and service_status == 'Confirmed'):
            if self._delay_auth_decision:
                self.log.info(_LI('Deferring reject downstream'))
            else:
                self.log.info(_LI('Rejecting request'))
                self._reject_request()

        if request.user_token_valid:
            request.set_user_headers(request.token_auth._user_auth_ref,
                                     self._include_service_catalog)

        if request.service_token and request.service_token_valid:
            request.set_service_headers(request.token_auth._serv_auth_ref)

        if self.log.isEnabledFor(logging.DEBUG):
            self.log.debug('Received request from %s',
                           request.token_auth._log_format)
Example #3
0
File: wsgi.py Project: hbkqh/patch
    def dispatch(self, obj, action, *args, **kwargs):
        """Find action-specific method on self and call it."""
        try:
            method = getattr(obj, action)
            if isinstance(args[0], Request):
                ser_name = "%s[%s]" % (method.__module__, method.__name__)
                tomograph.start_http(ser_name, method.__name__, args[0])
                tomograph.stop(method.__name__)
        except AttributeError:
            method = getattr(obj, 'default')

        return method(*args, **kwargs)
Example #4
0
    def process_request(self, request):
        """Process request.

        Evaluate the headers in a request and attempt to authenticate the
        request against the identity server. If authenticated then additional
        headers are added to the request for use by applications. If not
        authenticated the request will be rejected or marked unauthenticated
        depending on configuration.
        """
        # pdb.set_trace()
        tomograph.start_http("keystonemiddleware.auth_token.AuthProtocol[process_request]", "process_request", request)
        tomograph.add_trace_info_header(request.headers)

        self._token_cache.initialize(request.environ)

        resp = super(AuthProtocol, self).process_request(request)

        tomograph.stop("process_request")

        if resp:
            return resp

        if not request.user_token:
            # if no user token is present then that's an invalid request
            request.user_token_valid = False

        # NOTE(jamielennox): The service status is allowed to be missing if a
        # service token is not passed. If the service status is missing that's
        # a valid request. We should find a better way to expose this from the
        # request object.
        user_status = request.user_token and request.user_token_valid
        service_status = request.headers.get("X-Service-Identity-Status", "Confirmed")

        if not (user_status and service_status == "Confirmed"):
            if self._delay_auth_decision:
                self.log.info(_LI("Deferring reject downstream"))
            else:
                self.log.info(_LI("Rejecting request"))
                self._reject_request()

        if request.user_token_valid:
            request.set_user_headers(request.token_auth._user_auth_ref, self._include_service_catalog)

        if request.service_token and request.service_token_valid:
            request.set_service_headers(request.token_auth._serv_auth_ref)

        if self.log.isEnabledFor(logging.DEBUG):
            self.log.debug("Received request from %s", request.token_auth._log_format)
Example #5
0
File: wsgi.py Project: hbkqh/patch
    def __call__(self, req):
        arg_dict = req.environ['wsgiorg.routing_args'][1]
        action = arg_dict.pop('action')
        del arg_dict['controller']

        # allow middleware up the stack to provide context, params and headers.
        context = req.environ.get(CONTEXT_ENV, {})
        context['query_string'] = dict(req.params.items())
        context['headers'] = dict(req.headers.items())
        context['path'] = req.environ['PATH_INFO']
        scheme = (None if not CONF.secure_proxy_ssl_header else
                  req.environ.get(CONF.secure_proxy_ssl_header))
        if scheme:
            # NOTE(andrey-mp): "wsgi.url_scheme" contains the protocol used
            # before the proxy removed it ('https' usually). So if
            # the webob.Request instance is modified in order to use this
            # scheme instead of the one defined by API, the call to
            # webob.Request.relative_url() will return a URL with the correct
            # scheme.
            req.environ['wsgi.url_scheme'] = scheme
        context['host_url'] = req.host_url
        params = req.environ.get(PARAMS_ENV, {})
        # authentication and authorization attributes are set as environment
        # values by the container and processed by the pipeline.  the complete
        # set is not yet know.
        context['environment'] = req.environ
        context['accept_header'] = req.accept
        req.environ = None

        params.update(arg_dict)

        context.setdefault('is_admin', False)

        # TODO(termie): do some basic normalization on methods
        method = getattr(self, action)

        # NOTE(morganfainberg): use the request method to normalize the
        # response code between GET and HEAD requests. The HTTP status should
        # be the same.
        LOG.info(
            '%(req_method)s %(uri)s', {
                'req_method': req.environ['REQUEST_METHOD'].upper(),
                'uri': wsgiref.util.request_uri(req.environ),
            })

        params = self._normalize_dict(params)

        try:
            ser_name = "%s[%s]" % (method.__module__, method.__name__)
            tomograph.start_http(ser_name, method.__name__, req)
            result = method(context, **params)
            tomograph.stop(method.__name__)
        except exception.Unauthorized as e:
            LOG.warning(
                _LW("Authorization failed. %(exception)s from "
                    "%(remote_addr)s"), {
                        'exception': e,
                        'remote_addr': req.environ['REMOTE_ADDR']
                    })
            return render_exception(e,
                                    context=context,
                                    user_locale=best_match_language(req))
        except exception.Error as e:
            LOG.warning(six.text_type(e))
            return render_exception(e,
                                    context=context,
                                    user_locale=best_match_language(req))
        except TypeError as e:
            LOG.exception(six.text_type(e))
            return render_exception(exception.ValidationError(e),
                                    context=context,
                                    user_locale=best_match_language(req))
        except Exception as e:
            LOG.exception(six.text_type(e))
            return render_exception(exception.UnexpectedError(exception=e),
                                    context=context,
                                    user_locale=best_match_language(req))
        if result is None:
            return render_response(status=(204, 'No Content'))
        elif isinstance(result, six.string_types):
            return result
        elif isinstance(result, webob.Response):
            return result
        elif isinstance(result, webob.exc.WSGIHTTPException):
            return result

        response_code = self._get_response_code(req)
        return render_response(body=result,
                               status=response_code,
                               method=req.environ['REQUEST_METHOD'])
Example #6
0
File: wsgi.py Project: hbkqh/patch
    def _process_stack(self, request, action, action_args,
                       content_type, body, accept):
        """Implement the processing stack."""

        # Get the implementing method
        try:
            meth, extensions = self.get_method(request, action,
                                               content_type, body)
        except (AttributeError, TypeError):
            return Fault(webob.exc.HTTPNotFound())
        except KeyError as ex:
            msg = _("There is no such action: %s") % ex.args[0]
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))
        except exception.MalformedRequestBody:
            msg = _("Malformed request body")
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))

        ser_name = "%s[%s]" % (meth.__module__, meth.__name__)
        tomograph.start_http(ser_name, meth.__name__, request)

        if body:
            msg = _("Action: '%(action)s', calling method: %(meth)s, body: "
                    "%(body)s") % {'action': action,
                                   'body': six.text_type(body, 'utf-8'),
                                   'meth': str(meth)}
            LOG.debug(strutils.mask_password(msg))
        else:
            LOG.debug("Calling method '%(meth)s'",
                      {'meth': str(meth)})

        # Now, deserialize the request body...
        try:
            contents = {}
            if self._should_have_body(request):
                # allow empty body with PUT and POST
                if request.content_length == 0:
                    contents = {'body': None}
                else:
                    contents = self.deserialize(meth, content_type, body)
        except exception.InvalidContentType:
            msg = _("Unsupported Content-Type")
            tomograph.tag("Exception", "Unsupported Content-Type")
            tomograph.stop(meth.__name__)
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))
        except exception.MalformedRequestBody:
            msg = _("Malformed request body")
            tomograph.tag("Exception", "Malformed request body")
            tomograph.stop(meth.__name__)
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))

        # Update the action args
        action_args.update(contents)

        project_id = action_args.pop("project_id", None)
        context = request.environ.get('nova.context')
        if (context and project_id and (project_id != context.project_id)):
            msg = _("Malformed request URL: URL's project_id '%(project_id)s'"
                    " doesn't match Context's project_id"
                    " '%(context_project_id)s'") % \
                    {'project_id': project_id,
                     'context_project_id': context.project_id}
            tomograph.tag("Exception", "HTTPBadRequest")
            tomograph.stop(meth.__name__)
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))

        # Run pre-processing extensions
        response, post = self.pre_process_extensions(extensions,
                                                     request, action_args)

        if not response:
            try:
                with ResourceExceptionHandler():
                    action_result = self.dispatch(meth, request, action_args)
            except Fault as ex:
                response = ex

        if not response:
            # No exceptions; convert action_result into a
            # ResponseObject
            resp_obj = None
            if type(action_result) is dict or action_result is None:
                resp_obj = ResponseObject(action_result)
            elif isinstance(action_result, ResponseObject):
                resp_obj = action_result
            else:
                response = action_result

            # Run post-processing extensions
            if resp_obj:
                # Do a preserialize to set up the response object
                serializers = getattr(meth, 'wsgi_serializers', {})
                resp_obj._bind_method_serializers(serializers)
                if hasattr(meth, 'wsgi_code'):
                    resp_obj._default_code = meth.wsgi_code
                resp_obj.preserialize(accept, self.default_serializers)

                # Process post-processing extensions
                response = self.post_process_extensions(post, resp_obj,
                                                        request, action_args)

            if resp_obj and not response:
                response = resp_obj.serialize(request, accept,
                                              self.default_serializers)

        if hasattr(response, 'headers'):

            for hdr, val in response.headers.items():
                # Headers must be utf-8 strings
                response.headers[hdr] = utils.utf8(str(val))

            if not request.api_version_request.is_null():
                response.headers[API_VERSION_REQUEST_HEADER] = \
                    request.api_version_request.get_string()
                response.headers['Vary'] = API_VERSION_REQUEST_HEADER

        tomograph.stop(meth.__name__)

        return response
Example #7
0
File: wsgi.py Project: hbkqh/patch
    def __call__(self, req):
        arg_dict = req.environ['wsgiorg.routing_args'][1]
        action = arg_dict.pop('action')
        del arg_dict['controller']

        # allow middleware up the stack to provide context, params and headers.
        context = req.environ.get(CONTEXT_ENV, {})
        context['query_string'] = dict(req.params.items())
        context['headers'] = dict(req.headers.items())
        context['path'] = req.environ['PATH_INFO']
        scheme = (None if not CONF.secure_proxy_ssl_header
                  else req.environ.get(CONF.secure_proxy_ssl_header))
        if scheme:
            # NOTE(andrey-mp): "wsgi.url_scheme" contains the protocol used
            # before the proxy removed it ('https' usually). So if
            # the webob.Request instance is modified in order to use this
            # scheme instead of the one defined by API, the call to
            # webob.Request.relative_url() will return a URL with the correct
            # scheme.
            req.environ['wsgi.url_scheme'] = scheme
        context['host_url'] = req.host_url
        params = req.environ.get(PARAMS_ENV, {})
        # authentication and authorization attributes are set as environment
        # values by the container and processed by the pipeline.  the complete
        # set is not yet know.
        context['environment'] = req.environ
        context['accept_header'] = req.accept
        req.environ = None

        params.update(arg_dict)

        context.setdefault('is_admin', False)

        # TODO(termie): do some basic normalization on methods
        method = getattr(self, action)

        # NOTE(morganfainberg): use the request method to normalize the
        # response code between GET and HEAD requests. The HTTP status should
        # be the same.
        LOG.info('%(req_method)s %(uri)s', {
            'req_method': req.environ['REQUEST_METHOD'].upper(),
            'uri': wsgiref.util.request_uri(req.environ),
        })

        params = self._normalize_dict(params)

        try:
            ser_name = "%s[%s]" % (method.__module__, method.__name__)
            tomograph.start_http(ser_name, method.__name__, req)
            result = method(context, **params)
            tomograph.stop(method.__name__)
        except exception.Unauthorized as e:
            LOG.warning(
                _LW("Authorization failed. %(exception)s from "
                    "%(remote_addr)s"),
                {'exception': e, 'remote_addr': req.environ['REMOTE_ADDR']})
            return render_exception(e, context=context,
                                    user_locale=best_match_language(req))
        except exception.Error as e:
            LOG.warning(six.text_type(e))
            return render_exception(e, context=context,
                                    user_locale=best_match_language(req))
        except TypeError as e:
            LOG.exception(six.text_type(e))
            return render_exception(exception.ValidationError(e),
                                    context=context,
                                    user_locale=best_match_language(req))
        except Exception as e:
            LOG.exception(six.text_type(e))
            return render_exception(exception.UnexpectedError(exception=e),
                                    context=context,
                                    user_locale=best_match_language(req))
        if result is None:
            return render_response(status=(204, 'No Content'))
        elif isinstance(result, six.string_types):
            return result
        elif isinstance(result, webob.Response):
            return result
        elif isinstance(result, webob.exc.WSGIHTTPException):
            return result

        response_code = self._get_response_code(req)
        return render_response(body=result, status=response_code,
                               method=req.environ['REQUEST_METHOD'])
Example #8
0
    def _process_stack(self, request, action, action_args, content_type, body,
                       accept):
        """Implement the processing stack."""

        # Get the implementing method
        try:
            meth, extensions = self.get_method(request, action, content_type,
                                               body)
        except (AttributeError, TypeError):
            return Fault(webob.exc.HTTPNotFound())
        except KeyError as ex:
            msg = _("There is no such action: %s") % ex.args[0]
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))
        except exception.MalformedRequestBody:
            msg = _("Malformed request body")
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))

        ser_name = "%s[%s]" % (meth.__module__, meth.__name__)
        tomograph.start_http(ser_name, meth.__name__, request)

        if body:
            msg = _("Action: '%(action)s', calling method: %(meth)s, body: "
                    "%(body)s") % {
                        'action': action,
                        'body': six.text_type(body, 'utf-8'),
                        'meth': str(meth)
                    }
            LOG.debug(strutils.mask_password(msg))
        else:
            LOG.debug("Calling method '%(meth)s'", {'meth': str(meth)})

        # Now, deserialize the request body...
        try:
            contents = {}
            if self._should_have_body(request):
                # allow empty body with PUT and POST
                if request.content_length == 0:
                    contents = {'body': None}
                else:
                    contents = self.deserialize(meth, content_type, body)
        except exception.InvalidContentType:
            msg = _("Unsupported Content-Type")
            tomograph.tag("Exception", "Unsupported Content-Type")
            tomograph.stop(meth.__name__)
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))
        except exception.MalformedRequestBody:
            msg = _("Malformed request body")
            tomograph.tag("Exception", "Malformed request body")
            tomograph.stop(meth.__name__)
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))

        # Update the action args
        action_args.update(contents)

        project_id = action_args.pop("project_id", None)
        context = request.environ.get('nova.context')
        if (context and project_id and (project_id != context.project_id)):
            msg = _("Malformed request URL: URL's project_id '%(project_id)s'"
                    " doesn't match Context's project_id"
                    " '%(context_project_id)s'") % \
                    {'project_id': project_id,
                     'context_project_id': context.project_id}
            tomograph.tag("Exception", "HTTPBadRequest")
            tomograph.stop(meth.__name__)
            return Fault(webob.exc.HTTPBadRequest(explanation=msg))

        # Run pre-processing extensions
        response, post = self.pre_process_extensions(extensions, request,
                                                     action_args)

        if not response:
            try:
                with ResourceExceptionHandler():
                    action_result = self.dispatch(meth, request, action_args)
            except Fault as ex:
                response = ex

        if not response:
            # No exceptions; convert action_result into a
            # ResponseObject
            resp_obj = None
            if type(action_result) is dict or action_result is None:
                resp_obj = ResponseObject(action_result)
            elif isinstance(action_result, ResponseObject):
                resp_obj = action_result
            else:
                response = action_result

            # Run post-processing extensions
            if resp_obj:
                # Do a preserialize to set up the response object
                serializers = getattr(meth, 'wsgi_serializers', {})
                resp_obj._bind_method_serializers(serializers)
                if hasattr(meth, 'wsgi_code'):
                    resp_obj._default_code = meth.wsgi_code
                resp_obj.preserialize(accept, self.default_serializers)

                # Process post-processing extensions
                response = self.post_process_extensions(
                    post, resp_obj, request, action_args)

            if resp_obj and not response:
                response = resp_obj.serialize(request, accept,
                                              self.default_serializers)

        if hasattr(response, 'headers'):

            for hdr, val in response.headers.items():
                # Headers must be utf-8 strings
                response.headers[hdr] = utils.utf8(str(val))

            if not request.api_version_request.is_null():
                response.headers[API_VERSION_REQUEST_HEADER] = \
                    request.api_version_request.get_string()
                response.headers['Vary'] = API_VERSION_REQUEST_HEADER

        tomograph.stop(meth.__name__)

        return response