Skip to content

Instantly share code, notes, and snippets.

@chgeuer
Last active February 1, 2018 13:01
Show Gist options
  • Save chgeuer/329345c808b84401e3effd023da5c123 to your computer and use it in GitHub Desktop.
Save chgeuer/329345c808b84401e3effd023da5c123 to your computer and use it in GitHub Desktop.
namespace AccountSAS
{
using System;
using System.Linq;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Globalization;
class Program
{
const string accountkey = "UqhiqGVBWNHWtCIrGwTudidp9oxvu...........................................==";
public static void Main(string[] args) => MainAsync(args).GetAwaiter().GetResult();
public static async Task MainAsync(string[] args)
{
// https://docs.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services
var accountname = "erlang";
var cloudEnvironmentSuffix = "core.windows.net";
var host = $"{accountname}.blob.{cloudEnvironmentSuffix}";
var resourcePath = "/";
var query = "comp=list";
var url = $"https://{host}{resourcePath}?{query}";
Func<DateTime, string> dateToString = _ => $"{_.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss", new CultureInfo("en-US"))} GMT";
var xMsDate = dateToString(DateTime.Now);// Mon, 22 Jan 2018 20:55:12 GMT
var xMsVersion = "2015-04-05";
var verb = "GET";
var contentEncoding = "";
var contentLanguage = "";
var contentLength = "";
var contentMD5 = "";
var contentType = "";
var date = "";
var ifModifiedSince = "";
var ifMatch = "";
var ifNoneMatch = "";
var ifUnmodifiedSince = "";
var range = "";
var canonicalizedHeaders = $"x-ms-date:{xMsDate}\nx-ms-version:{xMsVersion}";
Func<string, Uri, string> getCanonicalizedResource = (accountName, theUrl) => {
// see https://docs.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services
var result = new StringBuilder();
// Beginning with an empty string (""), append a forward slash (/), followed by the name of the account that owns the resource being accessed
result.Append($"/{accountName}");
// Append the resource's encoded URI path, without any query parameters
result.Append(HttpUtility.UrlDecode(theUrl.LocalPath));
result.Append("\n");
// Retrieve all query parameters on the resource URI, including the comp parameter if it exists
var queryParams = HttpUtility.ParseQueryString(theUrl.Query);
var q2 = new Dictionary<string, string>();
foreach (var k in queryParams.AllKeys)
{
q2.Add(HttpUtility.UrlDecode(k).ToLower(), HttpUtility.UrlDecode(queryParams[k]));
}
result.Append(string.Join("\n", q2.Keys.OrderBy(__ => __).Select(__ => $"{__}:{q2[__]}").ToArray()));
return result.ToString();
};
var canonicalizedResource = getCanonicalizedResource(accountname, new Uri(url));
var stringToSign = $"{verb}\n{contentEncoding}\n{contentLanguage}\n{contentLength}\n{contentMD5}\n{contentType}\n{date}\n{ifModifiedSince}\n{ifMatch}\n{ifNoneMatch}\n{ifUnmodifiedSince}\n{range}\n{canonicalizedHeaders}\n{canonicalizedResource}";
var signature =
Convert.ToBase64String(
(new HMACSHA256(Convert.FromBase64String(accountkey))).ComputeHash(
Encoding.UTF8.GetBytes(
stringToSign)));
var request = new HttpRequestMessage(HttpMethod.Get, requestUri: url);
request.Headers.Add("x-ms-date", xMsDate);
request.Headers.Add("x-ms-version", xMsVersion);
request.Headers.Add("Authorization", $"SharedKey {accountname}:{signature}");
var response = await new HttpClient().SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
await Console.Out.WriteAsync(body);
}
}
}
GET https://erlang.blob.core.windows.net/?comp=list HTTP/1.1
Authorization: SharedKey erlang:1mBiYrJLA7deadbeefksecretsupervaluedjdjdjdH=
x-ms-date: Thu, 01 Feb 2018 12:58:39 GMT
x-ms-version: 2015-04-05
HTTP/1.1 200 OK
Content-Type: application/xml
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: fe740fd5-001e-0046-6e5c-9bf0ca000000
x-ms-version: 2015-04-05
Date: Thu, 01 Feb 2018 12:58:39 GMT
Content-Length: 1319
<?xml version="1.0" encoding="utf-8"?><EnumerationResults ServiceEndpoint="https://erlang.blob.core.windows.net/"><Containers><Container><Name>datacamp</Name><Properties><Last-Modified>Mon, 07 Nov 2016 14:24:52 GMT</Last-Modified><Etag>"0x8D40719D6AD1DA2"</Etag><LeaseStatus>unlocked</LeaseStatus><LeaseState>available</LeaseState></Properties></Container><Container><Name>otp</Name><Properties><Last-Modified>Thu, 27 Oct 2016 05:46:07 GMT</Last-Modified><Etag>"0x8D3FE2C8C8C182F"</Etag><LeaseStatus>unlocked</LeaseStatus><LeaseState>available</LeaseState></Properties></Container><Container><Name>philipp</Name><Properties><Last-Modified>Tue, 21 Feb 2017 20:39:13 GMT</Last-Modified><Etag>"0x8D45A99B2695859"</Etag><LeaseStatus>unlocked</LeaseStatus><LeaseState>available</LeaseState></Properties></Container><Container><Name>private</Name><Properties><Last-Modified>Wed, 31 Jan 2018 18:39:09 GMT</Last-Modified><Etag>"0x8D568D9EAB0C569"</Etag><LeaseStatus>unlocked</LeaseStatus><LeaseState>available</LeaseState></Properties></Container><Container><Name>weblogs</Name><Properties><Last-Modified>Sat, 19 Nov 2016 19:37:39 GMT</Last-Modified><Etag>"0x8D410B385D5EFA8"</Etag><LeaseStatus>unlocked</LeaseStatus><LeaseState>available</LeaseState></Properties></Container></Containers><NextMarker /></EnumerationResults>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment