in src/Microsoft.Atlas.CommandLine/OAuth2/HttpClientFactory.cs [85:139]
private async Task<HttpResponseMessage> SharedKeyAuthentication(HttpRequestMessage request, CancellationToken cancellationToken, Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> next)
{
var authorization = request.Headers.Authorization;
if (authorization != null && string.Equals(authorization.Scheme, "SharedKey"))
{
var parts = authorization.Parameter.Split(":", 2);
var account = parts[0];
var key = Convert.FromBase64String(parts[1]);
var canonicalizedHeaders = request.Headers
.Where(header => header.Key.StartsWith("x-ms-"))
.Select(header => Tuple.Create(header.Key.ToLowerInvariant(), string.Join(",", header.Value)))
.OrderBy(header => header.Item1, StringComparer.InvariantCulture)
.Select(header => $"{header.Item1}:{header.Item2}\n")
.Aggregate(string.Empty, (a, b) => a + b);
var queryParameters = QueryHelpers
.ParseNullableQuery(request.RequestUri.Query)
?.Select((System.Collections.Generic.KeyValuePair<string, Extensions.Primitives.StringValues> item) =>
{
var name = UrlEncoder.Default.Encode(item.Key.ToLower());
var value = string.Join(",", item.Value.Select(UrlEncoder.Default.Encode));
return new { name, value };
})
?.OrderBy(item => item.name)
?.Select(item => $"\n{item.name}:{item.value}")
?.Aggregate(string.Empty, (a, b) => a + b)
?? string.Empty;
var canonicalizedResource = $"/{account}{request.RequestUri.AbsolutePath}{queryParameters}";
var signatureString =
$"{request.Method}\n" +
$"{request.Content?.Headers?.ContentEncoding}\n" +
$"{request.Content?.Headers?.ContentLanguage}\n" +
$"{request.Content?.Headers?.ContentLength}\n" +
$"{request.Content?.Headers?.ContentMD5}\n" +
$"{request.Content?.Headers?.ContentType}\n" +
$"{request.Headers.Date}\n" +
$"{request.Headers.IfModifiedSince}\n" +
$"{request.Headers.IfMatch}\n" +
$"{request.Headers.IfNoneMatch}\n" +
$"{request.Headers.IfUnmodifiedSince}\n" +
$"{request.Headers.Range}\n" +
$"{canonicalizedHeaders}" +
$"{canonicalizedResource}";
var hmac = new HMACSHA256(key);
var signature = hmac.ComputeHash(Encoding.ASCII.GetBytes(signatureString));
request.Headers.Authorization = new AuthenticationHeaderValue("SharedKey", $"{account}:{Convert.ToBase64String(signature)}");
}
return await next(request, cancellationToken);
}