Skip to content

Commit

Permalink
Implements the review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
ebozduman committed Apr 27, 2022
1 parent d0b499c commit a2ba386
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 79 deletions.
2 changes: 1 addition & 1 deletion Minio/Credentials/AssumeRoleProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public async override Task<AccessCredentials> GetCredentialsAsync()
ResponseResult responseResult = null;
try
{
responseResult = await Client.ExecuteTaskAsync(this.NoErrorHandlers, requestBuilder, assumeRole: true);
responseResult = await Client.ExecuteTaskAsync(this.NoErrorHandlers, requestBuilder, isSts: true);

AssumeRoleResponse assumeRoleResp = null;
if (responseResult.Response.IsSuccessStatusCode)
Expand Down
13 changes: 7 additions & 6 deletions Minio/MinioClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -524,24 +525,24 @@ public MinioClient WithCredentialsProvider(ClientProvider provider)
/// <param name="errorHandlers">List of handlers to override default handling</param>
/// <param name="requestMessageBuilder">The build of HttpRequestMessageBuilder </param>
/// <param name="cancellationToken">Optional cancellation token to cancel the operation</param>
/// <param name="assumeRole">boolean; if true role credentials, otherwise IAM user</param>
/// <param name="isSts">boolean; if true role credentials, otherwise IAM user</param>
/// <returns>ResponseResult</returns>
internal Task<ResponseResult> ExecuteTaskAsync(
IEnumerable<ApiResponseErrorHandlingDelegate> errorHandlers,
HttpRequestMessageBuilder requestMessageBuilder,
CancellationToken cancellationToken = default(CancellationToken),
bool assumeRole = false)
bool isSts = false)
{
return ExecuteWithRetry(
() => ExecuteTaskCoreAsync(errorHandlers, requestMessageBuilder,
cancellationToken, assumeRole));
cancellationToken, isSts));
}

private async Task<ResponseResult> ExecuteTaskCoreAsync(
IEnumerable<ApiResponseErrorHandlingDelegate> errorHandlers,
HttpRequestMessageBuilder requestMessageBuilder,
CancellationToken cancellationToken = default(CancellationToken),
bool assumeRole = false)
bool isSts = false)
{

var startTime = DateTime.Now;
Expand All @@ -556,7 +557,7 @@ public MinioClient WithCredentialsProvider(ClientProvider provider)
this.SessionToken);

requestMessageBuilder.AddOrUpdateHeaderParameter("Authorization",
v4Authenticator.Authenticate(requestMessageBuilder, assumeRole));
v4Authenticator.Authenticate(requestMessageBuilder, isSts));

HttpRequestMessage request = requestMessageBuilder.Request;

Expand Down Expand Up @@ -732,7 +733,7 @@ private static void ParseErrorFromContent(ResponseResult response)
throw new BucketNotFoundException(bucketName, "Not found.");
}

var contentBytes = System.Text.Encoding.UTF8.GetBytes(response.Content);
var contentBytes = Encoding.UTF8.GetBytes(response.Content);
var stream = new MemoryStream(contentBytes);
ErrorResponse errResponse = (ErrorResponse)new XmlSerializer(typeof(ErrorResponse)).Deserialize(stream);

