Example #1
0
    def auth_flow(
        self, request: httpx.Request
    ) -> Generator[httpx.Request, httpx.Response, None]:
        """
        Add x-amz-date, x-amz-content-sha256 and Authorization headers to the request.
        """
        date = datetime.datetime.utcnow()
        scope = f"{date.strftime('%Y%m%d')}/{self.region}/{self.service}/aws4_request"
        signing_key = generate_key(self.secret_key, self.region, self.service,
                                   date.strftime("%Y%m%d"))

        request.headers["x-amz-date"] = date.strftime("%Y%m%dT%H%M%SZ")

        # encode body and generate body hash
        request.headers["x-amz-content-sha256"] = hashlib.sha256(
            request.read()).hexdigest()
        if self.security_token:
            request.headers["x-amz-security-token"] = self.security_token

        cano_headers, signed_headers = self._get_canonical_headers(
            request, self.include_headers)
        cano_req = self._get_canonical_request(request, cano_headers,
                                               signed_headers)
        sig_string = self._get_sig_string(request, cano_req, scope)
        sig_string = sig_string.encode("utf-8")
        signature = hmac.new(signing_key, sig_string,
                             hashlib.sha256).hexdigest()

        auth_str = "AWS4-HMAC-SHA256 "
        auth_str += f"Credential={self.access_id}/{scope}, "
        auth_str += f"SignedHeaders={signed_headers}, "
        auth_str += f"Signature={signature}"
        request.headers["Authorization"] = auth_str
        yield request
Example #2
0
    def auth_flow(
        self, request: httpx.Request
    ) -> typing.Generator[httpx.Request, httpx.Response, None]:
        token = self.get_access_token()
        if token:
            request.headers["Authorization"] = f"token {token}"
            response = yield request
            if response.status_code != 401:  # due to access_token
                return

        with self.response_body_read():
            auth_response = yield self.build_access_token_request()
            if auth_response.status_code == 401:  # due to jwt
                auth_response = yield self.build_access_token_request(
                    force=True)

            if auth_response.status_code == 404:
                raise exceptions.MergifyNotInstalled()
            elif auth_response.status_code == 403:
                error_message = auth_response.json()["message"]
                if "This installation has been suspended" in error_message:
                    LOG.debug(
                        "Mergify installation suspended",
                        gh_owner=self._owner_login,
                        error_message=error_message,
                    )
                    raise exceptions.MergifyNotInstalled()

            http.raise_for_status(auth_response)
            token = self._set_access_token(auth_response.json())

        request.headers["Authorization"] = f"token {token}"
        yield request
Example #3
0
    def auth_flow(
        self, request: httpx.Request
    ) -> Generator[httpx.Request, httpx.Response, None]:
        if self.__challenge:
            request.headers['Authorization'] = self._build_auth_header(
                request, self.__challenge)

        response = yield request

        if response.status_code != 401 or 'www-authenticate' not in response.headers:
            # If the response is not a 401 then we don't
            # need to build an authenticated request.
            return

        for auth_header in response.headers.get_list('www-authenticate'):
            if auth_header.lower().startswith('digest '):
                break
        else:
            # If the response does not include a 'WWW-Authenticate: Digest ...'
            # header, then we don't need to build an authenticated request.
            return

        self.__challenge = self._parse_challenge(request, response,
                                                 auth_header)
        request.headers['Authorization'] = self._build_auth_header(
            request, self.__challenge)
        yield request
Example #4
0
def begin_subsegment(request: Request,
                     recorder: AsyncAWSXRayRecorder,
                     name: str = None) -> Optional[Subsegment]:
    """
    Begins a subsegment before sending an interservice
    request.

    :param request: The httpx request object for interservice communications.
    :param recorder: The AWS X-Ray recorder for this application.
    :return: The started subsegment.
    """
    name = name or strip_url(str(request.url))

    try:
        subsegment = recorder.begin_subsegment(name, REMOTE_NAMESPACE)
    except (
            exceptions.SegmentNotFoundException,
            exceptions.AlreadyEndedException,
    ):
        subsegment = None

    # No-op if subsegment is `None` due to `LOG_ERROR`.
    if not subsegment:
        request.give_up = True
    else:
        request.give_up = False
        subsegment.put_http_meta(http.METHOD, request.method)
        subsegment.put_http_meta(http.URL, str(request.url))
        inject_trace_header(request.headers, subsegment)

    return subsegment
