Authenticating against the Windows Azure Service Management REST API
The Windows Azure Portal provides a user interface for managing Windows Azure hosted services and storage accounts. The Windows Azure Service Management REST API provides a RESTful interface that allows programmatic control of hosted services and storage accounts. It supports most, but not all, of the functionality provided in the Windows Azure Portal.
The Service Management API uses an X.509 certificate for authentication. This certificate must be uploaded as a management certificate to the Windows Azure Portal. Unlike service certificates, management certificates are not deployed to role instances. Consequently, if the Service Management API is to be accessed from an instance of a role, it is necessary to upload the certificate twice: as a management certificate for authentication and as a server certificate that is deployed to the instance. The latter also requires appropriate configuration in the service definition and service configuration files.
A management certificate can be self-signed because it is used only for authentication. As Visual Studio uses the Service Management API to upload and deploy packages, it contains tooling supporting the creation of the certificate. This is an option on the Publish dialog. A management certificate can also be created using makecert
as follows:
C:\Users\Administrator>makecert -r -pe -sky exchange
-a sha1 -len 2048 -ss my -n "CN=Azure Service Management"
AzureServiceManagement.cer
This creates an X.509 certificate and installs it in the Personal (My) branch of the Current User level of the certificate store. It also creates a file named AzureServiceManagement.cer
containing the certificate in a form that can be uploaded as a management certificate to the Windows Azure Portal. The certificate is self-signed (-r), with an exportable private key (-pe), created with the SHA-1 hash algorithm (-a), a 2048-bit key (-len), and with a key type of exchange (-sky).
Once created, the certificate must be uploaded to the Management Certificates section of the Windows Azure Portal. This section is at the subscription level—not the service level—as the Service Management API has visibility across all hosted services and storage accounts under the subscription.
In this recipe, we will learn how to authenticate to the Windows Azure Service Management REST API.
How to do it...
We are going to authenticate against the Windows Azure Service Management REST API and retrieve the list of hosted services for the subscription. We do this as follows:
Add a class named
ServiceManagementExample
to the project.Add the following using statements to the top of the class file:
using System.Net; using System.IO; using System.Xml.Linq; using System.Security.Cryptography.X509Certificates;
Add the following private members to the class:
XNamespace ns = "http://schemas.microsoft.com/windowsazure"; String apiVersion = "2011-02-25"; String subscriptionId; String thumbprint;
Add the following constructor to the class:
ServiceManagementExample(String subscriptionId, String thumbprint) { this.subscriptionId = subscriptionId; this.thumbprint = thumbprint; }
Add the following method, retrieving the client authentication certificate from the certificate store, to the class:
private static X509Certificate2 GetX509Certificate2(String thumbprint) { X509Certificate2 x509Certificate2 = null; X509Store store =new X509Store("My", StoreLocation.CurrentUser); try { store.Open(OpenFlags.ReadOnly); X509Certificate2Collection x509Certificate2Collection =store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false); x509Certificate2 = x509Certificate2Collection[0]; } finally { store.Close(); } return x509Certificate2; }
Add the following method, creating a web request, to the project:
private HttpWebRequest CreateHttpWebRequest(Uri uri, String httpWebRequestMethod) { X509Certificate2 x509Certificate2 =GetX509Certificate2(thumbprint); HttpWebRequest httpWebRequest =(HttpWebRequest)HttpWebRequest.Create(uri); httpWebRequest.Method = httpWebRequestMethod; httpWebRequest.Headers.Add("x-ms-version", apiVersion); httpWebRequest.ClientCertificates.Add(x509Certificate2); httpWebRequest.ContentType = "application/xml"; return httpWebRequest; }
Add the following method, invoking a Get Services operation on the Service Management API, to the class:
private IEnumerable<String> GetHostedServices() { String responseFromServer = String.Empty; XElement xElement; String uriPath = String.Format("https://management.core.windows.net/{0}/services/hostedservices", subscriptionId); Uri uri = new Uri(uriPath); HttpWebRequest httpWebRequest =CreateHttpWebRequest(uri, "GET"); using (HttpWebResponse response =(HttpWebResponse)httpWebRequest.GetResponse()) { Stream responseStream = response.GetResponseStream(); xElement = XElement.Load(responseStream); } IEnumerable<String> serviceNames =from s in xElement.Descendants(ns + "ServiceName") select s.Value; return serviceNames; }
Add the following method, invoking the methods added earlier, to the class:
public static void UseServiceManagementExample() { String subscriptionId = "{SUBSCRIPTION_ID}"; String thumbprint = "{THUMBPRINT}"; ServiceManagementExample example =new ServiceManagementExample(subscriptionId, thumbprint); IEnumerable<String> serviceNames =example.GetHostedServices(); List<String> listServiceNames =serviceNames.ToList<String>(); }
How it works...
In steps 1 and 2, we set up the class. In step 3, we add some private members including the subscriptionId
and thumbprint
that we initialize in the constructor we add in step 4. The ns
member specifies the namespace used in the XML data returned by the Service Management API. In apiVersion
, we specify the API version sent with each request to the Service Management API. The supported versions are listed on MSDN at http://msdn.microsoft.com/en-us/library/gg592580.aspx. Note that the API version is updated whenever new operations are added and that an operation can use a newer API version than the one it was released with.
In step 5, we retrieve the X.509 certificate we use to authenticate against the Service Management API. We use the certificate thumbprint to find the certificate in the Personal/Certificates (My) branch of the Current User level of the certificate store.
In step 6, we create and initialize the HttpWebRequest
used to submit an operation to the Service Management API. We add the X.509 certificate to the request. We also add an x-ms-version
request header specifying the API version of the Service Management API we are using.
In step 7, we submit the request to the Service Management API. We first construct the appropriate URL, which depends on the particular operation to be performed. Then, we make the request and load the response into a XElement
. We query this XElement
to retrieve the names of the hosted services created for the subscription and return them in an IEnumerable<String>
.
In step 8, we add a helper method that invokes each of the methods we added earlier. We must replace {SUBSCRIPTION_ID}
with the subscription ID for the Windows Azure subscription and replace {THUMBPRINT}
with the thumbprint of the management certificate. These can both be found on the Windows Azure Portal.
There's more...
The Microsoft Management Console (MMC) can be used to navigate the certificate store to view and, if desired, export an X.509 certificate. In MMC, the Certificates snap-in provides the choice of navigating through either the Current User or Local Machine level of the certificate store. The makecert
command used earlier inserts the certificate in the Personal branch of the Current User level of the certificate store. The export certificate wizard can be found by selecting the certificate All
Tasks on the right-click menu, and then choosing Export…. This wizard supports export both with and without a private key. The former creates the .CER
file needed for a management certificate while the latter creates the password-protected .PFX
file needed for a service certificate for a hosted service.
The thumbprint is one of the certificate properties that are displayed in the MMC certificate snap-in. However, the snap-in displays the thumbprint as a space-separated, lower-case string. When using the thumbprint in code, it must be converted to an upper-case string with no spaces.