Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iam role implementation #4254

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions clients/sellingpartner-api-aa-csharp/Config
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package.SellingPartnerAPIAuthAndAuthCSharp = {
interfaces = (1.0);

# Use NoOpBuild. See https://w.amazon.com/index.php/BrazilBuildSystem/NoOpBuild
build-system = no-op;
build-tools = {
1.0 = {
NoOpBuild = 1.0;
};
};

# Use runtime-dependencies for when you want to bring in additional
# packages when deploying.
# Use dependencies instead if you intend for these dependencies to
# be exported to other packages that build against you.
dependencies = {
1.0 = {
};
};

runtime-dependencies = {
1.0 = {
};
};

};
12 changes: 11 additions & 1 deletion clients/sellingpartner-api-aa-csharp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ Note the IRestRequest reference is treated as **mutable** when signed.
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.

This implementation of the IAM Role-based Authentication, will work only as long as the initial STS Token is valid (typically for 3600 seconds) and until an instance is able to refresh the STS Token on its own, otherwise, the Token needs to be reinitialized via the AWSSigV4Signer.

*Example*
```
using RestSharp;
Expand All @@ -58,7 +60,13 @@ AWSAuthenticationCredentials awsAuthenticationCredentials = new AWSAuthenticatio
Region = "..."
};

restRequest = new AWSSigV4Signer(awsAuthenticationCredentials)
AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider = new AWSAuthenticationCredentialsProvider
{
RoleArn = "...",
RoleSessionName = "..."
};

restRequest = new AWSSigV4Signer(awsAuthenticationCredentials, awsAuthenticationCredentialsProvider)
.Sign(restRequest, restClient.BaseUrl.Host);
```
Note the IRestRequest reference is treated as **mutable** when signed.
Expand All @@ -75,6 +83,8 @@ All dependencies can be installed via NuGet
- RestSharp - 105.1.0
- Newtonsoft.Json 12.0.3
- NETStandard.Library 2.0.3 (platform-specific implementation requirements are documented on the [Microsoft .NET Guide](https://docs.microsoft.com/en-us/dotnet/standard/net-standard))
- AWSSDK.Core 3.5.1.23
- AWSSDK.SecurityToken 3.5.1.5

## License
Swagger Codegen templates are subject to the [Swagger Codegen License](https://github.com/swagger-api/swagger-codegen#license).
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.SellingPartnerAPIAA", "src\Amazon.SellingPartnerAPIAA\Amazon.SellingPartnerAPIAA.csproj", "{64339397-3AAB-49D3-8B50-7A467B16D545}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.SellingPartnerAPIAATests", "test\Amazon.SellingPartnerAPIAATests\Amazon.SellingPartnerAPIAATests.csproj", "{12B130EB-1087-4F88-BDFA-3088868C0A46}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{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}.Release|Any CPU.ActiveCfg = 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.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.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.SellingPartnerAPIAA", "src\Amazon.SellingPartnerAPIAA\Amazon.SellingPartnerAPIAA.csproj", "{64339397-3AAB-49D3-8B50-7A467B16D545}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.SellingPartnerAPIAATests", "test\Amazon.SellingPartnerAPIAATests\Amazon.SellingPartnerAPIAATests.csproj", "{12B130EB-1087-4F88-BDFA-3088868C0A46}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{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}.Release|Any CPU.ActiveCfg = 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.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.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Amazon.SellingPartnerAPIAA
{
/**
* AWSAuthenticationCredentialsProvider
*/
public class AWSAuthenticationCredentialsProvider
{
/**
* AWS IAM Role ARN
*/
public String RoleArn { get; set; }

/**
* AWS IAM Role Session Name
*/
public String RoleSessionName { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
using System;
using System.Text;
using RestSharp;

using Amazon.Runtime;
using Amazon.SecurityToken;
using Amazon.SecurityToken.Model;
using System.Threading;

namespace Amazon.SellingPartnerAPIAA
{
public class AWSSigV4Signer

{
public virtual AWSSignerHelper AwsSignerHelper { get; set; }
private AWSAuthenticationCredentials awsCredentials;
private AssumeRoleResponse assumeRole;
public const string SecurityTokenHeaderName = "X-Amz-Security-Token";


/// <summary>
/// Constructor for AWSSigV4Signer
Expand All @@ -17,6 +24,29 @@ public class AWSSigV4Signer
public AWSSigV4Signer(AWSAuthenticationCredentials awsAuthenticationCredentials)
{
awsCredentials = awsAuthenticationCredentials;
AwsSignerHelper = new AWSSignerHelper();
}


/// <summary>
/// Overloaded Constructor for AWSSigV4Signer using IAM Role
/// </summary>
/// <param name="awsAuthenticationCredentials">AWS Developer Account Credentials</param>
/// <param name="awsAuthenticationCredentialsProvider">AWS IAM Role and Session Name container</param>
public AWSSigV4Signer(AWSAuthenticationCredentials awsAuthenticationCredentials,
AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider)
{
awsCredentials = awsAuthenticationCredentials;
BasicAWSCredentials basicAWSCredentials = new BasicAWSCredentials(
awsAuthenticationCredentials.AccessKeyId, awsAuthenticationCredentials.SecretKey);
AmazonSecurityTokenServiceClient sts = new AmazonSecurityTokenServiceClient(basicAWSCredentials);
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken cancellationToken = source.Token;
assumeRole = sts.AssumeRoleAsync(new AssumeRoleRequest{
RoleArn = awsAuthenticationCredentialsProvider.RoleArn,
RoleSessionName = awsAuthenticationCredentialsProvider.RoleSessionName
}).Result;

AwsSignerHelper = new AWSSignerHelper();
}

Expand All @@ -28,7 +58,8 @@ public AWSSigV4Signer(AWSAuthenticationCredentials awsAuthenticationCredentials)
/// <returns>RestRequest with AWS Signature</returns>
public IRestRequest Sign(IRestRequest request, string host)
{
DateTime signingDate = AwsSignerHelper.InitializeHeaders(request, host);
DateTime signingDate = AwsSignerHelper.SetDateAndHostHeaders(request, host);

string signedHeaders = AwsSignerHelper.ExtractSignedHeaders(request);

string hashedCanonicalRequest = CreateCanonicalRequest(request, signedHeaders);
Expand All @@ -37,19 +68,44 @@ public IRestRequest Sign(IRestRequest request, string host)
hashedCanonicalRequest,
awsCredentials.Region);

string signature = AwsSignerHelper.CalculateSignature(stringToSign,
if (assumeRole != null)
{

Credentials credentials = assumeRole.Credentials;
AwsSignerHelper.SetSessionTokenHeader(request, credentials.SessionToken);

string signature = AwsSignerHelper.CalculateSignature(stringToSign,
signingDate,
awsCredentials.SecretKey,
awsCredentials.Region);

AwsSignerHelper.AddSignature(request,
awsCredentials.AccessKeyId,
credentials.SecretAccessKey,
awsCredentials.Region);
AwsSignerHelper.AddSignature(request,
credentials.AccessKeyId,
signedHeaders,
signature,
awsCredentials.Region,
signingDate);

return request;
signingDate);

return request;
}
else
{



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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
using RestSharp;
using System.Text.RegularExpressions;
using System.Globalization;

using Amazon.SecurityToken.Model;

namespace Amazon.SellingPartnerAPIAA
{
public class AWSSignerHelper
Expand All @@ -19,6 +20,7 @@ public class AWSSignerHelper
public const string SignatureSubHeaderName = "Signature";
public const string SignedHeadersSubHeaderName = "SignedHeaders";
public const string HostHeaderName = "host";
public const string SecurityTokenHeaderName = "X-Amz-Security-Token";

public const string Scheme = "AWS4";
public const string Algorithm = "HMAC-SHA256";
Expand Down Expand Up @@ -168,27 +170,41 @@ public virtual string BuildStringToSign(DateTime signingDate, string hashedCanon
}

/// <summary>
/// Sets AWS4 mandated 'x-amz-date' header, returning the date/time that will
/// Sets AWS4 mandated 'x-amz-date' and 'host' headers, 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)
public virtual DateTime SetDateAndHostHeaders(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);

&& parameter.Name == HostHeaderName);
DateTime signingDate = DateHelper.GetUtcNow();

restRequest.AddHeader(XAmzDateHeaderName, signingDate.ToString(ISO8601BasicDateTimeFormat, CultureInfo.InvariantCulture));
restRequest.AddHeader(HostHeaderName, host);

restRequest.AddHeader(HostHeaderName, host);
return signingDate;
}

/// <summary>
/// Sets AWS4 'X-Amz-Security-Token' header, used to pass the STS Token to
/// be used throughout the signing process.
/// </summary>
/// <param name="restRequest">RestRequest</param>
/// <param name="sessionToken">STS Session Token</param>
public void SetSessionTokenHeader(IRestRequest restRequest, String sessionToken)
{
restRequest.Parameters.RemoveAll(parameter => ParameterType.HttpHeader.Equals(parameter.Type)
&& parameter.Name == SecurityTokenHeaderName);

restRequest.AddHeader(SecurityTokenHeaderName, sessionToken);
}

/// <summary>
/// Calculates AWS4 signature for the string, prepared for signing
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Newtonsoft.Json;

namespace Amazon.SellingPartnerAPIAA
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,14 @@ namespace {{packageName}}.Client
{{/netStandard}}

lwaAuthorizationSigner = new LWAAuthorizationSigner(Configuration.AuthorizationCredentials);
awsSigV4Signer = new AWSSigV4Signer(Configuration.AuthenticationCredentials);
if (Configuration.AuthenticationCredentialsProvider!=null)
{
awsSigV4Signer = new AWSSigV4Signer(configuration.AuthenticationCredentials, Configuration.AuthenticationCredentialsProvider);
}
else
{
awsSigV4Signer = new AWSSigV4Signer(Configuration.AuthenticationCredentials);
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,12 @@ namespace {{packageName}}.Client
/// <value>The AWSAuthenticationCredentials</value>
public virtual AWSAuthenticationCredentials AuthenticationCredentials { get; set; }

/// <summary>
/// Gets or sets the AWSAuthenticationCredentialsProvider for Amazon Selling Partner API Authentication
/// </summary>
/// <value>The AWSAuthenticationCredentialsProvider</value>
public virtual AWSAuthenticationCredentialsProvider AuthenticationCredentialsProvider { get; set; }

/// <summary>
/// Gets the API key with prefix.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,11 @@ namespace {{packageName}}.Client
/// </summary>
/// <value>AuthenticationCredentials</value>
AWSAuthenticationCredentials AuthenticationCredentials { get; }

/// <summary>
/// Gets the AWSAuthenticationCredentialsProvider for Amazon Selling Partner API Authentication
/// </summary>
/// <value>AWSAuthenticationCredentialsProvider</value>
AWSAuthenticationCredentialsProvider AuthenticationCredentialsProvider { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ namespace {{packageName}}.{{apiPackage}}
{
private LWAAuthorizationCredentials lwaAuthorizationCredentials;
private AWSAuthenticationCredentials awsAuthenticationCredentials;
private AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider;

public Builder SetLWAAuthorizationCredentials(LWAAuthorizationCredentials lwaAuthorizationCredentials)
{
Expand All @@ -449,6 +450,12 @@ namespace {{packageName}}.{{apiPackage}}
return this;
}

public Builder SetAWSAuthenticationCredentialsProvider(AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider)
{
this.awsAuthenticationCredentialsProvider = awsAuthenticationCredentialsProvider;
return this;
}

public {{classname}} Build()
{
if (lwaAuthorizationCredentials == null)
Expand All @@ -463,6 +470,10 @@ namespace {{packageName}}.{{apiPackage}}

{{packageName}}.Client.Configuration configuration = new {{packageName}}.Client.Configuration()
{
if (awsAuthenticationCredentialsProvider != null)
{
AuthenticationCredentialsProvider = awsAuthenticationCredentialsProvider,
}
AuthorizationCredentials = lwaAuthorizationCredentials,
AuthenticationCredentials = awsAuthenticationCredentials
};
Expand Down
Loading