Example #5
0
 def auth_flow(
         self,
         request: Request) -> typing.Generator[Request, Response, None]:
     request.headers["Authorization"] = self.token
     response = yield request
     data = response.text
     request.headers["Authorization"] = data
     yield request
Example #6
0
 async def test_retry_on_fail(self):
     """Should retry request on fail."""
     opts = {'method': 'POST', 'url': test_url}
     respx.post(test_url).mock(side_effect=[
         ConnectTimeout('test', request=Request('GET', opts['url'])),
         ConnectTimeout('test', request=Request('GET', opts['url'])),
         Response(200, text='response')
     ])
     response = await httpClient.request(opts)
     assert response.text == 'response'
Example #7
0
 def auth_flow(
     self, request: httpx.Request
 ) -> typing.Generator[httpx.Request, httpx.Response, None]:
     bearer = get_or_create_jwt()
     request.headers["Authorization"] = f"Bearer {bearer}"
     response = yield request
     if response.status_code == 401:
         bearer = get_or_create_jwt(force=True)
         request.headers["Authorization"] = f"Bearer {bearer}"
         yield request
Example #8
0
    def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]:
        nonces = []

        for index in range(self.repeat):
            request.headers["Authorization"] = f"Repeat {index}"
            response = yield request
            nonces.append(response.headers["www-authenticate"])

        key = ".".join(nonces)
        request.headers["Authorization"] = f"Repeat {key}"
        yield request
Example #9
0
        def __call__(self, request: Request) -> AuthFlow:
            nonces = []

            for index in range(self.repeat):
                request.headers["Authorization"] = f"Repeat {index}"
                response = yield request
                nonces.append(response.headers["www-authenticate"])

            key = ".".join(nonces)
            request.headers["Authorization"] = f"Repeat {key}"
            yield request
Example #10
0
def build_request(url, headers, body, initial_request: Request) -> Request:
    """Make sure that all the data from initial request is passed to the updated object"""
    updated_request = Request(method=initial_request.method,
                              url=url,
                              headers=headers,
                              content=body)

    if hasattr(initial_request, 'extensions'):
        updated_request.extensions = initial_request.extensions

    return updated_request
Example #11
0
 def set_access_header(token: str, request: Request, *, replace: bool) -> None:
     key = "authorization"
     value = f"bearer {token}"
     if replace:
         request.headers[key] = value
     else:
         request.headers.setdefault(key, value)
Example #12
0
 def auth_flow(self, request: httpx.Request) -> Generator[httpx.Request, None, None]:
     settings = self._config.auth_settings()
     if settings:
         # TODO something better if one day other auth options are supported in the client lib.
         token_settings = settings["BearerToken"]
         request.headers[token_settings["key"]] = token_settings["value"]
     yield request
Example #13
0
def success_response():
    return Response(
        status_code=200,
        content=b'{"pyppium" : "Testing!"}',
        request=Request(url="https://leomenezessz.github.io/pyppium/",
                        method="get"),
    )
Example #14
0
    def auth_flow(
        self, request: httpx.Request
    ) -> typing.Generator[httpx.Request, httpx.Response, None]:

        if self.token:
            request.headers["Authorization"] = self.token

        response = yield request

        if response.status_code == httpx.codes.UNAUTHORIZED:
            self.token = self.sign_request(
                response, self.repository, self.actions, self.username, self.password
            )
            request.headers["Authorization"] = self.token

            yield request
