PageRenderTime 199ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/sdk/src/Core/Amazon.Runtime/Internal/Auth/AWS3Signer.cs

https://gitlab.com/vectorci/aws-sdk-net
C# | 299 lines | 229 code | 42 blank | 28 comment | 20 complexity | f223f564f85644fd6f8a79f8e5439596 MD5 | raw file
  1. /*
  2. * Copyright 2010-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License").
  5. * You may not use this file except in compliance with the License.
  6. * A copy of the License is located at
  7. *
  8. * http://aws.amazon.com/apache2.0
  9. *
  10. * or in the "license" file accompanying this file. This file is distributed
  11. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  12. * express or implied. See the License for the specific language governing
  13. * permissions and limitations under the License.
  14. */
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Text;
  18. using Amazon.Util;
  19. using System.Globalization;
  20. using Amazon.Runtime.Internal.Util;
  21. namespace Amazon.Runtime.Internal.Auth
  22. {
  23. public class AWS3Signer : AbstractAWSSigner
  24. {
  25. private const string HTTP_SCHEME = "AWS3";
  26. private const string HTTPS_SCHEME = "AWS3-HTTPS";
  27. private bool UseAws3Https { get; set; }
  28. public AWS3Signer(bool useAws3Https)
  29. {
  30. UseAws3Https = useAws3Https;
  31. }
  32. public AWS3Signer()
  33. : this(false)
  34. {
  35. }
  36. public override ClientProtocol Protocol
  37. {
  38. get { return ClientProtocol.RestProtocol; }
  39. }
  40. /// <summary>
  41. /// Signs the specified request with the AWS3 signing protocol by using the
  42. /// AWS account credentials given in the method parameters.
  43. /// </summary>
  44. /// <param name="awsAccessKeyId">The AWS public key</param>
  45. /// <param name="awsSecretAccessKey">The AWS secret key used to sign the request in clear text</param>
  46. /// <param name="metrics">Request metrics</param>
  47. /// <param name="clientConfig">The configuration that specifies which hashing algorithm to use</param>
  48. /// <param name="request">The request to have the signature compute for</param>
  49. /// <exception cref="Amazon.Runtime.SignatureException">If any problems are encountered while signing the request</exception>
  50. public override void Sign(IRequest request, ClientConfig clientConfig, RequestMetrics metrics, string awsAccessKeyId, string awsSecretAccessKey)
  51. {
  52. var signer = SelectSigner(request, clientConfig);
  53. var useV4 = signer is AWS4Signer;
  54. if (useV4)
  55. signer.Sign(request, clientConfig, metrics, awsAccessKeyId, awsSecretAccessKey);
  56. else
  57. {
  58. if (UseAws3Https)
  59. {
  60. SignHttps(request, clientConfig, metrics, awsAccessKeyId, awsSecretAccessKey);
  61. }
  62. else
  63. {
  64. SignHttp(request, metrics, awsAccessKeyId, awsSecretAccessKey);
  65. }
  66. }
  67. }
  68. private static void SignHttps(IRequest request, ClientConfig clientConfig, RequestMetrics metrics, string awsAccessKeyId, string awsSecretAccessKey)
  69. {
  70. string nonce = Guid.NewGuid().ToString();
  71. string date = AWSSDKUtils.FormattedCurrentTimestampRFC822;
  72. string stringToSign;
  73. stringToSign = date + nonce;
  74. metrics.AddProperty(Metric.StringToSign, stringToSign);
  75. string signature = ComputeHash(stringToSign, awsSecretAccessKey, clientConfig.SignatureMethod);
  76. StringBuilder builder = new StringBuilder();
  77. builder.Append(HTTPS_SCHEME).Append(" ");
  78. builder.Append("AWSAccessKeyId=" + awsAccessKeyId + ",");
  79. builder.Append("Algorithm=" + clientConfig.SignatureMethod.ToString() + ",");
  80. builder.Append("SignedHeaders=x-amz-date;x-amz-nonce,");
  81. builder.Append("Signature=" + signature);
  82. request.Headers[HeaderKeys.XAmzAuthorizationHeader] = builder.ToString();
  83. request.Headers[HeaderKeys.XAmzNonceHeader] = nonce;
  84. request.Headers[HeaderKeys.XAmzDateHeader] = date;
  85. }
  86. private static void SignHttp(IRequest request, RequestMetrics metrics, string awsAccessKeyId, string awsSecretAccessKey)
  87. {
  88. SigningAlgorithm algorithm = SigningAlgorithm.HmacSHA256;
  89. string nonce = Guid.NewGuid().ToString();
  90. string date = AWSSDKUtils.FormattedCurrentTimestampRFC822;
  91. bool isHttps = IsHttpsRequest(request);
  92. // Temporarily disabling the AWS3 HTTPS signing scheme and only using AWS3 HTTP
  93. isHttps = false;
  94. request.Headers[HeaderKeys.DateHeader] = date;
  95. request.Headers[HeaderKeys.XAmzDateHeader] = date;
  96. // Clear out existing auth header (can be there if retry)
  97. request.Headers.Remove(HeaderKeys.XAmzAuthorizationHeader);
  98. // AWS3 HTTP requires that we sign the Host header
  99. // so we have to have it in the request by the time we sign.
  100. string hostHeader = request.Endpoint.Host;
  101. if (!request.Endpoint.IsDefaultPort)
  102. hostHeader += ":" + request.Endpoint.Port;
  103. request.Headers[HeaderKeys.HostHeader] = hostHeader;
  104. byte[] bytesToSign = null;
  105. string stringToSign;
  106. if (isHttps)
  107. {
  108. request.Headers[HeaderKeys.XAmzNonceHeader] = nonce;
  109. stringToSign = date + nonce;
  110. bytesToSign = Encoding.UTF8.GetBytes(stringToSign);
  111. }
  112. else
  113. {
  114. Uri url = request.Endpoint;
  115. if (!string.IsNullOrEmpty(request.ResourcePath))
  116. url = new Uri(request.Endpoint, request.ResourcePath);
  117. stringToSign = request.HttpMethod + "\n"
  118. + GetCanonicalizedResourcePath(url) + "\n"
  119. + GetCanonicalizedQueryString(request.Parameters) + "\n"
  120. + GetCanonicalizedHeadersForStringToSign(request) + "\n"
  121. + GetRequestPayload(request);
  122. bytesToSign = CryptoUtilFactory.CryptoInstance.ComputeSHA256Hash(Encoding.UTF8.GetBytes(stringToSign));
  123. }
  124. metrics.AddProperty(Metric.StringToSign, stringToSign);
  125. string signature = ComputeHash(bytesToSign, awsSecretAccessKey, algorithm);
  126. StringBuilder builder = new StringBuilder();
  127. builder.Append(isHttps ? HTTPS_SCHEME : HTTP_SCHEME);
  128. builder.Append(" ");
  129. builder.Append("AWSAccessKeyId=" + awsAccessKeyId + ",");
  130. builder.Append("Algorithm=" + algorithm.ToString() + ",");
  131. if (!isHttps)
  132. {
  133. builder.Append(GetSignedHeadersComponent(request) + ",");
  134. }
  135. builder.Append("Signature=" + signature);
  136. string authorizationHeader = builder.ToString();
  137. request.Headers[HeaderKeys.XAmzAuthorizationHeader] = authorizationHeader;
  138. }
  139. #region Http signing helpers
  140. private static string GetCanonicalizedResourcePath(Uri endpoint)
  141. {
  142. string uri = endpoint.AbsolutePath;
  143. if (string.IsNullOrEmpty(uri))
  144. {
  145. return "/";
  146. }
  147. else
  148. {
  149. return AWSSDKUtils.UrlEncode(uri, true);
  150. }
  151. }
  152. private static bool IsHttpsRequest(IRequest request)
  153. {
  154. string protocol = request.Endpoint.Scheme;
  155. if (protocol.Equals("http", StringComparison.OrdinalIgnoreCase))
  156. {
  157. return false;
  158. }
  159. else if (protocol.Equals("https", StringComparison.OrdinalIgnoreCase))
  160. {
  161. return true;
  162. }
  163. else
  164. {
  165. throw new AmazonServiceException(
  166. "Unknown request endpoint protocol encountered while signing request: " + protocol);
  167. }
  168. }
  169. private static string GetCanonicalizedQueryString(IDictionary<string, string> parameters)
  170. {
  171. IDictionary<string, string> sorted =
  172. new SortedDictionary<string, string>(parameters, StringComparer.Ordinal);
  173. StringBuilder builder = new StringBuilder();
  174. foreach (var pair in sorted)
  175. {
  176. if (pair.Value != null)
  177. {
  178. string key = pair.Key;
  179. string value = pair.Value;
  180. builder.Append(AWSSDKUtils.UrlEncode(key, false));
  181. builder.Append("=");
  182. builder.Append(AWSSDKUtils.UrlEncode(value, false));
  183. builder.Append("&");
  184. }
  185. }
  186. string result = builder.ToString();
  187. return (string.IsNullOrEmpty(result) ? string.Empty : result.Substring(0, result.Length - 1));
  188. }
  189. private static string GetRequestPayload(IRequest request)
  190. {
  191. if (request.Content == null)
  192. return string.Empty;
  193. return Encoding.UTF8.GetString(request.Content, 0, request.Content.Length);
  194. }
  195. private static string GetSignedHeadersComponent(IRequest request)
  196. {
  197. StringBuilder builder = new StringBuilder();
  198. builder.Append("SignedHeaders=");
  199. bool first = true;
  200. foreach (string header in GetHeadersForStringToSign(request))
  201. {
  202. if (!first) builder.Append(";");
  203. builder.Append(header);
  204. first = false;
  205. }
  206. return builder.ToString();
  207. }
  208. private static List<string> GetHeadersForStringToSign(IRequest request)
  209. {
  210. List<string> headersToSign = new List<string>();
  211. foreach (var entry in request.Headers) {
  212. string key = entry.Key;
  213. if (key.StartsWith("x-amz", StringComparison.OrdinalIgnoreCase)
  214. || key.Equals("content-encoding", StringComparison.OrdinalIgnoreCase)
  215. || key.Equals("host", StringComparison.OrdinalIgnoreCase))
  216. {
  217. headersToSign.Add(key);
  218. }
  219. }
  220. headersToSign.Sort(StringComparer.OrdinalIgnoreCase);
  221. return headersToSign;
  222. }
  223. private static string GetCanonicalizedHeadersForStringToSign(IRequest request)
  224. {
  225. List<string> headersToSign = GetHeadersForStringToSign(request);
  226. for (int i = 0; i < headersToSign.Count; i++)
  227. {
  228. headersToSign[i] = headersToSign[i].ToLowerInvariant();
  229. }
  230. SortedDictionary<string,string> sortedHeaderMap = new SortedDictionary<string,string>();
  231. foreach (var entry in request.Headers)
  232. {
  233. if (headersToSign.Contains(entry.Key.ToLowerInvariant()))
  234. {
  235. sortedHeaderMap[entry.Key] = entry.Value;
  236. }
  237. }
  238. StringBuilder builder = new StringBuilder();
  239. foreach (var entry in sortedHeaderMap)
  240. {
  241. builder.Append(entry.Key.ToLowerInvariant());
  242. builder.Append(":");
  243. builder.Append(entry.Value);
  244. builder.Append("\n");
  245. }
  246. return builder.ToString();
  247. }
  248. #endregion
  249. }
  250. internal class AWS3HTTPSigner : AWS3Signer
  251. {
  252. public AWS3HTTPSigner()
  253. : base(false)
  254. {
  255. }
  256. }
  257. }