CSharp Auth and auth lib changes

This commit is contained in:
Meena Peri 2023-10-01 18:16:11 -05:00
parent fcf32fdff6
commit f48b0a3564
17 changed files with 249 additions and 864 deletions

View File

@ -38,36 +38,9 @@ restRequest = new LWAAuthorizationSigner(lwaAuthorizationCredentials).Sign(restR
``` ```
Note the IRestRequest reference is treated as **mutable** when signed. Note the IRestRequest reference is treated as **mutable** when signed.
## AWSSigV4Signer
Signs a request with [AWS Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html)
using the provided AWS developer account credentials.
*Example*
```
using RestSharp;
using Amazon.SellingPartnerAPIAA;
string resource = "/my/api/path";
RestClient restClient = new RestClient("https://...");
IRestRequest restRequest = new RestRequest(resource, Method.GET);
AWSAuthenticationCredentials awsAuthenticationCredentials = new AWSAuthenticationCredentials
{
AccessKeyId = "..."
SecretKey = "..."
Region = "..."
};
restRequest = new AWSSigV4Signer(awsAuthenticationCredentials)
.Sign(restRequest, restClient.BaseUrl.Host);
```
Note the IRestRequest reference is treated as **mutable** when signed.
## RateLimitConfiguration ## RateLimitConfiguration
Interface to set and get rateLimit configurations that are used with RateLimiter. RateLimiter is used on client side to restrict the rate at which requests are made. RateLimiter Configuration takes Permit, rate which requests are made and TimeOut Interface to set and get rateLimit configurations that are used with RateLimiter. RateLimiter is used on client side to restrict the rate at which requests are made. RateLimiter Configuration takes Permit, rate which requests are made and TimeOut
*Example* *Example*
``` ```
RateLimitConfiguration rateLimitConfig = new RateLimitConfigurationOnRequests RateLimitConfiguration rateLimitConfig = new RateLimitConfigurationOnRequests
@ -78,6 +51,23 @@ RateLimitConfiguration rateLimitConfig = new RateLimitConfigurationOnRequests
``` ```
## Exception
This package returns a custom LWAException when there is an error returned during LWA authorization. LWAException provides additional details like errorCode and errorDescription to help fix the issue.
*Example*
```
catch (LWAException e)
{
Console.WriteLine("LWA Exception when calling Selling partner API");
Console.WriteLine(e.getErrorCode());
Console.WriteLine(e.getErrorMessage());
Console.WriteLine(e.Message);
}
```
## Version
Selling Partner API Authentication/Authorization Library version 2.0.
## Resources ## Resources
This package features Mustache templates designed for use with [swagger codegen](https://swagger.io/tools/swagger-codegen/). This package features Mustache templates designed for use with [swagger codegen](https://swagger.io/tools/swagger-codegen/).
When you build Selling Partner API Swagger models with these templates, they help generate a rich SDK with functionality to invoke Selling Partner APIs built in. The templates are located in *resources/swagger-codegen*. When you build Selling Partner API Swagger models with these templates, they help generate a rich SDK with functionality to invoke Selling Partner APIs built in. The templates are located in *resources/swagger-codegen*.

View File

@ -1,23 +1,26 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.SellingPartnerAPIAA", "src\Amazon.SellingPartnerAPIAA\Amazon.SellingPartnerAPIAA.csproj", "{64339397-3AAB-49D3-8B50-7A467B16D545}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.SellingPartnerAPIAA", "src\Amazon.SellingPartnerAPIAA\Amazon.SellingPartnerAPIAA.csproj", "{64339397-3AAB-49D3-8B50-7A467B16D545}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.SellingPartnerAPIAATests", "test\Amazon.SellingPartnerAPIAATests\Amazon.SellingPartnerAPIAATests.csproj", "{12B130EB-1087-4F88-BDFA-3088868C0A46}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.SellingPartnerAPIAATests", "test\Amazon.SellingPartnerAPIAATests\Amazon.SellingPartnerAPIAATests.csproj", "{12B130EB-1087-4F88-BDFA-3088868C0A46}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{64339397-3AAB-49D3-8B50-7A467B16D545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {64339397-3AAB-49D3-8B50-7A467B16D545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{64339397-3AAB-49D3-8B50-7A467B16D545}.Debug|Any CPU.Build.0 = Debug|Any CPU {64339397-3AAB-49D3-8B50-7A467B16D545}.Debug|Any CPU.Build.0 = Debug|Any CPU
{64339397-3AAB-49D3-8B50-7A467B16D545}.Release|Any CPU.ActiveCfg = Release|Any CPU {64339397-3AAB-49D3-8B50-7A467B16D545}.Release|Any CPU.ActiveCfg = Release|Any CPU
{64339397-3AAB-49D3-8B50-7A467B16D545}.Release|Any CPU.Build.0 = Release|Any CPU {64339397-3AAB-49D3-8B50-7A467B16D545}.Release|Any CPU.Build.0 = Release|Any CPU
{12B130EB-1087-4F88-BDFA-3088868C0A46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {12B130EB-1087-4F88-BDFA-3088868C0A46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{12B130EB-1087-4F88-BDFA-3088868C0A46}.Debug|Any CPU.Build.0 = Debug|Any CPU {12B130EB-1087-4F88-BDFA-3088868C0A46}.Debug|Any CPU.Build.0 = Debug|Any CPU
{12B130EB-1087-4F88-BDFA-3088868C0A46}.Release|Any CPU.ActiveCfg = Release|Any CPU {12B130EB-1087-4F88-BDFA-3088868C0A46}.Release|Any CPU.ActiveCfg = Release|Any CPU
{12B130EB-1087-4F88-BDFA-3088868C0A46}.Release|Any CPU.Build.0 = Release|Any CPU {12B130EB-1087-4F88-BDFA-3088868C0A46}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal GlobalSection(MonoDevelopProperties) = preSolution
version = 2.0
EndGlobalSection
EndGlobal

View File

@ -1,20 +0,0 @@
namespace Amazon.SellingPartnerAPIAA
{
public class AWSAuthenticationCredentials
{
/**
* AWS IAM User Access Key Id
*/
public string AccessKeyId { get; set; }
/**
* AWS IAM User Secret Key
*/
public string SecretKey { get; set; }
/**
* AWS Region
*/
public string Region { get; set; }
}
}

View File

@ -1,82 +0,0 @@
using System;
using System.Text;
using RestSharp;
namespace Amazon.SellingPartnerAPIAA
{
public class AWSSigV4Signer
{
public virtual AWSSignerHelper AwsSignerHelper { get; set; }
private AWSAuthenticationCredentials awsCredentials;
/// <summary>
/// Constructor for AWSSigV4Signer
/// </summary>
/// <param name="awsAuthenticationCredentials">AWS Developer Account Credentials</param>
public AWSSigV4Signer(AWSAuthenticationCredentials awsAuthenticationCredentials)
{
awsCredentials = awsAuthenticationCredentials;
AwsSignerHelper = new AWSSignerHelper();
}
/// <summary>
/// Signs a Request with AWS Signature Version 4
/// </summary>
/// <param name="request">RestRequest which needs to be signed</param>
/// <param name="host">Request endpoint</param>
/// <returns>RestRequest with AWS Signature</returns>
public IRestRequest Sign(IRestRequest request, string host)
{
DateTime signingDate = AwsSignerHelper.InitializeHeaders(request, host);
string signedHeaders = AwsSignerHelper.ExtractSignedHeaders(request);
string hashedCanonicalRequest = CreateCanonicalRequest(request, signedHeaders);
string stringToSign = AwsSignerHelper.BuildStringToSign(signingDate,
hashedCanonicalRequest,
awsCredentials.Region);
string signature = AwsSignerHelper.CalculateSignature(stringToSign,
signingDate,
awsCredentials.SecretKey,
awsCredentials.Region);
AwsSignerHelper.AddSignature(request,
awsCredentials.AccessKeyId,
signedHeaders,
signature,
awsCredentials.Region,
signingDate);
return request;
}
private string CreateCanonicalRequest(IRestRequest restRequest, string signedHeaders)
{
var canonicalizedRequest = new StringBuilder();
//Request Method
canonicalizedRequest.AppendFormat("{0}\n", restRequest.Method);
//CanonicalURI
canonicalizedRequest.AppendFormat("{0}\n", AwsSignerHelper.ExtractCanonicalURIParameters(restRequest));
//CanonicalQueryString
canonicalizedRequest.AppendFormat("{0}\n", AwsSignerHelper.ExtractCanonicalQueryString(restRequest));
//CanonicalHeaders
canonicalizedRequest.AppendFormat("{0}\n", AwsSignerHelper.ExtractCanonicalHeaders(restRequest));
//SignedHeaders
canonicalizedRequest.AppendFormat("{0}\n", signedHeaders);
// Hash(digest) the payload in the body
canonicalizedRequest.AppendFormat(AwsSignerHelper.HashRequestBody(restRequest));
string canonicalRequest = canonicalizedRequest.ToString();
//Create a digest(hash) of the canonical request
return Utils.ToHex(Utils.Hash(canonicalRequest));
}
}
}

View File

@ -1,263 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RestSharp;
using System.Text.RegularExpressions;
using System.Globalization;
namespace Amazon.SellingPartnerAPIAA
{
public class AWSSignerHelper
{
public const string ISO8601BasicDateTimeFormat = "yyyyMMddTHHmmssZ";
public const string ISO8601BasicDateFormat = "yyyyMMdd";
public const string XAmzDateHeaderName = "X-Amz-Date";
public const string AuthorizationHeaderName = "Authorization";
public const string CredentialSubHeaderName = "Credential";
public const string SignatureSubHeaderName = "Signature";
public const string SignedHeadersSubHeaderName = "SignedHeaders";
public const string HostHeaderName = "host";
public const string Scheme = "AWS4";
public const string Algorithm = "HMAC-SHA256";
public const string TerminationString = "aws4_request";
public const string ServiceName = "execute-api";
public const string Slash = "/";
private readonly static Regex CompressWhitespaceRegex = new Regex("\\s+");
public virtual IDateHelper DateHelper { get; set; }
public AWSSignerHelper()
{
DateHelper = new SigningDateHelper();
}
/// <summary>
/// Returns URI encoded version of absolute path
/// </summary>
/// <param name="request">RestRequest</param>
/// <returns>URI encoded version of absolute path</returns>
public virtual string ExtractCanonicalURIParameters(IRestRequest request)
{
string resource = request.Resource;
string canonicalUri = string.Empty;
if (string.IsNullOrEmpty(resource))
{
canonicalUri = Slash;
}
else
{
if (!resource.StartsWith(Slash))
{
canonicalUri = Slash;
}
IDictionary<string, string> 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<string> encodedSegments = resource.Split(new char[] { '/' }, StringSplitOptions.None);
// Encode twice
encodedSegments = encodedSegments.Select(segment => Utils.UrlEncode(segment));
encodedSegments = encodedSegments.Select(segment => Utils.UrlEncode(segment));
canonicalUri += string.Join(Slash, encodedSegments.ToArray());
}
return canonicalUri;
}
/// <summary>
/// Returns query parameters in canonical order with URL encoding
/// </summary>
/// <param name="request">RestRequest</param>
/// <returns>Query parameters in canonical order with URL encoding</returns>
public virtual string ExtractCanonicalQueryString(IRestRequest request)
{
IDictionary<string, string> queryParameters = request.Parameters
.Where(parameter => ParameterType.QueryString.Equals(parameter.Type))
.ToDictionary(parameter => parameter.Name.Trim().ToString(), parameter => parameter.Value.ToString());
SortedDictionary<string, string> sortedQueryParameters = new SortedDictionary<string, string>(queryParameters);
StringBuilder canonicalQueryString = new StringBuilder();
foreach (var key in sortedQueryParameters.Keys)
{
if (canonicalQueryString.Length > 0)
{
canonicalQueryString.Append("&");
}
canonicalQueryString.AppendFormat("{0}={1}",
Utils.UrlEncode(key),
Utils.UrlEncode(sortedQueryParameters[key]));
}
return canonicalQueryString.ToString();
}
/// <summary>
/// Returns Http headers in canonical order with all header names to lowercase
/// </summary>
/// <param name="request">RestRequest</param>
/// <returns>Returns Http headers in canonical order</returns>
public virtual string ExtractCanonicalHeaders(IRestRequest request)
{
IDictionary<string, string> headers = request.Parameters
.Where(parameter => ParameterType.HttpHeader.Equals(parameter.Type))
.ToDictionary(header => header.Name.Trim().ToLowerInvariant(), header => header.Value.ToString());
SortedDictionary<string, string> sortedHeaders = new SortedDictionary<string, string>(headers);
StringBuilder headerString = new StringBuilder();
foreach (string headerName in sortedHeaders.Keys)
{
headerString.AppendFormat("{0}:{1}\n",
headerName,
CompressWhitespaceRegex.Replace(sortedHeaders[headerName].Trim(), " "));
}
return headerString.ToString();
}
/// <summary>
/// Returns list(as string) of Http headers in canonical order
/// </summary>
/// <param name="request">RestRequest</param>
/// <returns>List of Http headers in canonical order</returns>
public virtual string ExtractSignedHeaders(IRestRequest request)
{
List<string> rawHeaders = request.Parameters.Where(parameter => ParameterType.HttpHeader.Equals(parameter.Type))
.Select(header => header.Name.Trim().ToLowerInvariant())
.ToList();
rawHeaders.Sort(StringComparer.OrdinalIgnoreCase);
return string.Join(";", rawHeaders);
}
/// <summary>
/// Returns hexadecimal hashed value(using SHA256) of payload in the body of request
/// </summary>
/// <param name="request">RestRequest</param>
/// <returns>Hexadecimal hashed value of payload in the body of request</returns>
public virtual string HashRequestBody(IRestRequest request)
{
Parameter body = request.Parameters.FirstOrDefault(parameter => ParameterType.RequestBody.Equals(parameter.Type));
string value = body != null ? body.Value.ToString() : string.Empty;
return Utils.ToHex(Utils.Hash(value));
}
/// <summary>
/// Builds the string for signing using signing date, hashed canonical request and region
/// </summary>
/// <param name="signingDate">Signing Date</param>
/// <param name="hashedCanonicalRequest">Hashed Canonical Request</param>
/// <param name="region">Region</param>
/// <returns>String to be used for signing</returns>
public virtual string BuildStringToSign(DateTime signingDate, string hashedCanonicalRequest, string region)
{
string scope = BuildScope(signingDate, region);
string stringToSign = string.Format(CultureInfo.InvariantCulture, "{0}-{1}\n{2}\n{3}\n{4}",
Scheme,
Algorithm,
signingDate.ToString(ISO8601BasicDateTimeFormat, CultureInfo.InvariantCulture),
scope,
hashedCanonicalRequest);
return stringToSign;
}
/// <summary>
/// Sets AWS4 mandated 'x-amz-date' header, returning the date/time that will
/// be used throughout the signing process.
/// </summary>
/// <param name="restRequest">RestRequest</param>
/// <param name="host">Request endpoint</param>
/// <returns>Date and time used for x-amz-date, in UTC</returns>
public virtual DateTime InitializeHeaders(IRestRequest restRequest, string host)
{
restRequest.Parameters.RemoveAll(parameter => ParameterType.HttpHeader.Equals(parameter.Type)
&& parameter.Name == XAmzDateHeaderName);
restRequest.Parameters.RemoveAll(parameter => ParameterType.HttpHeader.Equals(parameter.Type)
&& parameter.Name == HostHeaderName);
DateTime signingDate = DateHelper.GetUtcNow();
restRequest.AddHeader(XAmzDateHeaderName, signingDate.ToString(ISO8601BasicDateTimeFormat, CultureInfo.InvariantCulture));
restRequest.AddHeader(HostHeaderName, host);
return signingDate;
}
/// <summary>
/// Calculates AWS4 signature for the string, prepared for signing
/// </summary>
/// <param name="stringToSign">String to be signed</param>
/// <param name="signingDate">Signing Date</param>
/// <param name="secretKey">Secret Key</param>
/// <param name="region">Region</param>
/// <returns>AWS4 Signature</returns>
public virtual string CalculateSignature(string stringToSign,
DateTime signingDate,
string secretKey,
string region)
{
string date = signingDate.ToString(ISO8601BasicDateFormat, CultureInfo.InvariantCulture);
byte[] kSecret = Encoding.UTF8.GetBytes(Scheme + secretKey);
byte[] kDate = Utils.GetKeyedHash(kSecret, date);
byte[] kRegion = Utils.GetKeyedHash(kDate, region);
byte[] kService = Utils.GetKeyedHash(kRegion, ServiceName);
byte[] kSigning = Utils.GetKeyedHash(kService, TerminationString);
// Calculate the signature
return Utils.ToHex(Utils.GetKeyedHash(kSigning, stringToSign));
}
/// <summary>
/// Add a signature to a request in the form of an 'Authorization' header
/// </summary>
/// <param name="restRequest">Request to be signed</param>
/// <param name="accessKeyId">Access Key Id</param>
/// <param name="signedHeaders">Signed Headers</param>
/// <param name="signature">The signature to add</param>
/// <param name="region">AWS region for the request</param>
/// <param name="signingDate">Signature date</param>
public virtual void AddSignature(IRestRequest restRequest,
string accessKeyId,
string signedHeaders,
string signature,
string region,
DateTime signingDate)
{
string scope = BuildScope(signingDate, region);
StringBuilder authorizationHeaderValueBuilder = new StringBuilder();
authorizationHeaderValueBuilder.AppendFormat("{0}-{1}", Scheme, Algorithm);
authorizationHeaderValueBuilder.AppendFormat(" {0}={1}/{2},", CredentialSubHeaderName, accessKeyId, scope);
authorizationHeaderValueBuilder.AppendFormat(" {0}={1},", SignedHeadersSubHeaderName, signedHeaders);
authorizationHeaderValueBuilder.AppendFormat(" {0}={1}", SignatureSubHeaderName, signature);
restRequest.AddHeader(AuthorizationHeaderName, authorizationHeaderValueBuilder.ToString());
}
private static string BuildScope(DateTime signingDate, string region)
{
return string.Format("{0}/{1}/{2}/{3}",
signingDate.ToString(ISO8601BasicDateFormat, CultureInfo.InvariantCulture),
region,
ServiceName,
TerminationString);
}
}
}

View File

@ -1,16 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>net461</TargetFramework>
</PropertyGroup> <ReleaseVersion>2.0</ReleaseVersion>
<Version>2.0</Version>
<ItemGroup> <AssemblyVersion>2.0</AssemblyVersion>
<PackageReference Include="RestSharp" Version="106.12.0" /> <FileVersion>2.0</FileVersion>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> </PropertyGroup>
</ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="resources\" /> <PackageReference Include="RestSharp" Version="106.12.0" />
<Folder Include="resources\swagger-codegen\" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<Folder Include="resources\swagger-codegen\templates\" /> </ItemGroup>
</ItemGroup> <ItemGroup>
</Project> <Folder Include="resources\" />
<Folder Include="resources\swagger-codegen\" />
<Folder Include="resources\swagger-codegen\templates\" />
</ItemGroup>
</Project>

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@ -9,6 +10,8 @@ namespace Amazon.SellingPartnerAPIAA
public class LWAClient public class LWAClient
{ {
public const string AccessTokenKey = "access_token"; public const string AccessTokenKey = "access_token";
public const string ErrorCodeKey = "error";
public const string ErrorDescKey = "error_description";
public const string JsonMediaType = "application/json; charset=utf-8"; public const string JsonMediaType = "application/json; charset=utf-8";
public IRestClient RestClient { get; set; } public IRestClient RestClient { get; set; }
@ -38,19 +41,34 @@ namespace Amazon.SellingPartnerAPIAA
accessTokenRequest.AddParameter(JsonMediaType, jsonRequestBody, ParameterType.RequestBody); accessTokenRequest.AddParameter(JsonMediaType, jsonRequestBody, ParameterType.RequestBody);
string accessToken; string accessToken;
LWAExceptionErrorCode errorCode;
try try
{ {
var response = RestClient.Execute(accessTokenRequest); var response = RestClient.Execute(accessTokenRequest);
JObject responseJson = !String.IsNullOrEmpty(response.Content) ? JObject.Parse(response.Content) : null;
if (!IsSuccessful(response)) if (!IsSuccessful(response))
{ {
throw new IOException("Unsuccessful LWA token exchange", response.ErrorException); if (responseJson != null)
{
// If error code is present check error code if its one of the defined LWAExceptionErrorCode values
var parsedErrorCode = responseJson.ContainsKey(ErrorCodeKey) ? Enum.TryParse(responseJson.GetValue(ErrorCodeKey).ToString(), out errorCode) : false;
if (parsedErrorCode) // throw error code and description if matches defined values
{
throw new LWAException(responseJson.GetValue(ErrorCodeKey).ToString(), responseJson.GetValue(ErrorDescKey).ToString(), "Error getting LWA Access Token");
}
} //else throw general LWA exception
throw new LWAException(LWAExceptionErrorCode.other.ToString(), "Other LWA Exception", "Error getting LWA Access Token");
} }
JObject responseJson = JObject.Parse(response.Content);
accessToken = responseJson.GetValue(AccessTokenKey).ToString(); accessToken = responseJson.GetValue(AccessTokenKey).ToString();
} }
catch (LWAException e)
{
throw new LWAException(e.getErrorCode(), e.getErrorMessage(), e.Message);
}
catch (Exception e) catch (Exception e)
{ {
throw new SystemException("Error getting LWA Access Token", e); throw new SystemException("Error getting LWA Access Token", e);

View File

@ -0,0 +1,46 @@
using System;
namespace Amazon.SellingPartnerAPIAA
{
public class LWAException:Exception
{
private String errorMessage;
private String errorCode;
public LWAException():base()
{
}
public LWAException(String errorCode, String errorMessage)
{
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}
public LWAException(String errorCode, String errorMessage, String message): base(message)
{
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}
public LWAException(String errorCode, String errorMessage, String message, Exception innerException) : base(message,innerException)
{
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}
public String getErrorCode()
{
return this.errorCode;
}
public String getErrorMessage()
{
return this.errorMessage;
}
}
}

View File

@ -0,0 +1,17 @@
using System;
namespace Amazon.SellingPartnerAPIAA
{
public enum LWAExceptionErrorCode
{
access_denied,
invalid_grant,
invalid_request,
invalid_scope,
server_error,
temporarily_unavailable,
unauthorized_client,
invalid_client,
other
}
}

View File

@ -33,7 +33,6 @@ namespace {{packageName}}.Client
{{>visibility}} partial class ApiClient {{>visibility}} partial class ApiClient
{ {
private LWAAuthorizationSigner lwaAuthorizationSigner; private LWAAuthorizationSigner lwaAuthorizationSigner;
private AWSSigV4Signer awsSigV4Signer;
private RateLimitConfiguration rateLimitConfig; private RateLimitConfiguration rateLimitConfig;
private TimeLimiter rateLimiter; private TimeLimiter rateLimiter;
@ -46,10 +45,10 @@ namespace {{packageName}}.Client
/// Allows for extending request processing for <see cref="ApiClient"/> generated code. /// Allows for extending request processing for <see cref="ApiClient"/> generated code.
/// </summary> /// </summary>
/// <param name="request">The RestSharp request object</param> /// <param name="request">The RestSharp request object</param>
/// <exception cref="Amazon.SellingPartnerAPIAA.LWAException">Thrown when there is an error during LWA Authorization</exception>
private void InterceptRequest(IRestRequest request) private void InterceptRequest(IRestRequest request)
{ {
lwaAuthorizationSigner.Sign(request); lwaAuthorizationSigner.Sign(request);
awsSigV4Signer.Sign(request, RestClient.BaseUrl.Host);
} }
/// <summary> /// <summary>
@ -74,7 +73,6 @@ namespace {{packageName}}.Client
{{/netStandard}} {{/netStandard}}
lwaAuthorizationSigner = new LWAAuthorizationSigner(Configuration.AuthorizationCredentials); lwaAuthorizationSigner = new LWAAuthorizationSigner(Configuration.AuthorizationCredentials);
awsSigV4Signer = new AWSSigV4Signer(Configuration.AuthenticationCredentials);
rateLimitConfig = Configuration.RateLimitConfig; rateLimitConfig = Configuration.RateLimitConfig;
if(rateLimitConfig != null) if(rateLimitConfig != null)
{ {

View File

@ -268,12 +268,6 @@ namespace {{packageName}}.Client
/// </summary> /// </summary>
/// <value>The LWAAuthorizationCredentials</value> /// <value>The LWAAuthorizationCredentials</value>
public virtual LWAAuthorizationCredentials AuthorizationCredentials { get; set; } public virtual LWAAuthorizationCredentials AuthorizationCredentials { get; set; }
/// <summary>
/// Gets or sets the AWSAuthenticationCredentials for Amazon Selling Partner API Authentication
/// </summary>
/// <value>The AWSAuthenticationCredentials</value>
public virtual AWSAuthenticationCredentials AuthenticationCredentials { get; set; }
/// <summary> /// <summary>
/// Gets or sets the RateLimitConfiguration for Amazon Selling Partner API Authentication /// Gets or sets the RateLimitConfiguration for Amazon Selling Partner API Authentication

View File

@ -88,12 +88,6 @@ namespace {{packageName}}.Client
/// </summary> /// </summary>
/// <value>AuthorizationCredentials</value> /// <value>AuthorizationCredentials</value>
LWAAuthorizationCredentials AuthorizationCredentials { get; } LWAAuthorizationCredentials AuthorizationCredentials { get; }
/// <summary>
/// Gets the AWSAuthenticationCredentials for Amazon Selling Partner API Authentication
/// </summary>
/// <value>AuthenticationCredentials</value>
AWSAuthenticationCredentials AuthenticationCredentials { get; }
/// <summary> /// <summary>
/// Gets the RateLimitConfigurationOnRequests for Amazon Selling Partner API RateLimit /// Gets the RateLimitConfigurationOnRequests for Amazon Selling Partner API RateLimit

View File

@ -435,7 +435,6 @@ namespace {{packageName}}.{{apiPackage}}
public class Builder public class Builder
{ {
private LWAAuthorizationCredentials lwaAuthorizationCredentials; private LWAAuthorizationCredentials lwaAuthorizationCredentials;
private AWSAuthenticationCredentials awsAuthenticationCredentials;
private RateLimitConfiguration rateLimitConfiguration; private RateLimitConfiguration rateLimitConfiguration;
public Builder SetLWAAuthorizationCredentials(LWAAuthorizationCredentials lwaAuthorizationCredentials) public Builder SetLWAAuthorizationCredentials(LWAAuthorizationCredentials lwaAuthorizationCredentials)
@ -443,12 +442,6 @@ namespace {{packageName}}.{{apiPackage}}
this.lwaAuthorizationCredentials = lwaAuthorizationCredentials; this.lwaAuthorizationCredentials = lwaAuthorizationCredentials;
return this; return this;
} }
public Builder SetAWSAuthenticationCredentials(AWSAuthenticationCredentials awsAuthenticationCredentials)
{
this.awsAuthenticationCredentials = awsAuthenticationCredentials;
return this;
}
public Builder SetRateLimitConfiguration(RateLimitConfiguration rateLimitConfiguration) public Builder SetRateLimitConfiguration(RateLimitConfiguration rateLimitConfiguration)
@ -464,15 +457,10 @@ namespace {{packageName}}.{{apiPackage}}
throw new NullReferenceException("LWAAuthoriztionCredentials not set"); throw new NullReferenceException("LWAAuthoriztionCredentials not set");
} }
if (awsAuthenticationCredentials == null)
{
throw new NullReferenceException("AWSAuthenticationCredentials not set");
}
{{packageName}}.Client.Configuration configuration = new {{packageName}}.Client.Configuration() {{packageName}}.Client.Configuration configuration = new {{packageName}}.Client.Configuration()
{ {
AuthorizationCredentials = lwaAuthorizationCredentials, AuthorizationCredentials = lwaAuthorizationCredentials,
AuthenticationCredentials = awsAuthenticationCredentials,
RateLimitConfig = rateLimitConfiguration RateLimitConfig = rateLimitConfiguration
}; };

View File

@ -1,88 +0,0 @@
using Moq;
using Xunit;
using RestSharp;
using Amazon.SellingPartnerAPIAA;
using System;
namespace Amazon.SellingPartnerAPIAATests
{
public class AWSSigV4SignerTest
{
private const string TestAccessKeyId = "aKey";
private const string TestSecretKey = "sKey";
private const string TestRegion = "us-east-1";
private const string TestResourcePath = "iam/user";
private const string TestHost = "sellingpartnerapi.amazon.com";
private RestRequest request;
private AWSSigV4Signer sigV4SignerUnderTest;
private Mock<AWSSignerHelper> mockAWSSignerHelper;
public AWSSigV4SignerTest()
{
request = new RestRequest(TestResourcePath, Method.GET);
AWSAuthenticationCredentials authenticationCredentials = new AWSAuthenticationCredentials
{
AccessKeyId = TestAccessKeyId,
SecretKey = TestSecretKey,
Region = TestRegion
};
mockAWSSignerHelper = new Mock<AWSSignerHelper>();
sigV4SignerUnderTest = new AWSSigV4Signer(authenticationCredentials);
sigV4SignerUnderTest.AwsSignerHelper = mockAWSSignerHelper.Object;
}
[Fact]
public void TestSignRequest()
{
DateTime signingDate = DateTime.UtcNow;
string expectedHashedCanonicalRequest = "b7a5ea4c3179fcebed77f19ccd7d85795d4b7a1810709b55fa7ad3fd79ab6adc";
string expectedSignedHeaders = "testSignedHeaders";
string expectedSignature = "testSignature";
string expectedStringToSign = "testStringToSign";
mockAWSSignerHelper.Setup(signerHelper => signerHelper.InitializeHeaders(request, TestHost))
.Returns(signingDate);
mockAWSSignerHelper.Setup(signerHelper => signerHelper.ExtractCanonicalURIParameters(request))
.Returns("testURIParameters");
mockAWSSignerHelper.Setup(signerHelper => signerHelper.ExtractCanonicalQueryString(request))
.Returns("testCanonicalQueryString");
mockAWSSignerHelper.Setup(signerHelper => signerHelper.ExtractCanonicalHeaders(request))
.Returns("testCanonicalHeaders");
mockAWSSignerHelper.Setup(signerHelper => signerHelper.ExtractSignedHeaders(request))
.Returns(expectedSignedHeaders);
mockAWSSignerHelper.Setup(signerHelper => signerHelper.HashRequestBody(request))
.Returns("testHashRequestBody");
mockAWSSignerHelper.Setup(signerHelper => signerHelper.BuildStringToSign(signingDate,
expectedHashedCanonicalRequest, TestRegion))
.Returns(expectedStringToSign);
mockAWSSignerHelper.Setup(signerHelper => signerHelper.CalculateSignature(expectedStringToSign,
signingDate, TestSecretKey, TestRegion))
.Returns(expectedSignature);
IRestRequest actualRestRequest = sigV4SignerUnderTest.Sign(request, TestHost);
mockAWSSignerHelper.Verify(signerHelper => signerHelper.InitializeHeaders(request, TestHost));
mockAWSSignerHelper.Verify(signerHelper => signerHelper.ExtractCanonicalURIParameters(request));
mockAWSSignerHelper.Verify(signerHelper => signerHelper.ExtractCanonicalQueryString(request));
mockAWSSignerHelper.Verify(signerHelper => signerHelper.ExtractCanonicalHeaders(request));
mockAWSSignerHelper.Verify(signerHelper => signerHelper.ExtractSignedHeaders(request));
mockAWSSignerHelper.Verify(signerHelper => signerHelper.HashRequestBody(request));
mockAWSSignerHelper.Verify(signerHelper => signerHelper.BuildStringToSign(signingDate,
expectedHashedCanonicalRequest,
TestRegion));
mockAWSSignerHelper.Verify(signerHelper => signerHelper.CalculateSignature(expectedStringToSign,
signingDate,
TestSecretKey,
TestRegion));
mockAWSSignerHelper.Verify(signerHelper => signerHelper.AddSignature(request,
TestAccessKeyId,
expectedSignedHeaders,
expectedSignature,
TestRegion,
signingDate));
Assert.Equal(request, actualRestRequest);
}
}
}

View File

@ -1,291 +0,0 @@
using System;
using Xunit;
using RestSharp;
using Amazon.SellingPartnerAPIAA;
using System.Text;
using Moq;
namespace Amazon.SellingPartnerAPIAATests
{
public class AWSSignerHelperTest
{
private const string Slash = "/";
private const string ISOSigningDateTime = "20200504T121212Z";
private const string ISOSigningDate = "20200504";
private const string TestAccessKeyId = "aKey";
private const string TestSecretKey = "sKey";
private const string TestRegion = "us-east-1";
private const string TestResourcePath = "iam/user";
private const string TestHost = "sellingpartnerapi.amazon.com";
private const string JsonMediaType = "application/json; charset=utf-8";
private static readonly DateTime SigningDate = DateTime.Parse("2020-05-04 12:12:12");
private AWSSignerHelper awsSignerHelperUnderTest;
public AWSSignerHelperTest()
{
var mockDateHelper = new Mock<IDateHelper>();
mockDateHelper.Setup(dateHelper => dateHelper.GetUtcNow()).Returns(SigningDate);
awsSignerHelperUnderTest = new AWSSignerHelper() { DateHelper = mockDateHelper.Object };
}
[Fact]
public void TestExtractCanonicalURIParameters()
{
IRestRequest request = new RestRequest(TestResourcePath, Method.GET);
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()
{
IRestRequest request = new RestRequest("iam/ user", Method.GET);
string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(request);
Assert.Equal("/iam/%2520user", result);
}
[Fact]
public void TestExtractCanonicalURIParameters_EmptyResourcePath()
{
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(new RestRequest());
Assert.Equal(Slash, result);
}
[Fact]
public void TestExtractCanonicalURIParameters_SlashPath()
{
IRestRequest request = new RestRequest(Slash, Method.GET);
string result = awsSignerHelperUnderTest.ExtractCanonicalURIParameters(request);
Assert.Equal(Slash, result);
}
[Fact]
public void TestExtractCanonicalQueryString()
{
IRestRequest request = new RestRequest();
request.AddQueryParameter("Version", "2010-05-08");
request.AddQueryParameter("Action", "ListUsers");
request.AddQueryParameter("RequestId", "1");
string result = awsSignerHelperUnderTest.ExtractCanonicalQueryString(request);
//Query parameters in canonical order
Assert.Equal("Action=ListUsers&RequestId=1&Version=2010-05-08", result);
}
[Fact]
public void TestExtractCanonicalQueryString_EmptyQueryParameters()
{
string result = awsSignerHelperUnderTest.ExtractCanonicalQueryString(new RestRequest());
Assert.Empty(result);
}
[Fact]
public void TestExtractCanonicalQueryString_WithUrlEncoding()
{
IRestRequest request = new RestRequest();
request.AddQueryParameter("Action^", "ListUsers$Roles");
string result = awsSignerHelperUnderTest.ExtractCanonicalQueryString(request);
Assert.Equal("Action%5E=ListUsers%24Roles", result);
}
[Fact]
public void TestExtractCanonicalHeaders()
{
IRestRequest request = new RestRequest();
request.AddHeader("X-Amz-Date", "20150830T123600Z");
request.AddHeader("Host", "iam.amazonaws.com");
request.AddHeader("Content-Type", JsonMediaType);
string result = awsSignerHelperUnderTest.ExtractCanonicalHeaders(request);
Assert.Equal("content-type:application/json; charset=utf-8\nhost:iam.amazonaws.com\n" +
"x-amz-date:20150830T123600Z\n", result);
}
[Fact]
public void TestExtractCanonicalHeaders_NoHeader()
{
string result = awsSignerHelperUnderTest.ExtractCanonicalHeaders(new RestRequest());
Assert.Empty(result);
}
[Fact]
public void TestExtractSignedHeaders()
{
IRestRequest request = new RestRequest();
request.AddHeader("X-Amz-Date", "20150830T123600Z");
request.AddHeader("Host", "iam.amazonaws.com");
request.AddHeader("Content-Type", JsonMediaType);
string result = awsSignerHelperUnderTest.ExtractSignedHeaders(request);
Assert.Equal("content-type;host;x-amz-date", result);
}
[Fact]
public void TestExtractSignedHeaders_NoHeader()
{
string result = awsSignerHelperUnderTest.ExtractSignedHeaders(new RestRequest());
Assert.Empty(result);
}
[Fact]
public void TestHashRequestBody()
{
IRestRequest request = new RestRequest(TestResourcePath, Method.POST);
request.AddJsonBody("{\"test\":\"payload\"}");
string result = awsSignerHelperUnderTest.HashRequestBody(request);
Assert.NotEmpty(result);
}
[Fact]
public void TestHashRequestBody_NoBody()
{
string result = awsSignerHelperUnderTest.HashRequestBody(new RestRequest());
Assert.NotEmpty(result);
}
[Fact]
public void TestBuildStringToSign()
{
string expectedCanonicalHash = "foo";
StringBuilder expectedStringBuilder = new StringBuilder();
expectedStringBuilder.AppendLine("AWS4-HMAC-SHA256");
expectedStringBuilder.AppendLine(ISOSigningDateTime);
expectedStringBuilder.AppendFormat("{0}/{1}/execute-api/aws4_request\n", ISOSigningDate, TestRegion);
expectedStringBuilder.Append(expectedCanonicalHash);
string result = awsSignerHelperUnderTest.BuildStringToSign(SigningDate, expectedCanonicalHash, TestRegion);
Assert.Equal(expectedStringBuilder.ToString(), result);
}
[Fact]
public void TestInitializeHeadersReturnsUtcNow()
{
Assert.Equal(SigningDate, awsSignerHelperUnderTest.InitializeHeaders(new RestRequest(), TestHost));
}
[Fact]
public void TestInitializeHeadersSetsUtcNowXAmzDateHeader()
{
IRestRequest request = new RestRequest();
awsSignerHelperUnderTest.InitializeHeaders(request, TestHost);
Parameter actualParameter = request.Parameters.Find(parameter =>
ParameterType.HttpHeader.Equals(parameter.Type) && parameter.Name == AWSSignerHelper.XAmzDateHeaderName);
Assert.Equal(ISOSigningDateTime, actualParameter.Value);
}
[Fact]
public void TestInitializeHeadersOverwritesXAmzDateHeader()
{
IRestRequest request = new RestRequest();
request.AddHeader(AWSSignerHelper.XAmzDateHeaderName, "foobar");
awsSignerHelperUnderTest.InitializeHeaders(request, TestHost);
Parameter actualParameter = request.Parameters.Find(parameter =>
ParameterType.HttpHeader.Equals(parameter.Type) && parameter.Name == AWSSignerHelper.XAmzDateHeaderName);
Assert.Equal(ISOSigningDateTime, actualParameter.Value);
}
[Fact]
public void TestAddSignatureToRequest()
{
IRestRequest restRequest = new RestRequest();
string expectedAccessKeyId = TestAccessKeyId;
string expectedRegion = TestRegion;
string expectedSignature = "testCalculatedSignature";
string expectedSignedHeaders = "header1;header2";
string expectedAuthorizationHeaderValue = string.Format("AWS4-HMAC-SHA256 " +
"Credential={0}/{1}/{2}/execute-api/aws4_request, SignedHeaders={3}, Signature={4}",
expectedAccessKeyId,
ISOSigningDate,
expectedRegion,
expectedSignedHeaders,
expectedSignature);
awsSignerHelperUnderTest.AddSignature(restRequest,
expectedAccessKeyId,
expectedSignedHeaders,
expectedSignature,
expectedRegion,
SigningDate);
Parameter actualParameter = restRequest.Parameters.Find(parameter =>
ParameterType.HttpHeader.Equals(parameter.Type) && parameter.Name == AWSSignerHelper.AuthorizationHeaderName);
Assert.Equal(expectedAuthorizationHeaderValue, actualParameter.Value);
}
[Fact]
public void TestCalculateSignature()
{
string signature = awsSignerHelperUnderTest.CalculateSignature("testString",
SigningDate,
TestSecretKey,
TestRegion);
Assert.Equal("7e2c7c2e330123ef7468b41d8ddaf3841e6ef56959b9116b44ded5466cf96405", signature);
}
[Fact]
public void TestInitializeHeadersSetsHostHeader()
{
IRestRequest restRequest = new RestRequest();
awsSignerHelperUnderTest.InitializeHeaders(restRequest, TestHost);
Parameter actualParamter = restRequest.Parameters.Find(parameter =>
ParameterType.HttpHeader.Equals(parameter.Type) && parameter.Name == AWSSignerHelper.HostHeaderName);
Assert.Equal(TestHost, actualParamter.Value);
}
[Fact]
public void TestInitializeHeadersOverwritesHostHeader()
{
IRestRequest restRequest = new RestRequest();
restRequest.AddHeader(AWSSignerHelper.HostHeaderName, "foobar");
awsSignerHelperUnderTest.InitializeHeaders(restRequest, TestHost);
Parameter actualParamter = restRequest.Parameters.Find(parameter =>
ParameterType.HttpHeader.Equals(parameter.Type) && parameter.Name == AWSSignerHelper.HostHeaderName);
Assert.Equal(TestHost, actualParamter.Value);
}
}
}

View File

@ -1,20 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> <ReleaseVersion>2.0</ReleaseVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> <ItemGroup>
<PackageReference Include="xunit" Version="2.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" /> <PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="coverlet.collector" Version="1.2.0" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<PackageReference Include="Moq" Version="4.14.1" /> <PackageReference Include="coverlet.collector" Version="1.2.0" />
</ItemGroup> <PackageReference Include="Moq" Version="4.14.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Amazon.SellingPartnerAPIAA\Amazon.SellingPartnerAPIAA.csproj" /> <ItemGroup>
</ItemGroup> <ProjectReference Include="..\..\src\Amazon.SellingPartnerAPIAA\Amazon.SellingPartnerAPIAA.csproj" />
</Project> </ItemGroup>
</Project>

View File

@ -15,6 +15,9 @@ namespace Amazon.SellingPartnerAPIAATests
private const string TestClientSecret = "cSecret"; private const string TestClientSecret = "cSecret";
private const string TestClientId = "cId"; private const string TestClientId = "cId";
private const string TestRefreshGrantType = "rToken"; private const string TestRefreshGrantType = "rToken";
private const string LWAExceptionMessage = "Error getting LWA Access Token";
private const string LWAClientAuthMessage = "Client authentication failed";
private const string LWAAccessDeniedMessage = "The customer or authorization server denied the request";
private Mock<RestClient> mockRestClient; private Mock<RestClient> mockRestClient;
private Mock<LWAAccessTokenRequestMetaBuilder> mockLWAAccessTokenRequestMetaBuilder; private Mock<LWAAccessTokenRequestMetaBuilder> mockLWAAccessTokenRequestMetaBuilder;
@ -101,7 +104,7 @@ namespace Amazon.SellingPartnerAPIAATests
} }
[Fact] [Fact]
public void UnsuccessfulPostThrowsException() public void UnsuccessfulPostMissingContentThrowsOtherException()
{ {
IRestResponse response = new RestResponse IRestResponse response = new RestResponse
{ {
@ -119,8 +122,81 @@ namespace Amazon.SellingPartnerAPIAATests
LWAClient lwaClientUnderTest = new LWAClient(LWAAuthorizationCredentials); LWAClient lwaClientUnderTest = new LWAClient(LWAAuthorizationCredentials);
lwaClientUnderTest.RestClient = mockRestClient.Object; lwaClientUnderTest.RestClient = mockRestClient.Object;
SystemException systemException = Assert.Throws<SystemException>(() => lwaClientUnderTest.GetAccessToken()); LWAException lwaException = Assert.Throws<LWAException>(() => lwaClientUnderTest.GetAccessToken());
Assert.IsType<IOException>(systemException.GetBaseException()); Assert.Equal(LWAExceptionErrorCode.other.ToString(), lwaException.getErrorCode());
Assert.Equal(LWAExceptionMessage, lwaException.Message);
}
[Fact]
public void UnsuccessfulPostThrowsInvalidClientException()
{
IRestResponse response = new RestResponse
{
StatusCode = HttpStatusCode.BadRequest,
ResponseStatus = ResponseStatus.Completed,
Content = @"{error:'invalid_client', error_description:'Client authentication failed'}"
};
IRestRequest request = new RestRequest();
mockRestClient.Setup(client => client.Execute(It.IsAny<IRestRequest>()))
.Callback((IRestRequest req) => { request = req; })
.Returns(response);
LWAClient lwaClientUnderTest = new LWAClient(LWAAuthorizationCredentials);
lwaClientUnderTest.RestClient = mockRestClient.Object;
LWAException lwaException = Assert.Throws<LWAException>(() => lwaClientUnderTest.GetAccessToken());
Assert.Equal(LWAExceptionErrorCode.invalid_client.ToString(), lwaException.getErrorCode());
Assert.Equal(LWAClientAuthMessage, lwaException.getErrorMessage());
}
[Fact]
public void UnsuccessfulPostThrowsAccessDeniedException()
{
IRestResponse response = new RestResponse
{
StatusCode = HttpStatusCode.BadRequest,
ResponseStatus = ResponseStatus.Completed,
Content = @"{error:'access_denied', error_description:'The customer or authorization server denied the request'}"
};
IRestRequest request = new RestRequest();
mockRestClient.Setup(client => client.Execute(It.IsAny<IRestRequest>()))
.Callback((IRestRequest req) => { request = req; })
.Returns(response);
LWAClient lwaClientUnderTest = new LWAClient(LWAAuthorizationCredentials);
lwaClientUnderTest.RestClient = mockRestClient.Object;
LWAException lwaException = Assert.Throws<LWAException>(() => lwaClientUnderTest.GetAccessToken());
Assert.Equal(LWAExceptionErrorCode.access_denied.ToString(), lwaException.getErrorCode());
Assert.Equal(LWAAccessDeniedMessage, lwaException.getErrorMessage());
}
[Fact]
public void UnsuccessfulPostThrowsOtherException()
{
IRestResponse response = new RestResponse
{
StatusCode = HttpStatusCode.BadRequest,
ResponseStatus = ResponseStatus.Completed,
Content = @"{error:'invalid_token'}"
};
IRestRequest request = new RestRequest();
mockRestClient.Setup(client => client.Execute(It.IsAny<IRestRequest>()))
.Callback((IRestRequest req) => { request = req; })
.Returns(response);
LWAClient lwaClientUnderTest = new LWAClient(LWAAuthorizationCredentials);
lwaClientUnderTest.RestClient = mockRestClient.Object;
LWAException lwaException = Assert.Throws<LWAException>(() => lwaClientUnderTest.GetAccessToken());
Assert.Equal(LWAExceptionErrorCode.other.ToString(), lwaException.getErrorCode());
Assert.Equal(LWAExceptionMessage, lwaException.Message);
} }
[Fact] [Fact]