in sdk/batch/Microsoft.Azure.Batch/src/Protocol/BatchSharedKeyCredential.cs [59:168]
public override Task ProcessHttpRequestAsync(HttpRequestMessage httpRequest, CancellationToken cancellationToken)
{
if (httpRequest == null)
{
return Async.CompletedTask;
}
//First set ocp-date always
if (!httpRequest.Headers.Contains(OCPDateHeaderString))
{
httpRequest.Headers.TryAddWithoutValidation(OCPDateHeaderString, string.Format(CultureInfo.InvariantCulture, "{0:R}", DateTime.UtcNow));
}
// Set Headers
var signature = new StringBuilder();
signature.Append(httpRequest.Method).Append('\n');
signature.Append(httpRequest.Content != null && httpRequest.Content.Headers.Contains("Content-Encoding") ? httpRequest.Content.Headers.GetValues("Content-Encoding").FirstOrDefault() : string.Empty).Append('\n');
signature.Append(httpRequest.Content != null && httpRequest.Content.Headers.Contains("Content-Language") ? httpRequest.Content.Headers.GetValues("Content-Language").FirstOrDefault() : string.Empty).Append('\n');
// Handle content length
long? contentLength = httpRequest.Content?.Headers?.ContentLength;
if (contentLength == null)
{
// C# in .NET Framework adds a content-lenth = 0 reader for DELETE, PATH, OPTIONS, and POST, so we need to manually set the content-length to 0
// Because of https://github.com/dotnet/corefx/issues/31172 netstandard/netcore has different behavior depending on version, so we purpusefully set
// httoRequest.Content to an empty array to froce inclusion of content-length = 0 on all versions.
if (httpRequest.Method == HttpMethod.Delete || httpRequest.Method == new HttpMethod("PATCH") || httpRequest.Method == HttpMethod.Options || httpRequest.Method == HttpMethod.Post)
{
httpRequest.Content = new ByteArrayContent(EmptyArray);
contentLength = 0;
}
}
signature.Append(contentLength).Append('\n');
signature.Append(httpRequest.Content != null && httpRequest.Content.Headers.Contains("Content-MD5") ? httpRequest.Content.Headers.GetValues("Content-MD5").FirstOrDefault() : string.Empty).Append('\n');
signature.Append(httpRequest.Content != null && httpRequest.Content.Headers.Contains("Content-Type") ? httpRequest.Content.Headers.GetValues("Content-Type").FirstOrDefault() : string.Empty).Append('\n');
signature.Append(httpRequest.Headers.Contains("Date") ? httpRequest.Headers.GetValues("Date").FirstOrDefault() : string.Empty).Append('\n');
signature.Append(httpRequest.Headers.Contains("If-Modified-Since") ? httpRequest.Headers.GetValues("If-Modified-Since").FirstOrDefault() : string.Empty).Append('\n');
signature.Append(httpRequest.Headers.Contains("If-Match") ? httpRequest.Headers.GetValues("If-Match").FirstOrDefault() : string.Empty).Append('\n');
signature.Append(httpRequest.Headers.Contains("If-None-Match") ? httpRequest.Headers.GetValues("If-None-Match").FirstOrDefault() : string.Empty).Append('\n');
signature.Append(httpRequest.Headers.Contains("If-Unmodified-Since") ? httpRequest.Headers.GetValues("If-Unmodified-Since").FirstOrDefault() : string.Empty).Append('\n');
signature.Append(httpRequest.Headers.Contains("Range") ? httpRequest.Headers.GetValues("Range").FirstOrDefault() : string.Empty).Append('\n');
List<string> customHeaders = new List<string>();
foreach (KeyValuePair<string, IEnumerable<string>> header in httpRequest.Headers)
{
if (header.Key.StartsWith("ocp-", StringComparison.OrdinalIgnoreCase))
{
customHeaders.Add(header.Key.ToLowerInvariant());
}
}
if (httpRequest.Content != null)
{
foreach (KeyValuePair<string, IEnumerable<string>> contentHeader in httpRequest.Content.Headers)
{
if (contentHeader.Key.StartsWith("ocp-", StringComparison.OrdinalIgnoreCase))
{
customHeaders.Add(contentHeader.Key.ToLowerInvariant());
}
}
}
customHeaders.Sort(StringComparer.Ordinal);
foreach (string canonicalHeader in customHeaders)
{
string value = httpRequest.Headers.GetValues(canonicalHeader).FirstOrDefault();
value = value.Replace('\n', ' ').Replace('\r', ' ').TrimStart();
signature.Append(canonicalHeader).Append(':').Append(value).Append('\n');
}
signature.Append('/').Append(AccountName).Append('/').Append(httpRequest.RequestUri.AbsolutePath.TrimStart('/'));
if (!string.IsNullOrEmpty(httpRequest.RequestUri.Query))
{
#if FullNetFx
NameValueCollection queryVariables = System.Web.HttpUtility.ParseQueryString(httpRequest.RequestUri.Query);
List<string> queryVariableKeys = new List<string>(queryVariables.AllKeys);
#else
Dictionary<string, Extensions.Primitives.StringValues> queryVariables = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(httpRequest.RequestUri.Query);
List<string> queryVariableKeys = new List<string>(queryVariables.Keys);
#endif
queryVariableKeys.Sort(StringComparer.OrdinalIgnoreCase);
foreach (string queryKey in queryVariableKeys)
{
string lowercaseQueryKey;
if (queryKey != null)
{
lowercaseQueryKey = queryKey.ToLowerInvariant();
}
else
{
lowercaseQueryKey = null;
}
signature.Append('\n').Append(lowercaseQueryKey).Append(':').Append(queryVariables[queryKey]);
}
}
string signedSignature = null;
using (HashAlgorithm hashAlgorithm = new HMACSHA256(Convert.FromBase64String(this.KeyValue)))
{
signedSignature = Convert.ToBase64String(hashAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(signature.ToString())));
}
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("SharedKey", this.AccountName + ":" + signedSignature);
return Async.CompletedTask;
}