PageRenderTime 58ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/HigLaboNet/HigLabo.Net/OAuth/1.0/OAuth1Client.Static.cs

#
C# | 318 lines | 202 code | 16 blank | 100 comment | 25 complexity | 116c479a808ee8dfad0d1f5e30edcae0 MD5 | raw file
  1. using System;
  2. #if NETFX_CORE
  3. using Windows.Security.Cryptography;
  4. using Windows.Security.Cryptography.Core;
  5. using Windows.Security.Cryptography.Certificates;
  6. using Windows.Storage.Streams;
  7. using System.Runtime.InteropServices.WindowsRuntime;
  8. #else
  9. using System.Security.Cryptography;
  10. #endif
  11. using System.Collections.Generic;
  12. using System.Text;
  13. using System.Text.RegularExpressions;
  14. namespace HigLabo.Net
  15. {
  16. public partial class OAuth1Client
  17. {
  18. #if SILVERLIGHT || NETFX_CORE
  19. private static readonly Encoding GenerateSignatureEncoding = Encoding.UTF8;
  20. #else
  21. private static readonly Encoding GenerateSignatureEncoding = Encoding.GetEncoding("us-ascii");
  22. #endif
  23. /// <summary>
  24. ///
  25. /// </summary>
  26. public class Key
  27. {
  28. /// <summary>
  29. ///
  30. /// </summary>
  31. public static readonly String OAuthVersionNo = "1.0";
  32. /// <summary>
  33. ///
  34. /// </summary>
  35. public static readonly String OAuthParameterPrefix = "oauth_";
  36. /// <summary>
  37. /// List of know and used oauth parameters' names
  38. /// </summary>
  39. public static readonly String OAuthConsumerKey = "oauth_consumer_key";
  40. /// <summary>
  41. ///
  42. /// </summary>
  43. public static readonly String OAuthCallback = "oauth_callback";
  44. /// <summary>
  45. ///
  46. /// </summary>
  47. public static readonly String OAuthVersion = "oauth_version";
  48. /// <summary>
  49. ///
  50. /// </summary>
  51. public static readonly String OAuthSignatureMethod = "oauth_signature_method";
  52. /// <summary>
  53. ///
  54. /// </summary>
  55. public static readonly String OAuthSignature = "oauth_signature";
  56. /// <summary>
  57. ///
  58. /// </summary>
  59. public static readonly String OAuthTimestamp = "oauth_timestamp";
  60. /// <summary>
  61. ///
  62. /// </summary>
  63. public static readonly String OAuthNonce = "oauth_nonce";
  64. /// <summary>
  65. ///
  66. /// </summary>
  67. public static readonly String OAuthToken = "oauth_token";
  68. /// <summary>
  69. ///
  70. /// </summary>
  71. public static readonly String OAuthTokenSecret = "oauth_token_secret";
  72. /// <summary>
  73. ///
  74. /// </summary>
  75. public static readonly String HMACSHA1SignatureType = "HMAC-SHA1";
  76. /// <summary>
  77. ///
  78. /// </summary>
  79. public static readonly String PlainTextSignatureType = "PLAINTEXT";
  80. /// <summary>
  81. ///
  82. /// </summary>
  83. public static readonly String RSASHA1SignatureType = "RSA-SHA1";
  84. }
  85. private static readonly Random Random = new Random();
  86. /// <summary>
  87. /// Internal function to cut out all non oauth query String parameters (all parameters not begining with "oauth_")
  88. /// </summary>
  89. /// <param name="parameters">The query String part of the Url</param>
  90. /// <returns>A list of QueryParameter each containing the parameter name and value</returns>
  91. protected static List<KeyValuePair<String, String>> GetQueryParameters(String parameters)
  92. {
  93. if (parameters.StartsWith("?"))
  94. {
  95. parameters = parameters.Remove(0, 1);
  96. }
  97. List<KeyValuePair<String, String>> result = new List<KeyValuePair<String, String>>();
  98. if (!String.IsNullOrEmpty(parameters))
  99. {
  100. String[] p = parameters.Split('&');
  101. foreach (String s in p)
  102. {
  103. if (!String.IsNullOrEmpty(s) && !s.StartsWith(Key.OAuthParameterPrefix))
  104. {
  105. if (s.IndexOf('=') > -1)
  106. {
  107. String[] temp = s.Split('=');
  108. result.Add(new KeyValuePair<String, String>(temp[0], temp[1]));
  109. }
  110. else
  111. {
  112. result.Add(new KeyValuePair<String, String>(s, String.Empty));
  113. }
  114. }
  115. }
  116. }
  117. return result;
  118. }
  119. /// <summary>
  120. /// Normalizes the request parameters according to the spec
  121. /// </summary>
  122. /// <param name="parameters">The list of parameters already sorted</param>
  123. /// <returns>a String representing the normalized parameters</returns>
  124. protected static String NormalizeRequestParameters(IList<KeyValuePair<String, String>> parameters)
  125. {
  126. StringBuilder sb = new StringBuilder(256);
  127. KeyValuePair<String, String> p;
  128. for (int i = 0; i < parameters.Count; i++)
  129. {
  130. p = parameters[i];
  131. sb.AppendFormat("{0}={1}", p.Key, p.Value);
  132. if (i < parameters.Count - 1)
  133. {
  134. sb.Append("&");
  135. }
  136. }
  137. return sb.ToString();
  138. }
  139. /// <summary>
  140. ///
  141. /// </summary>
  142. /// <param name="url"></param>
  143. /// <param name="command"></param>
  144. /// <param name="signatureType"></param>
  145. /// <returns></returns>
  146. public static SignatureInfo GenerateSignature(Uri url, GetRequestTokenCommand command, OAuthSignatureTypes signatureType)
  147. {
  148. var cm = command;
  149. SignatureInfo si = new SignatureInfo();
  150. switch (signatureType)
  151. {
  152. case OAuthSignatureTypes.PLAINTEXT:
  153. si.Signature = OAuth1Client.UrlEncode(String.Format("{0}&{1}", cm.ConsumerKeySecret, cm.TokenSecret));
  154. return si;
  155. case OAuthSignatureTypes.HMACSHA1:
  156. si = GenerateSignatureBase(url, cm, Key.HMACSHA1SignatureType);
  157. String key = String.Format("{0}&{1}"
  158. , OAuth1Client.UrlEncode(cm.ConsumerKeySecret), String.IsNullOrEmpty(cm.TokenSecret) ? "" : OAuth1Client.UrlEncode(cm.TokenSecret));
  159. si.Signature = GenerateSignatureUsingHash(key, si.Signature);
  160. return si;
  161. case OAuthSignatureTypes.RSASHA1: throw new NotImplementedException();
  162. }
  163. throw new ArgumentException("Unknown signature type", "signatureType");
  164. }
  165. /// <summary>
  166. ///
  167. /// </summary>
  168. /// <param name="url"></param>
  169. /// <param name="command"></param>
  170. /// <param name="signatureType"></param>
  171. /// <returns></returns>
  172. public static SignatureInfo GenerateSignatureBase(Uri url, GetRequestTokenCommand command, String signatureType)
  173. {
  174. SignatureInfo si = new SignatureInfo();
  175. var cm = command;
  176. if (String.IsNullOrEmpty(signatureType))
  177. {
  178. throw new ArgumentNullException("signatureType");
  179. }
  180. List<KeyValuePair<String, String>> parameters = OAuth1Client.GetQueryParameters(url.Query);
  181. parameters.Add(new KeyValuePair<String, String>(Key.OAuthVersion, Key.OAuthVersionNo));
  182. parameters.Add(new KeyValuePair<String, String>(Key.OAuthNonce, cm.Nonce));
  183. parameters.Add(new KeyValuePair<String, String>(Key.OAuthTimestamp, cm.TimeStamp));
  184. parameters.Add(new KeyValuePair<String, String>(Key.OAuthSignatureMethod, signatureType));
  185. parameters.Add(new KeyValuePair<String, String>(Key.OAuthConsumerKey, cm.ConsumerKey));
  186. if (!String.IsNullOrEmpty(cm.Token))
  187. {
  188. parameters.Add(new KeyValuePair<String, String>(Key.OAuthToken, cm.Token));
  189. }
  190. parameters.Sort(CompareQueryString);
  191. si.NormalizedUrl = String.Format("{0}://{1}", url.Scheme, url.Host);
  192. if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443)))
  193. {
  194. si.NormalizedUrl += ":" + url.Port;
  195. }
  196. si.NormalizedUrl += url.AbsolutePath;
  197. si.NormalizedRequestParameters = NormalizeRequestParameters(parameters);
  198. StringBuilder sb = new StringBuilder(1000);
  199. sb.AppendFormat("{0}&", cm.MethodName.ToString().ToUpper());
  200. sb.AppendFormat("{0}&", OAuth1Client.UrlEncode(si.NormalizedUrl));
  201. sb.AppendFormat("{0}", OAuth1Client.UrlEncode(si.NormalizedRequestParameters));
  202. si.Signature = sb.ToString();
  203. return si;
  204. }
  205. private static int CompareQueryString(KeyValuePair<String, String> x, KeyValuePair<String, String> y)
  206. {
  207. if (x.Key == y.Key)
  208. {
  209. return String.Compare(x.Value, y.Value);
  210. }
  211. return String.Compare(x.Key, y.Key);
  212. }
  213. /// <summary>
  214. ///
  215. /// </summary>
  216. /// <param name="key"></param>
  217. /// <param name="data"></param>
  218. /// <returns></returns>
  219. #if NETFX_CORE
  220. public static String GenerateSignatureUsingHash(String key, String data)
  221. {
  222. MacAlgorithmProvider hash = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha1);
  223. BinaryStringEncoding encoding = BinaryStringEncoding.Utf8;
  224. var dataBuffer = CryptographicBuffer.ConvertStringToBinary(data, encoding);
  225. IBuffer buffKeyMaterial = CryptographicBuffer.GenerateRandom(hash.MacLength);
  226. var hmacKey = hash.CreateKey(OAuth1Client.GenerateSignatureEncoding.GetBytes(key).AsBuffer());
  227. var hashBytes = CryptographicEngine.Sign(hmacKey, dataBuffer);
  228. // Verify that the HMAC length is correct for the selected algorithm
  229. if (hashBytes.Length != hash.MacLength)
  230. {
  231. throw new Exception("Error computing digest");
  232. }
  233. return Convert.ToBase64String(hashBytes.ToArray());
  234. }
  235. #else
  236. public static String GenerateSignatureUsingHash(String key, String data)
  237. {
  238. if (String.IsNullOrEmpty(data))
  239. {
  240. throw new ArgumentNullException("data");
  241. }
  242. HMACSHA1 hash = new HMACSHA1();
  243. hash.Key = OAuth1Client.GenerateSignatureEncoding.GetBytes(key);
  244. byte[] dataBuffer = OAuth1Client.GenerateSignatureEncoding.GetBytes(data);
  245. byte[] hashBytes = hash.ComputeHash(dataBuffer);
  246. return Convert.ToBase64String(hashBytes);
  247. }
  248. #endif
  249. /// <summary>
  250. ///
  251. /// </summary>
  252. /// <param name="url"></param>
  253. /// <param name="command"></param>
  254. /// <returns></returns>
  255. public static SignatureInfo GenerateSignature(Uri url, GetRequestTokenCommand command)
  256. {
  257. return GenerateSignature(url, command, OAuthSignatureTypes.HMACSHA1);
  258. }
  259. /// <summary>
  260. /// Generate the timestamp for the signature
  261. /// </summary>
  262. /// <returns></returns>
  263. internal static String GenerateTimeStamp()
  264. {
  265. // Default implementation of UNIX time of the current UTC time
  266. TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
  267. return Convert.ToInt64(ts.TotalSeconds).ToString();
  268. }
  269. /// <summary>
  270. ///
  271. /// </summary>
  272. /// <returns></returns>
  273. internal static String GenerateNonce()
  274. {
  275. return GenerateNonce1();
  276. }
  277. /// <summary>
  278. /// Generate a nonce
  279. /// </summary>
  280. /// <returns></returns>
  281. private static String GenerateNonce0()
  282. {
  283. // Just a simple implementation of a random number between 123400 and 9999999
  284. return Random.Next(123400, 9999999).ToString();
  285. }
  286. /// <summary>
  287. ///
  288. /// </summary>
  289. /// <returns></returns>
  290. private static String GenerateNonce1()
  291. {
  292. String letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  293. StringBuilder result = new StringBuilder(8);
  294. Random random = new Random();
  295. for (int i = 0; i < 8; ++i)
  296. {
  297. result.Append(letters[random.Next(letters.Length)]);
  298. }
  299. return result.ToString();
  300. }
  301. }
  302. }