Send telemetry messages to Azure IoT Central device using HTTP POST request - azure

I'm trying to send telemetry to a device in Azure IoT Central with an HTTP POST request.
Similar Rest API is available for Azure IoT Hub - https://learn.microsoft.com/en-us/rest/api/iothub/device/send-device-event
I was able to extract the IoT Hub resource URL behind the Azure IoT Central using this website - https://dpsgen.z8.web.core.windows.net/
It takes Scope Id, Device Id and Device Primary Key that we get from Azure IoT Central. It gives you the IoT Hub connection string,
HostName=iotc-<<unique-iot-hub-id>>.azure-devices.net;DeviceId=<<device-id>>;SharedAccessKey=<<device-primary-key>>
Using the above IoT Hub host-name, I tried IoT Hub send device event Rest API. It is failing with an Unauthorized error.
I am using SAS token generated from the below path within the Azure IoT Central application
Azure IoT Central -> Permissions -> API tokens -> "App Administrator" Role
Any help will be useful.

Have a look at my answer where is described in details how to generate a connection info for sending a telemetry data to the Azure IoT Central App using a REST Post request.
The following is an updated azure function to generate a requested device connection info:
#r "Newtonsoft.Json"
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
int retryCounter = 10;
int pollingTimeInSeconds = 3;
string deviceId = req.Query["deviceid"];
string mid = req.Query["modelid"];
log.LogInformation($"DeviceId = {deviceId}, ModelId = {mid}");
if (!Regex.IsMatch(deviceId, #"^[a-z0-9\-]+$"))
throw new Exception($"Invalid format: DeviceID must be alphanumeric, lowercase, and may contain hyphens");
string iotcScopeId = System.Environment.GetEnvironmentVariable("AzureIoTC_scopeId");
string iotcSasToken = System.Environment.GetEnvironmentVariable("AzureIoTC_sasToken");
if(string.IsNullOrEmpty(iotcScopeId) || string.IsNullOrEmpty(iotcSasToken))
throw new ArgumentNullException($"Missing the scopeId and/or sasToken of the IoT Central App");
string deviceKey = SharedAccessSignatureBuilder.ComputeSignature(iotcSasToken, deviceId);
string address = $"https://global.azure-devices-provisioning.net/{iotcScopeId}/registrations/{deviceId}/register?api-version=2021-06-01";
string sas = SharedAccessSignatureBuilder.GetSASToken($"{iotcScopeId}/registrations/{deviceId}", deviceKey, "registration");
log.LogInformation($"sas_token: {sas}");
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", sas);
client.DefaultRequestHeaders.Add("accept", "application/json");
string jsontext = string.IsNullOrEmpty(mid) ? null : $"{{ \"modelId\": \"{mid}\" }}";
var response = await client.PutAsync(address, new StringContent(JsonConvert.SerializeObject(new { registrationId = deviceId, payload = jsontext }), Encoding.UTF8, "application/json"));
var atype = new { errorCode = "", message = "", operationId = "", status = "", registrationState = new JObject() };
do
{
dynamic operationStatus = JsonConvert.DeserializeAnonymousType(await response.Content.ReadAsStringAsync(), atype);
if (!string.IsNullOrEmpty(operationStatus.errorCode))
{
throw new Exception($"{operationStatus.errorCode} - {operationStatus.message}");
}
response.EnsureSuccessStatusCode();
if (operationStatus.status == "assigning")
{
Task.Delay(TimeSpan.FromSeconds(pollingTimeInSeconds)).Wait();
address = $"https://global.azure-devices-provisioning.net/{iotcScopeId}/registrations/{deviceId}/operations/{operationStatus.operationId}?api-version=2021-06-01";
response = await client.GetAsync(address);
}
else if (operationStatus.status == "assigned")
{
log.LogInformation($"{JsonConvert.SerializeObject(operationStatus, Formatting.Indented)}");
string assignedHub = operationStatus.registrationState.assignedHub;
string cstr = $"HostName={assignedHub};DeviceId={operationStatus.registrationState.deviceId};SharedAccessKey={deviceKey}"; // + (string.IsNullOrEmpty(mid) ? "" : $";modelId={mid.Replace(";","#")}");
string requestUrl = $"https://{assignedHub}/devices/{operationStatus.registrationState.deviceId}/messages/events?api-version=2021-04-12";
string deviceSasToken = SharedAccessSignatureBuilder.GetSASToken($"{assignedHub}/{operationStatus.registrationState.deviceId}", deviceKey);
log.LogInformation($"IoTC DeviceConnectionString:\n\t{cstr}");
return new OkObjectResult(JObject.FromObject(new { iotHub = assignedHub, iotFireUrl = requestUrl, deviceSasToken = deviceSasToken, deviceConnectionString = cstr }));
}
else
{
throw new Exception($"{operationStatus.registrationState.status}: {operationStatus.registrationState.errorCode} - {operationStatus.registrationState.errorMessage}");
}
} while (--retryCounter > 0);
throw new Exception("Registration device status retry timeout exprired, try again.");
}
}
public sealed class SharedAccessSignatureBuilder
{
public static string GetHostNameNamespaceFromConnectionString(string connectionString)
{
return GetPartsFromConnectionString(connectionString)["HostName"].Split('.').FirstOrDefault();
}
public static string GetSASTokenFromConnectionString(string connectionString, uint hours = 24)
{
var parts = GetPartsFromConnectionString(connectionString);
if (parts.ContainsKey("HostName") && parts.ContainsKey("SharedAccessKey"))
return GetSASToken(parts["HostName"], parts["SharedAccessKey"], parts.Keys.Contains("SharedAccessKeyName") ? parts["SharedAccessKeyName"] : null, hours);
else
return string.Empty;
}
public static string GetSASToken(string resourceUri, string key, string keyName = null, uint hours = 24)
{
try
{
var expiry = GetExpiry(hours);
string stringToSign = System.Web.HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
var signature = SharedAccessSignatureBuilder.ComputeSignature(key, stringToSign);
var sasToken = keyName == null ?
String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}", HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry) :
String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}", HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry, keyName);
return sasToken;
}
catch
{
return string.Empty;
}
}
#region Helpers
public static string ComputeSignature(string key, string stringToSign)
{
using (HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(key)))
{
return Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
}
}
public static Dictionary<string, string> GetPartsFromConnectionString(string connectionString)
{
return connectionString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Split(new[] { '=' }, 2)).ToDictionary(x => x[0].Trim(), x => x[1].Trim(), StringComparer.OrdinalIgnoreCase);
}
// default expiring = 24 hours
private static string GetExpiry(uint hours = 24)
{
TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
return Convert.ToString((ulong)sinceEpoch.TotalSeconds + 3600 * hours);
}
public static DateTime GetDateTimeUtcFromExpiry(ulong expiry)
{
return (new DateTime(1970, 1, 1)).AddSeconds(expiry);
}
public static bool IsValidExpiry(ulong expiry, ulong toleranceInSeconds = 0)
{
return GetDateTimeUtcFromExpiry(expiry) - TimeSpan.FromSeconds(toleranceInSeconds) > DateTime.UtcNow;
}
public static string CreateSHA256Key(string secret)
{
using (var provider = new SHA256CryptoServiceProvider())
{
byte[] keyArray = provider.ComputeHash(UTF8Encoding.UTF8.GetBytes(secret));
provider.Clear();
return Convert.ToBase64String(keyArray);
}
}
public static string CreateRNGKey(int keySize = 32)
{
byte[] keyArray = new byte[keySize];
using (var provider = new RNGCryptoServiceProvider())
{
provider.GetNonZeroBytes(keyArray);
}
return Convert.ToBase64String(keyArray);
}
#endregion
}