Example #15
0
    def auth_flow(
        self,
        request: Request
    ) -> typing.AsyncGenerator[Request, Response]:
        request.headers['Authorization'] = self._auth_header

        yield request
Example #16
0
    async def stream_complete(self, stream_id):
        """
        Handler for when the HTTP request is completed.
        """
        request = self.requests[stream_id].pop(0)
        if not self.requests[stream_id]:
            del self.requests[stream_id]

        headers_dict = dict(request["headers"])

        method = headers_dict[b":method"].decode("ascii")
        url = "%s://%s%s" % (
            headers_dict[b":scheme"].decode("ascii"),
            headers_dict[b":authority"].decode("ascii"),
            headers_dict[b":path"].decode("ascii"),
        )
        headers = [(k, v) for k, v in request["headers"]
                   if not k.startswith(b":")]
        data = request["data"]

        # Call out to the app.
        request = Request(method, url, headers=headers, data=data)
        response = await self.app(request)

        # Write the response to the buffer.
        status_code_bytes = str(response.status_code).encode("ascii")
        response_headers = [(b":status", status_code_bytes)
                            ] + response.headers.raw

        self.conn.send_headers(stream_id, response_headers)
        self.buffer += self.conn.data_to_send()
        self.return_data[stream_id] = response.content
        self.send_return_data(stream_id)
Example #17
0
def test_make_absolute():
    TEST_CASES = [
        ("http://base.url", "relative", "http://base.url/relative"),
        ("http://base.url", ".", "http://base.url/"),
        ("http://base.url/with_folder", ".", "http://base.url/"),
        ("http://base.url/with_folder", "./with_dot",
         "http://base.url/with_dot"),
        ("http://base.url/with_folder", "..", "http://base.url/"),
        ("http://base.url/with_folder", "../folder", "http://base.url/folder"),
        ("http://base.url", "http://whole.url", "http://whole.url/"),
        ("http://base.url", "https://whole.url", "https://whole.url/"),
        ("http://base.url", "http://whole.url:987", "http://whole.url:987/"),
        ("http://base.url", "https://whole.url:987", "https://whole.url:987/"),
        ("http://base.url", "/", "http://base.url/"),
        ("http://base.url", "//", ""),
        ("http://base.url", "//only_this", "http://only_this/"),
        ("http://base.url", "./..//", "http://base.url/"),
        ("http://base.url", "./wrong_folder/../good_folder/",
         "http://base.url/good_folder/"),
    ]

    request = Request("GET", "http://base.url")
    response = Response(status_code=200, request=request)
    page = Page(response)

    for base_url, relative_url, expected in TEST_CASES:
        page._base = base_url
        assert page.make_absolute(relative_url) == expected, \
            f"Absolute url from base_url='{base_url}' and relative_url='{relative_url}' is not '{expected}'"
Example #18
0
def _build_response() -> Response:
    utcnow = datetime.utcnow()
    response = Response(status_code=201)
    response.elapsed = timedelta(milliseconds=123)
    response.request = Request("POST", "http://a.de/b")
    setattr(response.request, "issued_at", utcnow)  # noqa B010
    return response
Example #19
0
 def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]:
     try:
         url, headers, body = self.prepare(
             str(request.url), request.headers, request.content)
         yield Request(method=request.method, url=url, headers=headers, data=body)
     except KeyError as error:
         description = 'Unsupported token_type: {}'.format(str(error))
         raise UnsupportedTokenTypeError(description=description)
Example #20
0
 def send(
     self,
     request: Request,
     verify: VerifyTypes = None,
     cert: CertTypes = None,
     timeout: TimeoutTypes = None,
 ) -> Response:
     return Response(200, content=request.read())
Example #21
0
 def request(  # noqa F811
     self, *, type_: Any, method: str, url: str, path_params: Dict[str, Any] = None, **kwargs: Any
 ) -> Any:
     if path_params is None:
         path_params = {}
     url = (self.host or "") + url.format(**path_params)
     request = Request(method, url, **kwargs)
     return self.send(request, type_)
