Skip to content

Commit

Permalink
feat: allow to set a signature host for tunnel usage with async client
Browse files Browse the repository at this point in the history
Signed-off-by: Bruno Murino <[email protected]>
  • Loading branch information
Bruno Murino committed Nov 30, 2024
1 parent 6c9d8f4 commit a6324e8
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 2 deletions.
32 changes: 30 additions & 2 deletions opensearchpy/helpers/asyncsigner.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
# GitHub history for details.

from typing import Any, Dict, Optional, Union
from urllib.parse import parse_qs, urlencode, urlparse


class AWSV4SignerAsyncAuth:
Expand All @@ -34,15 +35,17 @@ def __call__(
url: str,
query_string: Optional[str] = None,
body: Optional[Union[str, bytes]] = None,
headers: Optional[Dict[str, str]] = None,
) -> Dict[str, str]:
return self._sign_request(method, url, query_string, body)
return self._sign_request(method, url, query_string, body, headers)

def _sign_request(
self,
method: str,
url: str,
query_string: Optional[str],
body: Optional[Union[str, bytes]],
headers: Optional[Dict[str, str]],
) -> Dict[str, str]:
"""
This method helps in signing the request by injecting the required headers.
Expand All @@ -53,10 +56,12 @@ def _sign_request(
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest

signature_host = self._fetch_url(url, headers or dict()) # type: ignore

# create an AWS request object and sign it using SigV4Auth
aws_request = AWSRequest(
method=method,
url=url,
url=signature_host,
data=body,
)

Expand All @@ -80,3 +85,26 @@ def _sign_request(

# copy the headers from AWS request object into the prepared_request
return dict(aws_request.headers.items())

def _fetch_url(self, url, headers): # type: ignore
"""
This is a util method that helps in reconstructing the request url.
:param prepared_request: unsigned request
:return: reconstructed url
"""
url = urlparse(url)
path = url.path or "/"

# fetch the query string if present in the request
querystring = ""
if url.query:
querystring = "?" + urlencode(

Check warning on line 101 in opensearchpy/helpers/asyncsigner.py

View check run for this annotation

Codecov / codecov/patch

opensearchpy/helpers/asyncsigner.py#L101

Added line #L101 was not covered by tests
parse_qs(url.query, keep_blank_values=True), doseq=True
)

# fetch the host information from headers
headers = {key.lower(): value for key, value in headers.items()}
location = headers.get("host") or url.netloc

# construct the url and return
return url.scheme + "://" + location + path + querystring
1 change: 1 addition & 0 deletions test_opensearchpy/test_async/test_signer.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ def _sign_request(
url: str,
query_string: Optional[str] = None,
body: Optional[Union[str, bytes]] = None,
headers: Optional[Dict[str, str]] = None,
) -> Dict[str, str]:
nonlocal signed_url
signed_url = url
Expand Down

0 comments on commit a6324e8

Please sign in to comment.