PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/WP7.0/BabelCam/C#/Libraries/WindowsPhoneCloud.StorageClient.C#/Credentials/StorageCredentialsAccountAndKey.cs

#
C# | 264 lines | 211 code | 38 blank | 15 comment | 18 complexity | 257067266e0c431aebbb4ff6a81b9ad0 MD5 | raw file
  1. // ----------------------------------------------------------------------------------
  2. // Microsoft Developer & Platform Evangelism
  3. //
  4. // Copyright (c) Microsoft Corporation. All rights reserved.
  5. //
  6. // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
  7. // EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
  8. // OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
  9. // ----------------------------------------------------------------------------------
  10. // The example companies, organizations, products, domain names,
  11. // e-mail addresses, logos, people, places, and events depicted
  12. // herein are fictitious. No association with any real company,
  13. // organization, product, domain name, email address, logo, person,
  14. // places, or events is intended or should be inferred.
  15. // ----------------------------------------------------------------------------------
  16. namespace Microsoft.Samples.WindowsPhoneCloud.StorageClient.Credentials
  17. {
  18. using System;
  19. using System.Collections.Generic;
  20. using System.Data.Services.Client;
  21. using System.Globalization;
  22. using System.Net;
  23. using System.Security.Cryptography;
  24. using System.Text;
  25. public class StorageCredentialsAccountAndKey : IStorageCredentials
  26. {
  27. private string accountName;
  28. private byte[] accountKey;
  29. public StorageCredentialsAccountAndKey(string accountName, string accountKey)
  30. {
  31. if (string.IsNullOrEmpty(accountName))
  32. {
  33. throw new ArgumentException("The account name cannot be empty", "accountName");
  34. }
  35. if (string.IsNullOrEmpty(accountKey))
  36. {
  37. throw new ArgumentException("The account key cannot be empty", "accountKey");
  38. }
  39. this.accountName = accountName;
  40. this.accountKey = Convert.FromBase64String(accountKey.ToString());
  41. }
  42. public void SignRequest(WebRequest webRequest, long contentLength)
  43. {
  44. if (webRequest != null)
  45. {
  46. webRequest.Headers["x-ms-date"] = this.GetDateHeader();
  47. webRequest.Headers["Authorization"] = GetAuthenticationHeader(webRequest, contentLength, this.accountName, this.accountKey);
  48. }
  49. }
  50. public void SignRequestLite(WebRequest webRequest)
  51. {
  52. if (webRequest != null)
  53. {
  54. this.AddAuthenticationHeadersLite(new RequestData { Method = webRequest.Method, RequestUri = webRequest.RequestUri }, webRequest.Headers);
  55. }
  56. }
  57. public void AddAuthenticationHeadersLite(RequestData requestData, WebHeaderCollection requestHeaders)
  58. {
  59. if (requestHeaders != null)
  60. {
  61. var xmsdate = this.GetDateHeader();
  62. requestHeaders["x-ms-version"] = "2009-09-19";
  63. requestHeaders["x-ms-date"] = xmsdate;
  64. requestHeaders["Authorization"] = GetAuthenticationHeaderLite(requestData, this.accountName, this.accountKey, xmsdate);
  65. }
  66. }
  67. internal virtual string GetDateHeader()
  68. {
  69. return DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
  70. }
  71. private static string GetCanonicalizedResourceVersion2(Uri address, string accountName)
  72. {
  73. var builder = new StringBuilder("/");
  74. builder.Append(accountName);
  75. builder.Append(address.AbsolutePath);
  76. var canonicalizedString = new CanonicalizedString(builder.ToString());
  77. var values = HttpUtility.ParseQueryString(address.Query);
  78. var allValues = new WebHeaderCollection();
  79. foreach (string key in values.AllKeys)
  80. {
  81. var list = new List<string>(values.GetValues(key));
  82. list.Sort();
  83. var innerBuilder = new StringBuilder();
  84. foreach (object obj2 in list)
  85. {
  86. if (innerBuilder.Length > 0)
  87. {
  88. innerBuilder.Append(",");
  89. }
  90. innerBuilder.Append(obj2.ToString());
  91. }
  92. allValues.Add(string.IsNullOrEmpty(key) ? key : key.ToLowerInvariant(), innerBuilder.ToString());
  93. }
  94. var keyList = new List<string>(allValues.AllKeys);
  95. keyList.Sort();
  96. foreach (string key in keyList)
  97. {
  98. var innerBuilder = new StringBuilder(string.Empty);
  99. innerBuilder.Append(key);
  100. innerBuilder.Append(":");
  101. innerBuilder.Append(allValues[key]);
  102. canonicalizedString.AppendCanonicalizedElement(innerBuilder.ToString());
  103. }
  104. return canonicalizedString.Value;
  105. }
  106. private static string GetStandardHeaderValue(WebHeaderCollection headers, string headerName)
  107. {
  108. var headerValues = GetHeaderValues(headers, headerName);
  109. if (headerValues.Count != 1)
  110. {
  111. return string.Empty;
  112. }
  113. return (string)headerValues[0];
  114. }
  115. private static List<string> GetHeaderValues(WebHeaderCollection headers, string headerName)
  116. {
  117. var list = new List<string>();
  118. var values = headers.GetValues(headerName);
  119. if (values != null)
  120. {
  121. foreach (string value in values)
  122. {
  123. list.Add(value.TrimStart(new char[0]));
  124. }
  125. }
  126. return list;
  127. }
  128. private static string CanonicalizeHttpRequest(string accountName, long contentLength, WebRequest webRequest)
  129. {
  130. var canonicalizedString = new CanonicalizedString(webRequest.Method);
  131. canonicalizedString.AppendCanonicalizedElement(GetStandardHeaderValue(webRequest.Headers, "Content-Encoding"));
  132. canonicalizedString.AppendCanonicalizedElement(GetStandardHeaderValue(webRequest.Headers, "Content-Language"));
  133. canonicalizedString.AppendCanonicalizedElement((contentLength == -1L) ? string.Empty : contentLength.ToString(CultureInfo.InvariantCulture));
  134. canonicalizedString.AppendCanonicalizedElement(GetStandardHeaderValue(webRequest.Headers, "Content-MD5"));
  135. canonicalizedString.AppendCanonicalizedElement(webRequest.ContentType);
  136. canonicalizedString.AppendCanonicalizedElement(!string.IsNullOrEmpty(GetStandardHeaderValue(webRequest.Headers, "x-ms-date")) ? string.Empty : GetStandardHeaderValue(webRequest.Headers, "Date"));
  137. canonicalizedString.AppendCanonicalizedElement(GetStandardHeaderValue(webRequest.Headers, "If-Modified-Since"));
  138. canonicalizedString.AppendCanonicalizedElement(GetStandardHeaderValue(webRequest.Headers, "If-Match"));
  139. canonicalizedString.AppendCanonicalizedElement(GetStandardHeaderValue(webRequest.Headers, "If-None-Match"));
  140. canonicalizedString.AppendCanonicalizedElement(GetStandardHeaderValue(webRequest.Headers, "If-Unmodified-Since"));
  141. canonicalizedString.AppendCanonicalizedElement(GetStandardHeaderValue(webRequest.Headers, "Range"));
  142. AddCanonicalizedHeaders(webRequest.Headers, canonicalizedString);
  143. AddCanonicalizedResourceVersion2(webRequest.RequestUri, accountName, canonicalizedString);
  144. return canonicalizedString.Value;
  145. }
  146. private static void AddCanonicalizedResourceVersion2(Uri address, string accountName, CanonicalizedString canonicalizedString)
  147. {
  148. var element = GetCanonicalizedResourceVersion2(address, accountName);
  149. canonicalizedString.AppendCanonicalizedElement(element);
  150. }
  151. private static void AddCanonicalizedHeaders(WebHeaderCollection headers, CanonicalizedString canonicalizedString)
  152. {
  153. var keyList = new List<string>();
  154. foreach (string key in headers.AllKeys)
  155. {
  156. if (key.ToLowerInvariant().StartsWith("x-ms-", StringComparison.Ordinal))
  157. {
  158. keyList.Add(key.ToLowerInvariant());
  159. }
  160. }
  161. keyList.Sort();
  162. foreach (string key in keyList)
  163. {
  164. var builder = new StringBuilder(key);
  165. var colonAndComma = ":";
  166. foreach (string values in GetHeaderValues(headers, key))
  167. {
  168. string value = values.Replace("\r\n", string.Empty);
  169. builder.Append(colonAndComma);
  170. builder.Append(value);
  171. colonAndComma = ",";
  172. }
  173. canonicalizedString.AppendCanonicalizedElement(builder.ToString());
  174. }
  175. }
  176. private static string ComputeMacSha256(byte[] accountKey, string canonicalizedString)
  177. {
  178. var bytes = Encoding.UTF8.GetBytes(canonicalizedString);
  179. using (var hmacsha = new HMACSHA256(accountKey))
  180. {
  181. return Convert.ToBase64String(hmacsha.ComputeHash(bytes));
  182. }
  183. }
  184. private static string CanonicalizeHttpRequestLite(string accountName, string xmsdate, Uri requestUri)
  185. {
  186. if (string.IsNullOrEmpty(xmsdate))
  187. {
  188. throw new ArgumentException(
  189. string.Format(
  190. CultureInfo.CurrentCulture,
  191. "Canonicalization did not find a non empty x-ms-date header in the WebRequest. Please use a WebRequest with a valid x-ms-date header in RFC 123 format (example request.Headers[\"x-ms-date\"] = DateTime.UtcNow.ToString(\"R\", CultureInfo.InvariantCulture))",
  192. new object[0]),
  193. "xmsdate");
  194. }
  195. var canonicalizedString = new CanonicalizedString(xmsdate);
  196. canonicalizedString.AppendCanonicalizedElement(GetCanonicalizedResourceLite(requestUri, accountName));
  197. return canonicalizedString.Value;
  198. }
  199. private static string GetCanonicalizedResourceLite(Uri address, string accountName)
  200. {
  201. var builder = new StringBuilder("/");
  202. builder.Append(accountName);
  203. builder.Append(address.AbsolutePath);
  204. var parsedQuery = HttpUtility.ParseQueryString(address.Query);
  205. var compQuery = parsedQuery["comp"] != null ? parsedQuery["comp"] : string.Empty;
  206. if (!string.IsNullOrEmpty(compQuery))
  207. {
  208. builder.Append("?comp=");
  209. builder.Append(compQuery);
  210. }
  211. return builder.ToString();
  212. }
  213. private static string GetAuthenticationHeader(WebRequest webRequest, long contentLength, string accountName, byte[] accountKey)
  214. {
  215. var canonicalizedString = CanonicalizeHttpRequest(accountName, contentLength, webRequest);
  216. var hmacsha256 = ComputeMacSha256(accountKey, canonicalizedString);
  217. return string.Format(CultureInfo.InvariantCulture, "SharedKey {0}:{1}", accountName, hmacsha256);
  218. }
  219. private static string GetAuthenticationHeaderLite(RequestData requestData, string accountName, byte[] accountKey, string xmsdate)
  220. {
  221. var canonicalizedString = CanonicalizeHttpRequestLite(accountName, xmsdate, requestData.RequestUri);
  222. var hmacsha256 = ComputeMacSha256(accountKey, canonicalizedString);
  223. return string.Format(CultureInfo.InvariantCulture, "SharedKeyLite {0}:{1}", accountName, hmacsha256);
  224. }
  225. }
  226. }