1
votes

I am doing a POC on sending data to Azure event hub using C#. The data will be posted over http unlike the Eventhub client. As per the requirements I cam creating a SAStoken to be embedded in http header. However when posting I get 501, Unauthorized access error. Not sure where I am going wrong. Here is the code that I have written

public static async Task<HttpResponseMessage> SendDataUsingHttp()
        {

            // Namespace info.
            var serviceNamespace = "myeventhubs";
            var hubName = "eventhub1";
            var url = string.Format("{0}/publishers/{1}/messages", hubName, 1);
            //var url = string.Format("{0}/messages", hubName);
            var baseUri = new 
             Uri(string.Format("https://{0}.servicebus.windows.net/" 
                          ,  serviceNamespace));
            var SharedAccessKeyName = "All";
            var SharedAccessKey = "<shared access key>";
            var sasToken = 
            createSasToken(baseUri.ToString(),SharedAccessKeyName, 
                           SharedAccessKey);
            var evtData = new
            {
                Temperature = new Random().Next(20, 50)
            };

            var payload = JsonConvert.SerializeObject(evtData);
            // Create client.
            var httpClient = new HttpClient
            {
                BaseAddress = baseUri
            };


            httpClient.DefaultRequestHeaders.Accept.Clear();
            httpClient.DefaultRequestHeaders.Authorization = new 

            System.Net.Http.Headers.AuthenticationHeaderValue   
             ("SharedAccessSignature", sasToken); 

           var content = new StringContent(payload, Encoding.UTF8);
           content.Headers.ContentType = new 
             System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
            HttpResponseMessage result = null;
            try
            {
                result = await httpClient.PostAsync(url, content);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            return result;
        }

         private static string createSasToken(string baseUri, string keyName, 
         string key)
        {
            TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
            var week = 60 * 60 * 24 * 7;
            var expiration = Convert.ToString((int)sinceEpoch.TotalSeconds + 
            week);
            string stringToSign = HttpUtility.UrlEncode(baseUri) + "\n" + 
            expiration;
            HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key)); //--
            var signature = 
            Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes( 
            stringToSign)));
            var sasToken = String.Format(CultureInfo.InvariantCulture, 
                   "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}", 
            HttpUtility.UrlEncode(baseUri), HttpUtility.UrlEncode(signature), 
            expiration, keyName);
            return sasToken;
}

result

{StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content: System.Net.Http.StreamContent, Headers: { Transfer-Encoding: chunked Strict- Transport-Security: max-age=31536000 Date: Sun, 17 Jun 2018 08:35:43 GMT Server: Microsoft-HTTPAPI/2.0 Content-Type: application/xml; charset=utf-8
}} Content: {System.Net.Http.StreamContent} Headers: {Transfer-Encoding: chunked Strict-Transport-Security: max-age=31536000 Date: Sun, 17 Jun 2018 08:35:43 GMT Server: Microsoft-HTTPAPI/2.0

1
You can always edit your question to add more info without write a comment to add something new. - Kaj
Have you solved this issue, do you need further assistance? - Bruce Chen

1 Answers

0
votes

Based on your createSasToken method, it would generate the authorization header value with the following format:

Authorization: SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}

For your request, you also specify the following code:

System.Net.Http.Headers.AuthenticationHeaderValue("SharedAccessSignature", sasToken); 

Using Fiddler to capture the network traces, you would find that your authorization header value in your sent request would look like this:

Authorization: SharedAccessSignature SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}

For your code, you need to adjust the format of your sasToken under the createSasToken method.

Moreover, the baseUri parameter of createSasToken method needs to be the full request path you are requesting. So you need to modify the related code under SendDataUsingHttp for generating the token as follows:

var sasToken =createSasToken(baseUri+url, SharedAccessKeyName, SharedAccessKey);