The IoT Central API token is to manage the application functionality and cannot be used by the device. Select the device in IoT Central and click on the "Connect" menu at the top, use the primary key shown for that device.
As a side note, https although supported for devices is not well suited for IoT due to its polling nature and does not support device twin desired or reported properties. https://learn.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-d2c-guidance
IoT Central provides built-in high availability, the underlying IoTHub name can change, so manually getting the IoTHub name is not recommended. Always make call DPS to retrieve IoTHub name, the first time and periodically or error conditions.

Related

Azure SignalR Service Connection string

Trying to create a POC for azure signalr service. I found the github samples, which appeared to have some solid examples. I chose this one. Basically, my problem is that when I run the code locally, works like a champ with the localhost url, but when I try to run using an Azure SignalR Service using a url that I copied from azure portal keys which is in this format: Endpoint=<service_endpoint>;AccessKey=<access_key>;, I get an error stating that "Invalid URI: The URI scheme is not valid.". How do I transform the url from what I copy from keys and use it to connect to a signalr service?
class Program
{
private const string DefaultHubEndpoint = "Endpoint=http://someFakesrsname.service.signlar.net;AccsssKey=thisseemslikeagoodaccesskeytouseformyquestion";//"http://localhost:5000/ManagementSampleHub";
private const string Target = "Target";
private const string DefaultUser = "User";
static void Main(string[] args)
{
var app = new CommandLineApplication();
app.FullName = "Azure SignalR Management Sample: SignalR Client Tool";
app.HelpOption("--help");
var hubEndpointOption = app.Option("-h|--hubEndpoint", $"Set hub endpoint. Default value: {DefaultHubEndpoint}", CommandOptionType.SingleValue, true);
var userIdOption = app.Option("-u|--userIdList", "Set user ID list", CommandOptionType.MultipleValue, true);
app.OnExecute(async () =>
{
var hubEndpoint = hubEndpointOption.Value() ?? DefaultHubEndpoint;
var userIds = userIdOption.Values != null && userIdOption.Values.Count > 0 ? userIdOption.Values : new List<string>() { "User" };
Console.WriteLine("hubEndpoint: " + hubEndpoint);
Console.WriteLine("DefaultHubEndpoint: " + DefaultHubEndpoint);
foreach (var userId in userIds)
{
Console.WriteLine("UserId: " + userId);
}
var connections = (from userId in userIds
select CreateHubConnection(hubEndpoint, userId)).ToList();
await Task.WhenAll(from conn in connections
select conn.StartAsync());
Console.WriteLine($"{connections.Count} Client(s) started...");
Console.ReadLine();
await Task.WhenAll(from conn in connections
select conn.StopAsync());
return 0;
});
app.Execute(args);
}
static HubConnection CreateHubConnection(string hubEndpoint, string userId)
{
var url = hubEndpoint.TrimEnd('/') + $"?user={userId}";
var connection = new HubConnectionBuilder().WithUrl(url).Build();
connection.On(Target, (string message) =>
{
Console.WriteLine($"{userId}: gets message from service: '{message}'");
});
connection.Closed += async ex =>
{
Console.WriteLine(ex);
Environment.Exit(1);
};
return connection;
}
}
enter code here