Expand Down
111 changes: 39 additions & 72 deletions Minio/V4Authenticator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@ private string GetRegion(string endpoint)
/// Implements Authenticate interface method for IAuthenticator.
/// </summary>
/// <param name="requestBuilder">Instantiated IRestRequest object</param>
/// <param name="assumeRole">boolean; if true role credentials, otherwise IAM user</param>
public string Authenticate(HttpRequestMessageBuilder requestBuilder, bool assumeRole)
/// <param name="isSts">boolean; if true role credentials, otherwise IAM user</param>
public string Authenticate(HttpRequestMessageBuilder requestBuilder, bool isSts = false)
{
DateTime signingDate = DateTime.UtcNow;

this.SetContentSha256(requestBuilder, assumeRole);
this.SetContentSha256(requestBuilder, isSts);

requestBuilder.RequestUri = requestBuilder.Request.RequestUri;
var requestUri = requestBuilder.RequestUri;
Expand All @@ -115,34 +115,17 @@ public string Authenticate(HttpRequestMessageBuilder requestBuilder, bool assume
SortedDictionary<string, string> headersToSign = this.GetHeadersToSign(requestBuilder);
string signedHeaders = this.GetSignedHeaders(headersToSign);

string canonicalRequest = this.GetCanonicalRequest(requestBuilder, headersToSign, assumeRole);
byte[] canonicalRequestBytes;
if (assumeRole)
{
canonicalRequestBytes = Encoding.ASCII.GetBytes(canonicalRequest);
}
else
{
canonicalRequestBytes = Encoding.UTF8.GetBytes(canonicalRequest);
}
string canonicalRequest = this.GetCanonicalRequest(requestBuilder, headersToSign);
byte[] canonicalRequestBytes = Encoding.UTF8.GetBytes(canonicalRequest);
var hash = this.ComputeSha256(canonicalRequestBytes);
string canonicalRequestHash = this.BytesToHex(hash);
string region = this.GetRegion(requestUri.Host);
string stringToSign = this.GetStringToSign(region, signingDate, canonicalRequestHash, assumeRole);
byte[] signingKey = this.GenerateSigningKey(region, signingDate, assumeRole);
byte[] stringToSignBytes;
if (assumeRole)
{
stringToSignBytes = Encoding.ASCII.GetBytes(stringToSign);
}
else
{
stringToSignBytes = Encoding.UTF8.GetBytes(stringToSign);
}

string stringToSign = this.GetStringToSign(region, signingDate, canonicalRequestHash, isSts);
byte[] signingKey = this.GenerateSigningKey(region, signingDate, isSts);
byte[] stringToSignBytes = Encoding.UTF8.GetBytes(stringToSign);
byte[] signatureBytes = this.SignHmac(signingKey, stringToSignBytes);
string signature = this.BytesToHex(signatureBytes);
string authorization = this.GetAuthorizationHeader(signedHeaders, signature, signingDate, region, assumeRole);
string authorization = this.GetAuthorizationHeader(signedHeaders, signature, signingDate, region, isSts);
return authorization;
}

Expand All @@ -151,11 +134,11 @@ public string Authenticate(HttpRequestMessageBuilder requestBuilder, bool assume
/// </summary>
/// <param name="signingDate">Signature initiated date</param>
/// <param name="region">Region for the credential string</param>
/// <param name="assumeRole">boolean; if true role credentials, otherwise IAM user</param>
/// <param name="isSts">boolean; if true role credentials, otherwise IAM user</param>
/// <returns>Credential string for the authorization header</returns>
public string GetCredentialString(DateTime signingDate, string region, bool assumeRole = false)
public string GetCredentialString(DateTime signingDate, string region, bool isSts = false)
{
var scope = this.GetScope(region, signingDate, assumeRole);
var scope = this.GetScope(region, signingDate, isSts);
return $"{this.accessKey}/{scope}";
}

Expand All @@ -166,11 +149,11 @@ public string GetCredentialString(DateTime signingDate, string region, bool assu
/// <param name="signature">Hexadecimally encoded computed signature</param>
/// <param name="signingDate">Date for signature to be signed</param>
/// <param name="region">Requested region</param>
/// <param name="assumeRole">boolean; if true role credentials, otherwise IAM user</param>
/// <param name="isSts">boolean; if true role credentials, otherwise IAM user</param>
/// <returns>Fully formed authorization header</returns>
private string GetAuthorizationHeader(string signedHeaders, string signature, DateTime signingDate, string region, bool assumeRole = false)
private string GetAuthorizationHeader(string signedHeaders, string signature, DateTime signingDate, string region, bool isSts = false)
{
var scope = this.GetScope(region, signingDate, assumeRole);
var scope = this.GetScope(region, signingDate, isSts);
return $"AWS4-HMAC-SHA256 Credential={this.accessKey}/{scope}, SignedHeaders={signedHeaders}, Signature={signature}";
}

Expand All @@ -187,48 +170,33 @@ private string GetSignedHeaders(SortedDictionary<string, string> headersToSign)
/// <summary>
/// Determines and returns the kind of service
/// </summary>
/// <param name="assumeRole">boolean; if true role credentials, otherwise IAM user</param>
/// <param name="isSts">boolean; if true role credentials, otherwise IAM user</param>
/// <returns>returns the kind of service as a string</returns>
private string getServiceKind(bool assumeRole)
private string getService(bool isSts)
{
var serviceKind = "s3";
if (assumeRole) serviceKind = "sts";
return serviceKind;
return isSts ? "sts" : "s3";
}

/// <summary>
/// Generates signing key based on the region and date.
/// </summary>
/// <param name="region">Requested region</param>
/// <param name="signingDate">Date for signature to be signed</param>
/// <param name="assumeRole">boolean; if true role credentials, otherwise IAM user</param>
/// <param name="isSts">boolean; if true role credentials, otherwise IAM user</param>
/// <returns>bytes of computed hmac</returns>
private byte[] GenerateSigningKey(string region, DateTime signingDate, bool assumeRole = false)
private byte[] GenerateSigningKey(string region, DateTime signingDate, bool isSts = false)
{
byte[] dateRegionServiceKey;
byte[] requestBytes;
if (assumeRole)
{
byte[] formattedDateBytes = Encoding.ASCII.GetBytes(signingDate.ToString("yyyyMMdd"));
byte[] formattedKeyBytes = Encoding.ASCII.GetBytes($"AWS4{this.secretKey}");
byte[] dateKey = this.SignHmac(formattedKeyBytes, formattedDateBytes);
byte[] regionBytes = Encoding.ASCII.GetBytes(region);
byte[] dateRegionKey = this.SignHmac(dateKey, regionBytes);
byte[] serviceBytes = Encoding.ASCII.GetBytes("sts");
dateRegionServiceKey = this.SignHmac(dateRegionKey, serviceBytes);
requestBytes = Encoding.ASCII.GetBytes("aws4_request");
}
else
{
byte[] formattedDateBytes = Encoding.UTF8.GetBytes(signingDate.ToString("yyyyMMdd"));
byte[] formattedKeyBytes = Encoding.UTF8.GetBytes($"AWS4{this.secretKey}");
byte[] dateKey = this.SignHmac(formattedKeyBytes, formattedDateBytes);
byte[] regionBytes = Encoding.UTF8.GetBytes(region);
byte[] dateRegionKey = this.SignHmac(dateKey, regionBytes);
byte[] serviceBytes = Encoding.UTF8.GetBytes("s3");
dateRegionServiceKey = this.SignHmac(dateRegionKey, serviceBytes);
requestBytes = Encoding.UTF8.GetBytes("aws4_request");
}

byte[] serviceBytes = Encoding.UTF8.GetBytes(getService(isSts));
byte[] formattedDateBytes = Encoding.UTF8.GetBytes(signingDate.ToString("yyyyMMdd"));
byte[] formattedKeyBytes = Encoding.UTF8.GetBytes($"AWS4{this.secretKey}");
byte[] dateKey = this.SignHmac(formattedKeyBytes, formattedDateBytes);
byte[] regionBytes = Encoding.UTF8.GetBytes(region);
byte[] dateRegionKey = this.SignHmac(dateKey, regionBytes);
dateRegionServiceKey = this.SignHmac(dateRegionKey, serviceBytes);
requestBytes = Encoding.UTF8.GetBytes("aws4_request");
var signingKey = Encoding.UTF8.GetString(this.SignHmac(dateRegionServiceKey, requestBytes));
return this.SignHmac(dateRegionServiceKey, requestBytes);
}
Expand All @@ -252,12 +220,12 @@ private byte[] SignHmac(byte[] key, byte[] content)
/// <param name="region">Requested region</param>
/// <param name="signingDate">Date for signature to be signed</param>
/// <param name="canonicalRequestHash">Hexadecimal encoded sha256 checksum of canonicalRequest</param>
/// <param name="assumeRole">boolean; if true role credentials, otherwise IAM user</param>
/// <param name="isSts">boolean; if true role credentials, otherwise IAM user</param>
/// <returns>String to sign</returns>
private string GetStringToSign(string region, DateTime signingDate,
string canonicalRequestHash, bool assumeRole = false)
string canonicalRequestHash, bool isSts = false)
{
var scope = this.GetScope(region, signingDate, assumeRole);
var scope = this.GetScope(region, signingDate, isSts);
return $"AWS4-HMAC-SHA256\n{signingDate:yyyyMMddTHHmmssZ}\n{scope}\n{canonicalRequestHash}";
}

Expand All @@ -266,11 +234,11 @@ private byte[] SignHmac(byte[] key, byte[] content)
/// </summary>
/// <param name="region">Requested region</param>
/// <param name="signingDate">Date for signature to be signed</param>
/// <param name="assumeRole">boolean; if true role credentials, otherwise IAM user</param>
/// <param name="isSts">boolean; if true role credentials, otherwise IAM user</param>
/// <returns>Scope string</returns>
private string GetScope(string region, DateTime signingDate, bool assumeRole = false)
private string GetScope(string region, DateTime signingDate, bool isSts = false)
{
return $"{signingDate:yyyyMMdd}/{region}/{getServiceKind(assumeRole)}/aws4_request";
return $"{signingDate:yyyyMMdd}/{region}/{getService(isSts)}/aws4_request";
}

/// <summary>
Expand Down Expand Up @@ -424,10 +392,9 @@ private static string GetCanonicalHost(Uri url)
/// </summary>
/// <param name="requestBuilder">Instantiated requestBuilder object</param>
/// <param name="headersToSign">Dictionary of http headers to be signed</param>
/// <param name="assumeRole">boolean; if true role credentials, otherwise IAM user</param>
/// <returns>Canonical Request</returns>
private string GetCanonicalRequest(HttpRequestMessageBuilder requestBuilder,
SortedDictionary<string, string> headersToSign, bool assumeRole = false)
SortedDictionary<string, string> headersToSign)
{
var canonicalStringList = new LinkedList<string>();
// METHOD
Expand Down Expand Up @@ -590,9 +557,9 @@ private void SetSessionTokenHeader(HttpRequestMessageBuilder requestBuilder, str
/// <summary>
/// Set 'x-amz-content-sha256' http header.
/// </summary>
/// <param name="assumeRole">boolean; if true role credentials, otherwise IAM user</param>
/// <param name="isSts">boolean; if true role credentials, otherwise IAM user</param>
/// <param name="requestBuilder">Instantiated requestBuilder object</param>
private void SetContentSha256(HttpRequestMessageBuilder requestBuilder, bool assumeRole)
private void SetContentSha256(HttpRequestMessageBuilder requestBuilder, bool isSts = false)
{
if (this.isAnonymous)
return;
Expand All @@ -603,7 +570,7 @@ private void SetContentSha256(HttpRequestMessageBuilder requestBuilder, bool ass
{
isMultiDeleteRequest = requestBuilder.QueryParameters.Any(p => p.Key.Equals("delete", StringComparison.OrdinalIgnoreCase));
}
if (isSecure && !assumeRole || isMultiDeleteRequest)
if (isSecure && !isSts || isMultiDeleteRequest)
{
requestBuilder.AddOrUpdateHeaderParameter("x-amz-content-sha256", "UNSIGNED-PAYLOAD");
return;
Expand Down

0 comments on commit a2ba386

Please sign in to comment.