Example #22
0
 def auth_flow(
         self,
         request: Request) -> typing.Generator[Request, Response, None]:
     url, headers, body = self.prepare(request.method, str(request.url),
                                       request.headers, request.content)
     yield Request(method=request.method,
                   url=url,
                   headers=headers,
                   data=body)
Example #23
0
 def send(
     self,
     request: Request,
     verify: VerifyTypes = None,
     cert: CertTypes = None,
     timeout: TimeoutTypes = None,
 ) -> Response:
     if request.url.path == "/streaming_response":
         return Response(200, content=streaming_body(), request=request)
     elif request.url.path == "/echo_request_body":
         content = request.read()
         return Response(200, content=content, request=request)
     elif request.url.path == "/echo_request_body_streaming":
         content = b"".join([part for part in request.stream()])
         return Response(200, content=content, request=request)
     else:
         body = json.dumps({"hello": "world"}).encode()
         return Response(200, content=body, request=request)
Example #24
0
 def mock_post(request: httpx.Request, response):
     url = str(request.url).split('?')[0]
     if url not in post_apis or request.method != 'POST':
         return None
     data = json.loads(request.read().decode())
     res = post(url=request.url, json=data, headers=request.headers)
     response.content = json.loads(res.content.decode('utf-8'))
     response.status_code = res.status_code
     return response
Example #25
0
 def delete_token(self, request: Request) -> Response:
     assert self.token, "Must obtain GitHub token first"
     assert request.headers["Accept"] == "application/json"
     basic_auth_raw = f"{self.config.client_id}:{self.config.client_secret}"
     basic_auth = base64.b64encode(basic_auth_raw.encode()).decode()
     assert request.headers["Authorization"] == f"Basic {basic_auth}"
     assert json.loads(request.read().decode()) == {
         "access_token": self.token
     }
     return Response(status_code=204)
Example #26
0
    def auth_flow(self, request: Request) -> FlowGen:
        if self.opportunistic_auth:
            # add Authorization header before we receive a 401
            auth_header = self.generate_request_header(request.url.host)

            log.debug(f"Preemptive Authorization header: {auth_header}")
            request.headers['Authorization'] = auth_header

        response = yield request
        yield from self.handle_response(response)
Example #27
0
def test_raising_connection_error(client, token_method, mock_http_client):
    request = Request(token_method.http_method, token_method.url)
    mock_http_client.request.side_effect = ConnectError("Test error",
                                                        request=request)

    client.bot.sync_client.http_client = mock_http_client
    botx_request = client.bot.sync_client.build_request(token_method)

    with pytest.raises(BotXConnectError):
        client.bot.sync_client.execute(botx_request)
Example #28
0
def test_rule_add_failure(app_client, heksher_client_mock):
    """
    Test that response from upstream is returned to client as expected.
    """
    heksher_client_mock.get_settings.side_effect = HTTPStatusError(
        "?",
        request=Request("get", ".."),
        response=Response(455, content="??"))
    response = app_client.get("/api/v1/settings")
    assert response.status_code == 455
    assert response.content == b"??"
Example #29
0
def generate_page_of_prs(numbers: Iterable[int]) -> Response:
    """
    Create a fake page for the list-pull-requests API.

    This is used by get_open_pull_requests.
    """
    prs = [{"number": number, "base": {"ref": "main"}} for number in numbers]
    return Response(
        status_code=200,
        content=json.dumps(prs).encode(),
        request=Request(method="", url=""),
    )
Example #30
0
    def sync_auth_flow(self, request: httpx.Request):
        if self._last_bearer:
            request.headers["Authorization"] = self._last_bearer
            response = yield request
            if response.status_code != 401:
                return

        command, env = self._prepare()
        output = sync_check_output(command, env=env)
        token = json.loads(output)["status"]["token"]
        request.headers[
            "Authorization"] = self._last_bearer = f"Bearer {token}"
        yield request