Register Device using rest API of Azure device provisioning service?

I have to register a device on IoT hub using DPS service. I cannot use the .net SDK as device firmware does not support so we decided to use the REST based API's to do the same.
With C# SDK all I need are the .PFX file with password, DPS_IDSCOPE and device endpoint something like this (xyz.azure-devices-provisioning.net).
Now How I can use above information to do the same with azure rest API.For Authentication I have seen below link which says I have to use SAS token for the same as Azure AD access token wont work.
https://social.msdn.microsoft.com/Forums/en-US/19183e82-437e-4d6f-8498-ed33ba18a3fa/creating-iot-device-with-azure-dps-via-rest?forum=azureiothub
Now If I trust on above link (However I do not think it will work ) then where is the use of certificate .PFX file ?
I have found this official API to register the device .
https://learn.microsoft.com/en-us/rest/api/iot-dps/runtimeregistration/registerdevice
I have not understand how to pass the body information like structure of JSON.I know I have to use x509 as Attestation type but how I will form is it like
var pairs = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("registrationId", "device1"),
new KeyValuePair<string, string>("type", "x509"),
};
Or if its a json then what will be the name of attribute ?
Now below are the sample code that I tried to use and getting same error.
Way-1 (Used .PFX as authentication)
public static void RegisterDeviceWithEnrollementGroup()
{
try
{
var handler = new WebRequestHandler();
var certFile = Path.Combine(#"C:\IoT\", "device1.pfx");
handler.ClientCertificates.Add(new X509Certificate2(certFile, "certificatepassword"));
HttpClient client4 = new HttpClient(handler);
client4.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client4.BaseAddress = new Uri("https://XYZ.azure-devices-provisioning.net/scopeid/registrations/device1/register?api-version=2018-11-01");
string content = Newtonsoft.Json.JsonConvert.SerializeObject(null);
var httpContent3 = new StringContent(content, Encoding.UTF8, "application/json");
var pairs = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("registrationId", "device1"),
new KeyValuePair<string, string>("type", "x509"),
};
var content2 = new FormUrlEncodedContent(pairs);
HttpResponseMessage response4 = client4.PutAsync(client4.BaseAddress.ToString(), content2).Result;
var commandResult = string.Empty;
if (response4.IsSuccessStatusCode)
{
commandResult = response4.Content.ReadAsStringAsync().Result;
}
else
{
commandResult = response4.Content.ReadAsStringAsync().Result;
}
Console.WriteLine("IoT hub API call result - " + commandResult);
}
catch (Exception)
{
throw;
}
}
Way-2 - Using SAS token :
public static void RegisterDeviceWithEnrollementGroup()
{
try
{
HttpClient client4 = new HttpClient();
var sas = generateSasToken("XYZ.azure-devices-provisioning.net", "key", "provisioningserviceowner");
client4.DefaultRequestHeaders.Add("Authorization", sas);
client4.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client4.BaseAddress = new Uri("https://XYZ.azure-devices-provisioning.net/scopeid/registrations/device1/register?api-version=2018-11-01");
string content = Newtonsoft.Json.JsonConvert.SerializeObject(null);
var httpContent3 = new StringContent(content, Encoding.UTF8, "application/json");
var pairs = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("registrationId", "device1"),
new KeyValuePair<string, string>("type", "x509"),
};
var content2 = new FormUrlEncodedContent(pairs);
HttpResponseMessage response4 = client4.PutAsync(client4.BaseAddress.ToString(), content2).Result;
var commandResult = string.Empty;
if (response4.IsSuccessStatusCode)
{
commandResult = response4.Content.ReadAsStringAsync().Result;
}
else
{
commandResult = response4.Content.ReadAsStringAsync().Result;
}
Console.WriteLine("IoT hub API call result - " + commandResult);
}
catch (Exception)
{
throw;
}
}
Helper method :
public static string generateSasToken(string resourceUri, string key, string policyName, int expiryInSeconds = 3600)
{
TimeSpan fromEpochStart = DateTime.UtcNow - new DateTime(1970, 1, 1);
string expiry = Convert.ToString((int)fromEpochStart.TotalSeconds + expiryInSeconds);
string stringToSign = WebUtility.UrlEncode(resourceUri) + "\n" + expiry;
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(key));
string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
string token = String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}", WebUtility.UrlEncode(resourceUri), WebUtility.UrlEncode(signature), expiry);
if (!String.IsNullOrEmpty(policyName))
{
token += "&skn=" + policyName;
}
return token;
}
Now Please answer some body whether I am doing correct or wrong here as I am getting exception.
{StatusCode: 415, ReasonPhrase: 'Unsupported Media Type', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
x-ms-request-id: 6475343d-5a2e-407a-9e7f-896e0c489307
Strict-Transport-Security: max-age=31536000; includeSubDomains
Date: Thu, 28 Feb 2019 11:42:59 GMT
Content-Length: 0
}}
Looking forward for the help ...
Please follow the steps outlined here:
https://learn.microsoft.com/en-us/azure/iot-dps/tutorial-net-provision-device-to-hub
to first create an Enrollment in DPS for this device using X.509 (no need to use EnrollmentGroup for a single device).
When registering a device with DPS, use the global endpoint - global.azure-devices-provisioning.net. Configure the HTTP client to include the device client certificate. Do not provide a SAStoken from the device.
You can setup the HTTP message content for device registration as follows:
httpRequest.Content = new StringContent("{\"registrationId\": \"device1\"}", Encoding.UTF8);
httpRequest.Content.Headers.ContentType=MediaTypeHeaderValue.Parse("application/json; charset=utf-8");
Note that the JSON content does NOT include "type" : "x509".
The device endpoint would be as follows:
PUT https://global.azure-devices-provisioning.net/{idScope}/registrations/device1/register?api-version=2018-11-01 (replace idScope with the one from your DPS. A sample idScope would be 0ne00000012)
This POST explains it quite well: http://busbyland.com/azure-iot-device-provisioning-service-via-rest-part-1/
Using the endpoint documented here: https://learn.microsoft.com/es-es/rest/api/iot-dps/runtimeregistration/registerdevice
You can manage to register your devices with a HTTPRequest see the CURL Example above:
curl -L -i -X PUT --cert ./chain.pem --key ./iot-device-1.key.pem -H 'Content-Type: application/json' -H 'Content-Encoding: utf-8' -d '{"registrationId": "iot-device-1", "payload": {"CustomProperty": "CustomValue"}}' https://global.azure-devices-provisioning.net/XXXXXXXXXXX/registrations/iot-device-1/register?api-version=2019-03-31
You could replicate that request in your development environment.
Note that the global.azure-devices-provisioning.net is used which is public and you do not need any authentication/authorization.

