Accessing Azure Storage Services REST API
First of all, I am not a big fan of implementing Service REST API due to complexity in implementation over easiness with SDK. I would vouch for SDK’s instead going through this lengthy route until unless you have any business compelling reason. The reason is, it would be confusing for the beginners, lot of time spent on testing, lesser samples to refer and why reinvent the wheel. I would focus on the outcome rather going through some complex route of getting the things done.
- --------- C# sample code
static void Main(string[] args)
{
GetQueueMessageWithoutSDK("newportalstorage");
Console.Read();
}
public static String CreateAuthorizationHeader(String canonicalizedString)
{
String signature = String.Empty;
using (HMACSHA256 hmacSha256 = new HMACSHA256(Convert.FromBase64String("your_primarykeyorsecondary")))
{
Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(canonicalizedString);
signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
}
String authorizationHeader = String.Format(CultureInfo.InvariantCulture,"{0} {1}:{2}","SharedKey","newportalstorage",signature);
return authorizationHeader;
}
// get the queueservice name
public static void GetQueueMessageWithoutSDK(String queueName)
{
string requestMethod = "GET";
String urlPath = String.Format("{0}/messages", "queuename");
String storageServiceVersion = "2012-02-12";
String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
String canonicalizedHeaders = String.Format("x-ms-date:{0}\nx-ms-version:{1}",dateInRfc1123Format,storageServiceVersion);
String canonicalizedResource = String.Format("/{0}/{1}", queueName, urlPath);
String stringToSign = String.Format("{0}\n\n\n\n\n\n\n\n\n\n\n\n{1}\n{2}",requestMethod,canonicalizedHeaders,canonicalizedResource);
String authorizationHeader = CreateAuthorizationHeader(stringToSign);
Uri uri = new Uri(https://yourstorageaccountname.queue.core.windows.net/ + urlPath);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = requestMethod;
request.Headers.Add("x-ms-date", dateInRfc1123Format);
request.Headers.Add("x-ms-version", storageServiceVersion);
request.Headers.Add("Authorization", authorizationHeader);
request.Headers.Add(HttpRequestHeader.AcceptCharset, "UTF-8");
request.Accept = "application/atom+xml,application/xml";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response != null
&& response.StatusCode != HttpStatusCode.Unauthorized
&& response.Headers["Content-Type"] != null
&& response.Headers["Content-Type"].Contains("xml"))
{
StreamReader ResponseDataStream = new StreamReader(response.GetResponseStream());
String res = ResponseDataStream.ReadToEnd();
XmlDocument XMLDoc = new XmlDocument();
XMLDoc.LoadXml(res);
XmlNodeList word = XMLDoc.GetElementsByTagName("MessageText");
var xmlNode = word.Item(0);
if (xmlNode != null)
{
string actualMessage=xmlNode.InnerText;
var base64EncodedBytes = Convert.FromBase64String(actualMessage);
string str= Encoding.UTF8.GetString(base64EncodedBytes);
//Actual queue message
Console.WriteLine(str);
}
}
}
------------------------------------------------------------------------------------------------
Equivalent Java code:-
package testone;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;
public class storagedemohttp2 {
static String key="your_primary_key";
static String account="your_accountname";
private static Base64 base64 ;
private static String createAuthorizationHeader(String canonicalizedString) throws InvalidKeyException, Base64DecodingException, NoSuchAlgorithmException, IllegalStateException, UnsupportedEncodingException {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(base64.decode(key), "HmacSHA256"));
String authKey = new String(base64.encode(mac.doFinal(canonicalizedString.getBytes("UTF-8"))));
String authStr = "SharedKey " + account + ":" + authKey;
return authStr;
}
@SuppressWarnings("deprecation")
public static void main(String[] args) throws IOException
{
String key="RxKt6ZxB3+7R8dYHo70HCj+lNwQ5SBLryWVnWYbm8woK+dNd9p31bAbWOAXecVxtklHdZTyu7K/szi0geH31Kw==";
String account="your_accountname";
String requestMethod = "GET";
String urlPath = "yourqueue/messages";
String storageServiceVersion = "2012-02-12";
SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
String date = fmt.format(Calendar.getInstance().getTime()) + " GMT";
String canonicalizedHeaders = "x-ms-date:"+date+"\nx-ms-version:"+storageServiceVersion;
String canonicalizedResource = "/"+account+"/"+urlPath;
String stringToSign = requestMethod+"\n\n\n\n\n\n\n\n\n\n\n\n"+canonicalizedHeaders+"\n"+canonicalizedResource;
HttpURLConnection connection = null;
try {
String authorizationHeader = createAuthorizationHeader(stringToSign);
URL myUrl = new URL("https://newportalstorage.queue.core.windows.net/" + urlPath);
connection=(HttpURLConnection)myUrl.openConnection();
connection.setRequestProperty("x-ms-date", date);
connection.setRequestProperty("x-ms-version", storageServiceVersion);
connection.setRequestProperty("Authorization", authorizationHeader);
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("GET");
DataInputStream inStream = null;
inStream = new DataInputStream(connection.getInputStream());
String buffer;
while((buffer = inStream.readLine()) != null) {
System.out.println(buffer);
}
// Close I/O streams
inStream.close();
} catch (Exception e) {
DataInputStream errStream = new DataInputStream(connection.getErrorStream());
String buffer;
while((buffer = errStream.readLine()) != null) {
System.out.println(buffer);
}
e.printStackTrace();
} finally {
connection.disconnect();
//fs.close();
}
}
}
=============================
Useful links:-
Authentication for the Azure Storage Services
https://msdn.microsoft.com/en-us/library/azure/dd179428.aspx
Github dump >SharedAccessSignatureHelper.java
Examples of the Windows Azure Storage Services REST API
https://dzone.com/articles/examples-windows-azure-storage & https://convective.wordpress.com/2010/08/18/examples-of-the-windows-azure-storage-services-rest-api/
Let me know why you one have to choose this raw implementation over SDK’s and advantage? I understand, we can avoid bulky SDK references but interesting to hear the use case around this. Feel free to drop your comments on this.