From f1b2bc7b3e12b1fbd8c35abc1cdafa09fdc8d635 Mon Sep 17 00:00:00 2001 From: Parvathi Mallampalli Date: Wed, 30 Mar 2022 14:17:01 -0700 Subject: [PATCH] Fix issue of signature mismatch for resource path with UrlSegment --- .../AWSSigV4Signer.cs | 2 +- .../AWSSignerHelper.cs | 24 +++++++++---- .../AWSSigV4SignerTest.cs | 4 +-- .../AWSSignerHelperTest.cs | 34 +++++++++++++++---- 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSSigV4Signer.cs b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSSigV4Signer.cs index 9f7e3db..3937efa 100644 --- a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSSigV4Signer.cs +++ b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSSigV4Signer.cs @@ -59,7 +59,7 @@ namespace Amazon.SellingPartnerAPIAA canonicalizedRequest.AppendFormat("{0}\n", restRequest.Method); //CanonicalURI - canonicalizedRequest.AppendFormat("{0}\n", AwsSignerHelper.ExtractCanonicalURIParameters(restRequest.Resource)); + canonicalizedRequest.AppendFormat("{0}\n", AwsSignerHelper.ExtractCanonicalURIParameters(restRequest)); //CanonicalQueryString canonicalizedRequest.AppendFormat("{0}\n", AwsSignerHelper.ExtractCanonicalQueryString(restRequest)); diff --git a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSSignerHelper.cs b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSSignerHelper.cs index 5a2f7ef..6cd10d4 100644 --- a/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSSignerHelper.cs +++ b/clients/sellingpartner-api-aa-csharp/src/Amazon.SellingPartnerAPIAA/AWSSignerHelper.cs @@ -38,10 +38,11 @@ namespace Amazon.SellingPartnerAPIAA /// /// Returns URI encoded version of absolute path /// - /// Resource path(absolute path) from the request + /// RestRequest /// URI encoded version of absolute path - public virtual string ExtractCanonicalURIParameters(string resource) + public virtual string ExtractCanonicalURIParameters(IRestRequest request) { + string resource = request.Resource; string canonicalUri = string.Empty; if (string.IsNullOrEmpty(resource)) @@ -54,6 +55,17 @@ namespace Amazon.SellingPartnerAPIAA { canonicalUri = Slash; } + IDictionary pathParameters = request.Parameters + .Where(parameter => ParameterType.UrlSegment.Equals(parameter.Type)) + .ToDictionary(parameter => parameter.Name.Trim().ToString(), parameter => parameter.Value.ToString()); + + // Replace path parameter with actual value. + // Ex: /products/pricing/v0/items/{Asin}/offers -> /products/pricing/v0/items/AB12CD3E4Z/offers + foreach (string parameter in pathParameters.Keys) + { + resource = resource.Replace("{" + parameter + "}", pathParameters[parameter]); + } + //Split path at / into segments IEnumerable encodedSegments = resource.Split(new char[] { '/' }, StringSplitOptions.None); @@ -76,12 +88,12 @@ namespace Amazon.SellingPartnerAPIAA { IDictionary queryParameters = request.Parameters .Where(parameter => ParameterType.QueryString.Equals(parameter.Type)) - .ToDictionary(header => header.Name.Trim().ToString(), header => header.Value.ToString()); + .ToDictionary(parameter => parameter.Name.Trim().ToString(), parameter => parameter.Value.ToString()); - SortedDictionary sortedqueryParameters = new SortedDictionary(queryParameters); + SortedDictionary sortedQueryParameters = new SortedDictionary(queryParameters); StringBuilder canonicalQueryString = new StringBuilder(); - foreach (var key in sortedqueryParameters.Keys) + foreach (var key in sortedQueryParameters.Keys) { if (canonicalQueryString.Length > 0) { @@ -89,7 +101,7 @@ namespace Amazon.SellingPartnerAPIAA } canonicalQueryString.AppendFormat("{0}={1}", Utils.UrlEncode(key), - Utils.UrlEncode(sortedqueryParameters[key])); + Utils.UrlEncode(sortedQueryParameters[key])); } return canonicalQueryString.ToString(); diff --git a/clients/sellingpartner-api-aa-csharp/test/Amazon.SellingPartnerAPIAATests/AWSSigV4SignerTest.cs b/clients/sellingpartner-api-aa-csharp/test/Amazon.SellingPartnerAPIAATests/AWSSigV4SignerTest.cs index d0487a0..20d6a3f 100644 --- a/clients/sellingpartner-api-aa-csharp/test/Amazon.SellingPartnerAPIAATests/AWSSigV4SignerTest.cs +++ b/clients/sellingpartner-api-aa-csharp/test/Amazon.SellingPartnerAPIAATests/AWSSigV4SignerTest.cs @@ -43,7 +43,7 @@ namespace Amazon.SellingPartnerAPIAATests string expectedStringToSign = "testStringToSign"; mockAWSSignerHelper.Setup(signerHelper => signerHelper.InitializeHeaders(request, TestHost)) .Returns(signingDate); - mockAWSSignerHelper.Setup(signerHelper => signerHelper.ExtractCanonicalURIParameters(request.Resource)) + mockAWSSignerHelper.Setup(signerHelper => signerHelper.ExtractCanonicalURIParameters(request)) .Returns("testURIParameters"); mockAWSSignerHelper.Setup(signerHelper => signerHelper.ExtractCanonicalQueryString(request)) .Returns("testCanonicalQueryString"); @@ -63,7 +63,7 @@ namespace Amazon.SellingPartnerAPIAATests IRestRequest actualRestRequest = sigV4SignerUnderTest.Sign(request, TestHost); mockAWSSignerHelper.Verify(signerHelper => signerHelper.InitializeHeaders(request, TestHost)); - mockAWSSignerHelper.Verify(signerHelper => signerHelper.ExtractCanonicalURIParameters(request.Resource)); + mockAWSSignerHelper.Verify(signerHelper => signerHelper.ExtractCanonicalURIParameters(request)); mockAWSSignerHelper.Verify(signerHelper => signerHelper.ExtractCanonicalQueryString(request)); mockAWSSignerHelper.Verify(signerHelper => signerHelper.ExtractCanonicalHeaders(request)); mockAWSSignerHelper.Verify(signerHelper => signerHelper.ExtractSignedHeaders(request)); diff --git a/clients/sellingpartner-api-aa-csharp/test/Amazon.SellingPartnerAPIAATests/AWSSignerHelperTest.cs b/clients/sellingpartner-api-aa-csharp/test/Amazon.SellingPartnerAPIAATests/AWSSignerHelperTest.cs index 4a10c8c..665eb3d 100644 --- a/clients/sellingpartner-api-aa-csharp/test/Amazon.SellingPartnerAPIAATests/AWSSignerHelperTest.cs +++ b/clients/sellingpartner-api-aa-csharp/test/Amazon.SellingPartnerAPIAATests/AWSSignerHelperTest.cs @@ -34,35 +34,57 @@ namespace Amazon.SellingPartnerAPIAATests public void TestExtractCanonicalURIParameters() { IRestRequest request = new RestRequest(TestResourcePath, Method.GET); - string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(request.Resource); - Assert.Equal("/iam/user", result); + string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(request); + Assert.Equal(Slash + TestResourcePath, result); + } + + [Fact] + public void TestExtractCanonicalURIParameters_UrlSegments() + { + IRestRequest request = new RestRequest("products/pricing/v0/items/{Asin}/offers/{SellerSKU}", Method.GET); + request.AddUrlSegment("Asin", "AB12CD3E4Z"); + request.AddUrlSegment("SellerSKU", "1234567890"); + string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(request); + Assert.Equal("/products/pricing/v0/items/AB12CD3E4Z/offers/1234567890", result); + } + + [Fact] + public void TestExtractCanonicalURIParameters_IncorrectUrlSegment() + { + IRestRequest request = new RestRequest("products/pricing/v0/items/{Asin}/offers", Method.GET); + request.AddUrlSegment("asin", "AB12CD3E4Z"); + string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(request); + Assert.Equal("/products/pricing/v0/items/%257BAsin%257D/offers", result); } [Fact] public void TestExtractCanonicalURIParameters_ResourcePathWithSpace() { - string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters("iam/ user"); + IRestRequest request = new RestRequest("iam/ user", Method.GET); + string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(request); Assert.Equal("/iam/%2520user", result); } [Fact] public void TestExtractCanonicalURIParameters_EmptyResourcePath() { - string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(string.Empty); + IRestRequest request = new RestRequest(string.Empty, Method.GET); + string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(request); Assert.Equal(Slash, result); } [Fact] public void TestExtractCanonicalURIParameters_NullResourcePath() { - string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(null); + string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(new RestRequest()); Assert.Equal(Slash, result); } [Fact] public void TestExtractCanonicalURIParameters_SlashPath() { - string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(Slash); + IRestRequest request = new RestRequest(Slash, Method.GET); + string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(request); Assert.Equal(Slash, result); }