Azure Service Bus Shared Access Signature Generation

I am trying to generate Shared Access signature for the Azure service bus queue. Here is the code snippnet through which I am generating SAS token.
using System;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using System.Web;
namespace SASTokenGeneration
{
class Program
{
static void Main(string[] args)
{
string resourceUri = "sb://xxxservicequeue.servicebus.windows.net/;SharedAccessKeyName=xxxservicequeue;SharedAccessKey=xxxxxx";
string key = "token";
string keyName = "xxxservicequeue";
try
{
TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
var week = 60 * 60 * 24 * 7;
var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + week);
string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
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(resourceUri), HttpUtility.UrlEncode(signature), expiry, keyName);
}
catch (Exception ex)
{
}
}
}
}
When I use this token in postman then sometime it gives
MalformedToken: Failed to parse simple web token. azure sevice Bus
and Now I am getting
401 40103: Invalid authorization token signature
From error, I know that I am doing something wrong with connection string but cannot figure out what. Can you please point me in right direction.
Thanks
Problems may locate at
string resourceUri = "sb://xxxservicequeue.servicebus.windows.net/;SharedAccessKeyName=xxxservicequeue;SharedAccessKey=xxxxxx";
string key = "token";
string keyName = "xxxservicequeue";
The resourceUri is the full URI of the Service Bus resource to which access is claimed, in the format of sb://xxxservicequeue.servicebus.windows.net/ or with specific entity you need to operate like sb://xxxservicequeue.servicebus.windows.net/queueName.
The key should be the value of SharedAccessKeyKey and keyName is SAS policy name like the default RootManageSharedAccessKey.
Have a look at doc for more details.

