Repository: opensearch-project/opensearch-py
Pull request #279 (2023-01-24 00:46:15)

Fixed Sigv4 Signing for Managed Service and Async OpenSearch
Signed-off-by: Theo Truong <theotr@amazon.com>

### Issues Resolved
closes https://github.com/opensearch-project/opensearch-py/issues/278
closes https://github.com/opensearch-project/opensearch-py/issues/272

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check [here](https://github.com/opensearch-project/OpenSearch/blob/main/CONTRIBUTING.md#developer-certificate-of-origin).


dblock: Needs tests please? 
VachaShah: Thank you @nhtruong! Can you fix the lint that is causing the CI to fail?

Patch:
diff --git a/.github/workflows/unified-release.yml b/.github/workflows/unified-release.yml
index 3dd9f2d2..4ece02a6 100644
--- a/.github/workflows/unified-release.yml
+++ b/.github/workflows/unified-release.yml
@@ -9,7 +9,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        stack_version: ['2.1.0']
+        stack_version: ['2.1.1']
 
     steps:
       - name: Checkout
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5e3a2fd3..157f89aa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,15 +1,23 @@
 # CHANGELOG
 Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
 
-## [Unreleased]
+## [2.1.1]
 ### Added
 ### Changed
 ### Deprecated
-
 ### Removed
-
 ### Fixed
+- Fixed SigV4 Signing for Managed Service ([#279](https://github.com/opensearch-project/opensearch-py/pull/279))
+- Fixed SigV4 Signing for Async Requests with QueryStrings ([#272](https://github.com/opensearch-project/opensearch-py/pull/279))
+### Security
 
+## [2.1.0]
+### Added
+- Added Support for AOSS ([#268](https://github.com/opensearch-project/opensearch-py/pull/268))
+### Changed
+### Deprecated
+### Removed
+### Fixed
 ### Security
 
 ## [2.0.1]
diff --git a/opensearchpy/_version.py b/opensearchpy/_version.py
index 0c246699..7ed5f16a 100644
--- a/opensearchpy/_version.py
+++ b/opensearchpy/_version.py
@@ -24,4 +24,4 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-__versionstr__ = "2.1.0"
+__versionstr__ = "2.1.1"
diff --git a/opensearchpy/helpers/asyncsigner.py b/opensearchpy/helpers/asyncsigner.py
index b10e3188..08a81748 100644
--- a/opensearchpy/helpers/asyncsigner.py
+++ b/opensearchpy/helpers/asyncsigner.py
@@ -46,11 +46,13 @@ class AWSV4SignerAsyncAuth:
         # create an AWS request object and sign it using SigV4Auth
         aws_request = AWSRequest(
             method=method,
-            url="".join([url, query_string]),
+            url=url,
+            data=body,
         )
 
         sig_v4_auth = SigV4Auth(self.credentials, self.service, self.region)
         sig_v4_auth.add_auth(aws_request)
+        aws_request.headers["X-Amz-Content-SHA256"] = sig_v4_auth.payload(aws_request)
 
         # copy the headers from AWS request object into the prepared_request
         return dict(aws_request.headers.items())
diff --git a/opensearchpy/helpers/signer.py b/opensearchpy/helpers/signer.py
index 3731d7dd..9c330b7b 100644
--- a/opensearchpy/helpers/signer.py
+++ b/opensearchpy/helpers/signer.py
@@ -80,6 +80,7 @@ class AWSV4SignerAuth(requests.auth.AuthBase):
         aws_request = AWSRequest(
             method=prepared_request.method.upper(),
             url=url,
+            data=prepared_request.body,
         )
 
         sig_v4_auth = SigV4Auth(self.credentials, self.service, self.region)
@@ -87,5 +88,8 @@ class AWSV4SignerAuth(requests.auth.AuthBase):
 
         # copy the headers from AWS request object into the prepared_request
         prepared_request.headers.update(dict(aws_request.headers.items()))
+        prepared_request.headers["X-Amz-Content-SHA256"] = sig_v4_auth.payload(
+            aws_request
+        )
 
         return prepared_request


Test patch:
diff --git a/test_opensearchpy/test_async/test_asyncsigner.py b/test_opensearchpy/test_async/test_asyncsigner.py
index c5b62193..3be40142 100644
--- a/test_opensearchpy/test_async/test_asyncsigner.py
+++ b/test_opensearchpy/test_async/test_asyncsigner.py
@@ -78,3 +78,4 @@ class TestAsyncSigner(TestCase):
         self.assertIn("Authorization", headers)
         self.assertIn("X-Amz-Date", headers)
         self.assertIn("X-Amz-Security-Token", headers)
+        self.assertIn("X-Amz-Content-SHA256", headers)
diff --git a/test_opensearchpy/test_connection.py b/test_opensearchpy/test_connection.py
index 1f890d7c..93b6913b 100644
--- a/test_opensearchpy/test_connection.py
+++ b/test_opensearchpy/test_connection.py
@@ -332,6 +332,7 @@ class TestUrllib3Connection(TestCase):
         self.assertIn("Authorization", prepared_request.headers)
         self.assertIn("X-Amz-Date", prepared_request.headers)
         self.assertIn("X-Amz-Security-Token", prepared_request.headers)
+        self.assertIn("X-Amz-Content-SHA256", prepared_request.headers)
 
     @pytest.mark.skipif(
         sys.version_info < (3, 6), reason="AWSV4SignerAuth requires python3.6+"