Ejemplo n.º 1
0
 def strip_endpoint(self, location):
     if location is None:
         message = _("Location not returned with 302")
         raise exc.InvalidEndpoint(message=message)
     elif location.lower().startswith(self.endpoint.lower()):
         return location[len(self.endpoint):]
     else:
         message = _("Prohibited endpoint redirect %s") % location
         raise exc.InvalidEndpoint(message=message)
Ejemplo n.º 2
0
 def strip_endpoint(self, location):
     if location is None:
         message = _("Location not returned with 302")
         raise exc.InvalidEndpoint(message=message)
     if (self.endpoint_override is not None and location.lower().startswith(
             self.endpoint_override.lower())):
         return location[len(self.endpoint_override):]
     else:
         return location
Ejemplo n.º 3
0
    def _http_request(self, url, method, **kwargs):
        kwargs.setdefault('user_agent', USER_AGENT)
        kwargs.setdefault('auth', self.auth)

        endpoint_filter = kwargs.setdefault('endpoint_filter', {})
        endpoint_filter.setdefault('interface', self.interface)
        endpoint_filter.setdefault('service_type', self.service_type)
        endpoint_filter.setdefault('region_name', self.region_name)

        # TODO(gyee): what are these headers for?
        if self.auth_url:
            kwargs['headers'].setdefault('X-Auth-Url', self.auth_url)
        if self.region_name:
            kwargs['headers'].setdefault('X-Region-Name', self.region_name)
        if self.include_pass and 'X-Auth-Key' not in kwargs['headers']:
            kwargs['headers'].update(self.credentials_headers())

        # Allow caller to specify not to follow redirects, in which case we
        # just return the redirect response.  Useful for using stacks:lookup.
        follow_redirects = kwargs.pop('follow_redirects', True)

        # If the endpoint is passed in, make sure keystone uses it
        # instead of looking up the endpoint in the auth plugin.
        if self.endpoint is not None:
            kwargs['endpoint_override'] = self.endpoint

        resp = self.session.request(url,
                                    method,
                                    redirect=follow_redirects,
                                    raise_exc=False,
                                    **kwargs)

        if 400 <= resp.status_code < 600:
            raise exc.from_response(resp)
        elif resp.status_code in (301, 302, 305):
            # Redirected. Reissue the request to the new location,
            # unless caller specified follow_redirects=False
            if follow_redirects:
                location = resp.headers.get('location')
                if location is None:
                    message = _("Location not returned with 302")
                    raise exc.InvalidEndpoint(message=message)
                elif (self.endpoint is not None
                      and location.lower().startswith(self.endpoint.lower())):
                    location = location[len(self.endpoint):]
                resp = self._http_request(location, method, **kwargs)
        elif resp.status_code == 300:
            raise exc.from_response(resp)

        return resp
Ejemplo n.º 4
0
 def _resolve_stack_id(self, stack_id):
     # if the id already has a slash in it,
     # then it is already {stack_name}/{stack_id}
     if stack_id.find('/') > 0:
         return stack_id
     # We want to capture the redirect, not actually get the stack,
     # since all we want is the stacks:lookup response to get the
     # fully qualified ID, and not all users are allowed to do the
     # redirected stacks:show, so pass redirect=False
     resp = self.client.get('/stacks/%s' % stack_id, redirect=False)
     location = resp.headers.get('location')
     if not location:
         message = _("Location not returned with redirect")
         raise exc.InvalidEndpoint(message=message)
     return location.split('/stacks/', 1)[1]
Ejemplo n.º 5
0
    def _http_request(self, url, method, **kwargs):
        """Send an http request with the specified characteristics.

        Wrapper around requests.request to handle tasks such as
        setting headers and error handling.
        """
        # Copy the kwargs so we can reuse the original in case of redirects
        kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {}))
        kwargs['headers'].setdefault('User-Agent', USER_AGENT)
        if self.auth_token:
            kwargs['headers'].setdefault('X-Auth-Token', self.auth_token)
        else:
            kwargs['headers'].update(self.credentials_headers())
        if self.auth_url:
            kwargs['headers'].setdefault('X-Auth-Url', self.auth_url)
        if self.region_name:
            kwargs['headers'].setdefault('X-Region-Name', self.region_name)
        if self.include_pass and 'X-Auth-Key' not in kwargs['headers']:
            kwargs['headers'].update(self.credentials_headers())
        if osprofiler_web:
            kwargs['headers'].update(osprofiler_web.get_trace_id_headers())

        self.log_curl_request(method, url, kwargs)

        if self.cert_file and self.key_file:
            kwargs['cert'] = (self.cert_file, self.key_file)

        if self.verify_cert is not None:
            kwargs['verify'] = self.verify_cert

        if self.timeout is not None:
            kwargs['timeout'] = float(self.timeout)

        # Allow caller to specify not to follow redirects, in which case we
        # just return the redirect response.  Useful for using stacks:lookup.
        redirect = kwargs.pop('redirect', True)

        # Since requests does not follow the RFC when doing redirection to sent
        # back the same method on a redirect we are simply bypassing it.  For
        # example if we do a DELETE/POST/PUT on a URL and we get a 302 RFC says
        # that we should follow that URL with the same method as before,
        # requests doesn't follow that and send a GET instead for the method.
        # Hopefully this could be fixed as they say in a comment in a future
        # point version i.e.: 3.x
        # See issue: https://github.com/kennethreitz/requests/issues/1704
        allow_redirects = False

        try:
            resp = requests.request(method,
                                    self.endpoint_url + url,
                                    allow_redirects=allow_redirects,
                                    **kwargs)
        except socket.gaierror as e:
            message = (_("Error finding address for %(url)s: %(e)s") % {
                'url': self.endpoint_url + url,
                'e': e
            })
            raise exc.InvalidEndpoint(message=message)
        except (socket.error, socket.timeout) as e:
            endpoint = self.endpoint
            message = (_("Error communicating with %(endpoint)s %(e)s") % {
                'endpoint': endpoint,
                'e': e
            })
            raise exc.CommunicationError(message=message)

        self.log_http_response(resp)

        if not ('X-Auth-Key' in kwargs['headers']) and (
                resp.status_code == 401 or
            (resp.status_code == 500 and "(HTTP 401)" in resp.content)):
            raise exc.HTTPUnauthorized(
                _("Authentication failed: %s") % resp.content)
        elif 400 <= resp.status_code < 600:
            raise exc.from_response(resp)
        elif resp.status_code in (301, 302, 305):
            # Redirected. Reissue the request to the new location,
            # unless caller specified redirect=False
            if redirect:
                location = resp.headers.get('location')
                path = self.strip_endpoint(location)
                resp = self._http_request(path, method, **kwargs)
        elif resp.status_code == 300:
            raise exc.from_response(resp)

        return resp