Connecting Azure Service Bus with Android

I wrote a simply java program (jdk 1.7) that lists all my service bus topics and prints out the name of each topic to stdout:
try {
String namespace = "myservicebus"; // from azure portal
String issuer = "owner"; // from azure portal
String key = "asdjklasdjklasdjklasdjklasdjk"; // from azure portal
Configuration config = ServiceBusConfiguration.configureWithWrapAuthentication(
namespace,
issuer,
key,
".servicebus.windows.net",
"-sb.accesscontrol.windows.net/WRAPv0.9");
ServiceBusContract service = ServiceBusService.create(config);
ListTopicsResult result = service.listTopics();
List<TopicInfo> infoList = result.getItems();
for(TopicInfo info : infoList) {
System.out.println( info.getPath());
}
} catch (Exception e) {
e.printStackTrace();
}
Now, i am trying to run this example in a simple android project (Android 4.2) but it wont work.
The runtime always throws following error:
java.lang.RuntimeException: Service or property not registered: com.microsoft.windowsazure.services.serviceBus.ServiceBusContract
Has anyone successfully established a connection from an android device (or emulator) to azure service bus?
Does the Microsoft Azure-Java-SDK not support android projects?
Thanks in advance
This error is due to the fact that apks generated do not include (remove) the ServiceLoader information (under META-INF/services). You can test yourself deleting it from the jar generated and see that the same error appears. In the documentation it is said that it is now supported, but i found problems to use it.
http://developer.android.com/reference/java/util/ServiceLoader.html
You can include manually the data in the apk using ant
Keep 'META-INF/services'-files in apk
After 10h debugging, removing classes manually, including META-INF/services, etc, I found that the Azure SDK uses some classes not supported by Android (javax.ws.*) and any woraround works for me.
So I would recommend using the REST API in Android environments, find below the source code i used to sebd messages to the topic.
private static String generateSasToken(URI uri) {
String targetUri;
try {
targetUri = URLEncoder
.encode(uri.toString().toLowerCase(), "UTF-8")
.toLowerCase();
long expiresOnDate = System.currentTimeMillis();
int expiresInMins = 20; // 1 hour
expiresOnDate += expiresInMins * 60 * 1000;
long expires = expiresOnDate / 1000;
String toSign = targetUri + "\n" + expires;
// Get an hmac_sha1 key from the raw key bytes
byte[] keyBytes = sasKey.getBytes("UTF-8");
SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA256");
// Get an hmac_sha1 Mac instance and initialize with the signing key
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
// Compute the hmac on input data bytes
byte[] rawHmac = mac.doFinal(toSign.getBytes("UTF-8"));
// using Apache commons codec for base64
// String signature = URLEncoder.encode(
// Base64.encodeBase64String(rawHmac), "UTF-8");
String rawHmacStr = new String(Base64.encodeBase64(rawHmac, false),"UTF-8");
String signature = URLEncoder.encode(rawHmacStr, "UTF-8");
// construct authorization string
String token = "SharedAccessSignature sr=" + targetUri + "&sig="
+ signature + "&se=" + expires + "&skn=" + sasKeyName;
return token;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void Send(String topic, String subscription, String msgToSend) throws Exception {
String url = uri+topic+"/messages";
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
// Add header
String token = generateSasToken(new URI(uri));
post.setHeader("Authorization", token);
post.setHeader("Content-Type", "text/plain");
post.setHeader(subscription, subscription);
StringEntity input = new StringEntity(msgToSend);
post.setEntity(input);
System.out.println("Llamando al post");
HttpResponse response = client.execute(post);
System.out.println("Response Code : "
+ response.getStatusLine().getStatusCode());
if (response.getStatusLine().getStatusCode() != 201)
throw new Exception(response.getStatusLine().getReasonPhrase());
}
Further info at REST API Azure information.

How to list Management Certificate In windows azure using REST Api

I am tring to list all the management certificates in a windows azure subcription. And I tried with the following code. But it gives me an exception. And I could find that response is null and the exception message is "The remote server returned an error: (403) Forbidden."
Please help me with this. Msdn doesn't provide an example for this :(
using System;
using System.Collections.Generic;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Xml;
using System.Xml.Linq;
class ManagemenCertificateViewer
{
public static void Runme()
{
string msVersion = "2012-03-01";
string subscriptionId = "I used the subscription Id here";
try
{
ListManagementCertificates(subscriptionId, msVersion);
}
catch (Exception ex)
{
Console.WriteLine("Exception caught: ");
Console.WriteLine(ex.Message);
}
}
private static void ListManagementCertificates(string subscriptionId, string version)
{
string uriFormat = "https://management.core.windows.net/{0}/certificates";
Uri uri = new Uri(string.Format(uriFormat, subscriptionId));
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = "GET";
request.Headers.Add("x-ms-version", version);
request.ContentType = "application/xml";
XDocument responseBody = null;
HttpStatusCode statusCode;
HttpWebResponse response;
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
// GetResponse throws a WebException for 400 and 500 status codes
response = (HttpWebResponse)ex.Response;
}
statusCode = response.StatusCode;
if (response.ContentLength > 0)
{
using (XmlReader reader = XmlReader.Create(response.GetResponseStream()))
{
responseBody = XDocument.Load(reader);
}
}
response.Close();
if (statusCode.Equals(HttpStatusCode.OK))
{
XNamespace wa = "http://schemas.microsoft.com/windowsazure";
XElement storageServices = responseBody.Element(wa + "SubscriptionCertificates");
int mngmntCertificateCount = 0;
foreach (XElement storageService in storageServices.Elements(wa + "SubscriptionCertificate"))
{
string publicKey = storageService.Element(wa + "SubscriptionCertificatePublicKey").Value;
string thumbprint = storageService.Element(wa + "SubscriptionCertificateThumbprint").Value;
string certificateData = storageService.Element(wa + "SubscriptionCertificateData").Value;
string timeCreated = storageService.Element(wa + "TimeCreated").Value;
Console.WriteLine(
"Certificate[{0}]{1} SubscriptionCertificatePublicKey: {2}{1} SubscriptionCertificateThumbprint: {3}{1} certificateData{4}{1} timeCreated{5}{1}",
mngmntCertificateCount++, Environment.NewLine, publicKey, thumbprint, certificateData, timeCreated);
}
}
else
{
Console.WriteLine("List Management certificates returned an error:");
Console.WriteLine("Status Code: {0} ({1}):{2}{3}",
(int)statusCode, statusCode, Environment.NewLine,
responseBody.ToString(SaveOptions.OmitDuplicateNamespaces));
}
return;
}
}
Thanks it's working as I expected. I just add the following line and the Method 'GetCertificate(arg1)'
request.ClientCertificates.Add(GetCertificate(certThumbprint));
One more thing, in Msdn help guide there's a tag in respond body called
<TimeCreated>time-created</TimeCreated>
But the api responds not the TimeCreated its just created.
<Created> ..... </Created>
403 error means something wrong with your management certificate used to authenticate your Service Management API requests. I don't see you attaching a management certificate along with your request in your code. You may find this link useful for authenticating service management API requests: http://msdn.microsoft.com/en-us/library/windowsazure/ee460782.
HTH.

Resources