已答复 BLOB REST authentication examples

  • 25. ledna 2010 17:47
     
     
    Searched net for examples and have basic framework, but still getting 403 errors.
    Does anyone have a working BLOB REST authentication example?

    Thanks in advance.

Všechny reakce

  • 25. ledna 2010 18:21
     
     
    Hi,

    Will you be able to post some code so that we can take a look?

    Thanks

    Gaurav Mantri
    Cerebrata Software
    http://www.cerebrata.com
  • 25. ledna 2010 18:30
     
     
    Thanks Gaurav, definitely, be back asap to post what I do have...
  • 25. ledna 2010 18:40
    Přispěvatel
     
      Obsahuje kód
    Here is an example of using the REST API to retrieve a list of containers:

    private void GetBlobs()
    {
    	string requestMethod = "GET";
    	String urlPath = "comp=list";
    	String urlPathResource = "comp:list";
    	String msVersion = "2009-09-19";
    	String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
    	String canonicalizedHeaders = String.Format("x-ms-date:{0}\nx-ms-version:{1}", dateInRfc1123Format, msVersion);
    	String canonicalizedResource = String.Format("/{0}/\n{1}", AzureStorageConstants.Account, urlPathResource);
    	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(AzureStorageConstants.BlobEndPoint + "?" + urlPath);
    	HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    	request.Method = requestMethod;
    	request.Headers.Add("x-ms-date", dateInRfc1123Format);
    	request.Headers.Add("x-ms-version", msVersion);
    	request.Headers.Add("Authorization", authorizationHeader);
    	request.Headers.Add("Accept-Charset", "UTF-8");
    	request.Accept = "application/atom+xml,application/xml";
    
    	using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    	{
    		Stream dataStream = response.GetResponseStream();
    		using (StreamReader reader = new StreamReader(dataStream))
    		{
    			String responseFromServer = reader.ReadToEnd();
    		}
    	}
    }
    
    
    private String CreateAuthorizationHeader(String canonicalizedString)
    {
    	if (String.IsNullOrEmpty(canonicalizedString))
    	{
    		throw new ArgumentNullException("canonicalizedString");
    	}
    
    	String signature = CreateHmacSignature(canonicalizedString, AzureStorageConstants.Key);
    	String authorizationHeader = String.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}", AzureStorageConstants.SharedKeyAuthorizationScheme, AzureStorageConstants.Account, signature);
    
    	return authorizationHeader;
    }
    
    private String CreateHmacSignature(String unsignedString, Byte[] key)
    {
    	if (String.IsNullOrEmpty(unsignedString))
    	{
    		throw new ArgumentNullException("unsignedString");
    	}
    
    	if (key == null)
    	{
    		throw new ArgumentNullException("key");
    	}
    
    	Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(unsignedString);
    	using (HMACSHA256 hmacSha256 = new HMACSHA256(key))
    	{
    		return Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
    	}
    }
    


    Note the unfortunate usage where urlPath uses comp=list while urlPathResource uses comp:list. AzureStorageConstants is a trivial class exposing the Azure account details and endpoints.

    I just tried this out so I know it works.
  • 25. ledna 2010 20:13
     
     
    Thank you Neil,

    I used your code with my account/endpoint info but still get 403.
    Can you tell if the values I'm using "look" right please? I'm wondering if its simply the account value?

    var BlobEndPoint = "http://expressionsoft.blob.core.windows.net/";
    var Account = "expressionsoft";
    var SharedKeyAuthorizationScheme = "SharedKey";
    byte[] Key = Encoding.UTF8.GetBytes("Base 64 Secondary Access Key");

    One thing I should mentions is that I expect the GET to return a null or empty list since I haven't submitted any PUT requests yet.
  • 25. ledna 2010 20:44
    Přispěvatel
     
     Odpovědět Obsahuje kód
    jmarquez -

    If you haven't created a container and some blobs I suggest you download Gaurav Mantri's Cloud Storage Studio and use that to create a container and upload some files. Doing this has the advantage that using a third-party tool to access Azure Storage Services demonstrates that there are no problems accessing Azure Storage from your machine - and that you are using the right account and key. You should also use Fiddler to verify precisely what you are sending across the wire. The response visible in Fiddler typically provides additional detail as what the Azure Storage Service discovered to be wrong with your request.

    You should verify that the data is in the correct RFC1123 format - and that it is correct. Azure gives you a 15 minute leeway on the time but if your system is too far off authentication will fail. You should verify that your account key is correct - a good clue that you copied it correctly is that base 64 keys often end with either one or two = symbols.

    I did forget to provide one piece of code and that was used to convert the Base 64 key into an array of Bytes. AzureStorageConstants.Key uses the following to return the key as a Byte array

    Convert.FromBase64String(cloudKey)

  • 25. ledna 2010 20:51
     
     
    Will do, and will post notes here. Thanks again Neil.
  • 19. dubna 2010 0:53
     
      Obsahuje kód

    Hi,

    Excellent post, really helped me get my head around the string signing. Using your code as a template I was trying to do PUTs but am gettting the "Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature." I'm not sure what i'm doing wrong here, any help would be much appreciated.

     

     

     string requestMethod = "PUT";
          String msVersion = "2009-09-19";
          String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
    
          String canonicalizedHeaders = String.Format("x-ms-blob-type:{2}\nx-ms-date:{0}\nx-ms-version:{1}", 
            dateInRfc1123Format, msVersion, "BlockBlob");
    
          String canonicalizedResource = String.Format("/{0}/{1}/{2}", account, container, xmlBlobNew);
          String stringToSign = String.Format("{0}\n\n\n{4}\n\n{3}\n\n\n\n\n\n\n{1}\n{2}", requestMethod, canonicalizedHeaders, 
            canonicalizedResource, "Content-Type:text/plain", "Content-Length:11");
          String authorizationHeader = CreateAuthorizationHeader(stringToSign);
    
          Uri uri = new Uri(blobEndPoint + container + @"/" + xmlBlobNew );
    
          HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
          request.Method = requestMethod;
          request.Headers.Add("x-ms-blob-type", "BlockBlob");
          request.Headers.Add("x-ms-date", dateInRfc1123Format);
          request.Headers.Add("x-ms-version", msVersion);
          request.Headers.Add("Authorization", authorizationHeader);
          request.Headers.Add("Accept-Charset", "UTF-8");
          request.ContentType = "text/plain";
          request.ContentLength = 11;
          request.Accept = "application/atom+xml,application/xml, text/plain";
          ...
    

     

  • 19. dubna 2010 3:02
    Přispěvatel
     
     Navržená odpověď Obsahuje kód

    JimmieBond -

    The following works:

    private void PutBlob(String containerName, String blobName)
    {
    	String requestMethod = "PUT";
    
    	String content = "The Name of This Band is Talking Heads";
    	UTF8Encoding utf8Encoding = new UTF8Encoding();
    	Byte[] blobContent = utf8Encoding.GetBytes(content);
    	Int32 blobLength = blobContent.Length;
    
    	const String blobType = "BlockBlob";
    
    	String urlPath = String.Format("{0}/{1}", containerName, blobName);
    	String msVersion = "2009-09-19";
    	String dateInRfc1123Format = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
    
    	String canonicalizedHeaders = String.Format("x-ms-blob-type:{0}\nx-ms-date:{1}\nx-ms-version:{2}", blobType, dateInRfc1123Format, msVersion);
    	String canonicalizedResource = String.Format("/{0}/{1}", AzureStorageConstants.Account, urlPath);
    	String stringToSign = String.Format("{0}\n\n\n{1}\n\n\n\n\n\n\n\n\n{2}\n{3}", requestMethod, blobLength, canonicalizedHeaders, canonicalizedResource);
    	String authorizationHeader = CreateAuthorizationHeader(stringToSign);
    
    	Uri uri = new Uri(AzureStorageConstants.BlobEndPoint + urlPath);
    	HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    	request.Method = requestMethod;
    	request.Headers.Add("x-ms-blob-type", blobType);
    	request.Headers.Add("x-ms-date", dateInRfc1123Format);
    	request.Headers.Add("x-ms-version", msVersion);
    	request.Headers.Add("Authorization", authorizationHeader);
    	request.ContentLength = blobLength;
    
    	using (Stream requestStream = request.GetRequestStream())
    	{
    		requestStream.Write(blobContent, 0, blobLength);
    	}
    
    	using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    	{
    		String ETag = response.Headers["ETag"];
    	}
    }
    
    • Navržen jako odpověď Jimmiebond 19. dubna 2010 9:58
    •  
  • 19. dubna 2010 9:58
     
     
    Thanks very much.
  • 27. září 2010 16:55
     
      Obsahuje kód

    Hi, I am trying your code for write in my blob, but method GetResponse() gives me the error 'Forbbiden (403)'. I think that the cause is a bad Authorization but I can't find how to fix that issue.

    I'm using local storage:

     

     

     

    String AzureStorageConstantsBlobEndPoint = "http://127.0.0.1:10000/";
    String AzureStorageConstantsAccount = "devstoreaccount1";
    

     

     

     

    private static String CreateAuthorizationHeader(String canonicalizedString)
      {
       String AzureStorageConstantsKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
       String AzureStorageConstantsAccount = "devstoreaccount1";
       String AzureStorageConstantsSharedKeyAuthorizationScheme = "SharedKey";
       
    
       String signature = string.Empty;
       using (HMACSHA256 hmacSha256 = new HMACSHA256(Convert.FromBase64String(AzureStorageConstantsKey)))
       {
        Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(canonicalizedString);
        signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
       }
    
       String authorizationHeader = String.Format(
         CultureInfo.InvariantCulture,
         "{0} {1}:{2}",
         AzureStorageConstantsSharedKeyAuthorizationScheme,
         AzureStorageConstantsAccount,
         signature);
    
       return authorizationHeader;
      }
    

     

     

    I just changed this line of code: 

     

    Uri uri = new Uri(AzureStorageConstantsBlobEndPoint + AzureStorageConstantsAccount + "/" + urlPath);
    

     

    because if I don't put account in the uri, I get a 404 error.

    Did I miss anything?? I'm a little stuck...

    Thanks in advance!! 

     

  • 27. září 2010 18:25
    Přispěvatel
     
      Obsahuje kód

    Carlimir -

    The issue is that the authorization string is slightly different in development storage - and requires the account to be specified twice. When trying out things with the REST interface I prefer to go directly against cloud storage because of these differences and because the Fiddler experience is better. (You should be using Fiddler.)

    In the REST examples I post I tend to focus on code against cloud storage to simplify the code (i.e. I don't give the alternatives.) In this particular case, the solution is to change the declaration of canonicalizedResource to the following (for development storage):

    String canonicalizedResource = String.Format("/{0}/{0}/{1}", AzureStorageConstants.Account, urlPath);
    
    
  • 28. září 2010 7:59
     
     
    Thanks for your response Neil, I solved my issue completely.
    I just  download Fiddler and I find it very interesting. I'll take a look when I can.

    Regards