PageRenderTime 26ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/backwpup/sdk/Aws_v1/authentication/signature_v4json.class.php

https://bitbucket.org/cesarmedrano/cesarmedrano
PHP | 349 lines | 177 code | 49 blank | 123 comment | 12 complexity | e995d3d72d16b62f65580f94f688b968 MD5 | raw file
  1. <?php
  2. /*
  3. * Copyright 2010-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License").
  6. * You may not use this file except in compliance with the License.
  7. * A copy of the License is located at
  8. *
  9. * http://aws.amazon.com/apache2.0
  10. *
  11. * or in the "license" file accompanying this file. This file is distributed
  12. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  13. * express or implied. See the License for the specific language governing
  14. * permissions and limitations under the License.
  15. */
  16. /*%******************************************************************************************%*/
  17. // CLASS
  18. /**
  19. * Implements support for Signature v4 (Query).
  20. *
  21. * @version 2011.01.03
  22. * @license See the included NOTICE.md file for more information.
  23. * @copyright See the included NOTICE.md file for more information.
  24. * @link http://aws.amazon.com/php/ PHP Developer Center
  25. */
  26. class AuthV4JSON extends Signer implements Signable
  27. {
  28. /**
  29. * Constructs a new instance of the <AuthV4Query> class.
  30. *
  31. * @param string $endpoint (Required) The endpoint to direct the request to.
  32. * @param string $operation (Required) The operation to execute as a result of this request.
  33. * @param array $payload (Required) The options to use as part of the payload in the request.
  34. * @param CFCredential $credentials (Required) The credentials to use for signing and making requests.
  35. * @return void
  36. */
  37. public function __construct($endpoint, $operation, $payload, CFCredential $credentials)
  38. {
  39. parent::__construct($endpoint, $operation, $payload, $credentials);
  40. }
  41. /**
  42. * Generates a cURL handle with all of the required authentication bits set.
  43. *
  44. * @return resource A cURL handle ready for executing.
  45. */
  46. public function authenticate()
  47. {
  48. // Determine signing values
  49. $current_time = time();
  50. $timestamp = gmdate(CFUtilities::DATE_FORMAT_SIGV4, $current_time);
  51. // Initialize
  52. $x_amz_target = null;
  53. $this->headers = array();
  54. $this->signed_headers = array();
  55. $this->canonical_headers = array();
  56. $this->query = array();
  57. // Prepare JSON structure
  58. $this->body = json_encode($this->payload);
  59. if ($this->body === '' || $this->body === '[]')
  60. {
  61. $this->body = '{}';
  62. }
  63. // Do we have an authentication token?
  64. if ($this->auth_token)
  65. {
  66. $this->headers['X-Amz-Security-Token'] = $this->auth_token;
  67. $this->query['SecurityToken'] = $this->auth_token;
  68. }
  69. // Manage the key-value pairs that are used in the query.
  70. if (stripos($this->operation, 'x-amz-target') !== false)
  71. {
  72. $x_amz_target = trim(str_ireplace('x-amz-target:', '', $this->operation));
  73. }
  74. else
  75. {
  76. $this->query['Action'] = $this->operation;
  77. }
  78. // Only add it if it exists.
  79. if ($this->api_version)
  80. {
  81. $this->query['Version'] = $this->api_version;
  82. }
  83. // Do a case-sensitive, natural order sort on the array keys.
  84. uksort($this->query, 'strcmp');
  85. // Remove the default scheme from the domain.
  86. $domain = str_replace(array('http://', 'https://'), '', $this->endpoint);
  87. // Parse our request.
  88. $parsed_url = parse_url('http://' . $domain);
  89. // Set the proper host header.
  90. if (isset($parsed_url['port']) && (integer) $parsed_url['port'] !== 80 && (integer) $parsed_url['port'] !== 443)
  91. {
  92. $host_header = strtolower($parsed_url['host']) . ':' . $parsed_url['port'];
  93. }
  94. else
  95. {
  96. $host_header = strtolower($parsed_url['host']);
  97. }
  98. // Generate the querystring from $this->query
  99. $this->querystring = $this->util->to_query_string($this->query);
  100. // Gather information to pass along to other classes.
  101. $helpers = array(
  102. 'utilities' => $this->utilities_class,
  103. 'request' => $this->request_class,
  104. 'response' => $this->response_class,
  105. );
  106. // Compose the request.
  107. $request_url = ($this->use_ssl ? 'https://' : 'http://') . $domain;
  108. $request_url .= !isset($parsed_url['path']) ? '/' : '';
  109. // Instantiate the request class
  110. $request = new $this->request_class($request_url, $this->proxy, $helpers, $this->credentials);
  111. $request->set_method('POST');
  112. $request->set_body($this->body);
  113. $this->querystring = $this->body;
  114. $content_type = (stripos($this->operation, 'StorageGateway') !== false) ? 'application/x-amz-json-1.1' : 'application/x-amz-json-1.0';
  115. $this->headers['Content-Type'] = $content_type;
  116. $this->headers['X-Amz-Target'] = $x_amz_target;
  117. // Pass along registered stream callbacks
  118. if ($this->registered_streaming_read_callback)
  119. {
  120. $request->register_streaming_read_callback($this->registered_streaming_read_callback);
  121. }
  122. if ($this->registered_streaming_write_callback)
  123. {
  124. $request->register_streaming_write_callback($this->registered_streaming_write_callback);
  125. }
  126. // Add authentication headers
  127. $this->headers['X-Amz-Date'] = $timestamp;
  128. $this->headers['Content-Length'] = strlen($this->querystring);
  129. $this->headers['Host'] = $host_header;
  130. // Sort headers
  131. uksort($this->headers, 'strnatcasecmp');
  132. // Add headers to request and compute the string to sign
  133. foreach ($this->headers as $header_key => $header_value)
  134. {
  135. // Strip line breaks and remove consecutive spaces. Services collapse whitespace in signature calculation
  136. $header_value = preg_replace('/\s+/', ' ', trim($header_value));
  137. $request->add_header($header_key, $header_value);
  138. $this->canonical_headers[] = strtolower($header_key) . ':' . $header_value;
  139. $this->signed_headers[] = strtolower($header_key);
  140. }
  141. $this->headers['Authorization'] = $this->authorization($timestamp);
  142. $request->add_header('Authorization', $this->headers['Authorization']);
  143. $request->request_headers = $this->headers;
  144. return $request;
  145. }
  146. /**
  147. * Generates the authorization string to use for the request.
  148. *
  149. * @param string $datetime (Required) The current timestamp.
  150. * @return string The authorization string.
  151. */
  152. protected function authorization($datetime)
  153. {
  154. $access_key_id = $this->key;
  155. $parts = array();
  156. $parts[] = "AWS4-HMAC-SHA256 Credential=${access_key_id}/" . $this->credential_string($datetime);
  157. $parts[] = 'SignedHeaders=' . implode(';', $this->signed_headers);
  158. $parts[] = 'Signature=' . $this->hex16($this->signature($datetime));
  159. return implode(',', $parts);
  160. }
  161. /**
  162. * Calculate the signature.
  163. *
  164. * @param string $datetime (Required) The current timestamp.
  165. * @return string The signature.
  166. */
  167. protected function signature($datetime)
  168. {
  169. $k_date = $this->hmac('AWS4' . $this->secret_key, substr($datetime, 0, 8));
  170. $k_region = $this->hmac($k_date, $this->region());
  171. $k_service = $this->hmac($k_region, $this->service());
  172. $k_credentials = $this->hmac($k_service, 'aws4_request');
  173. $signature = $this->hmac($k_credentials, $this->string_to_sign($datetime));
  174. return $signature;
  175. }
  176. /**
  177. * Calculate the string to sign.
  178. *
  179. * @param string $datetime (Required) The current timestamp.
  180. * @return string The string to sign.
  181. */
  182. protected function string_to_sign($datetime)
  183. {
  184. $parts = array();
  185. $parts[] = 'AWS4-HMAC-SHA256';
  186. $parts[] = $datetime;
  187. $parts[] = $this->credential_string($datetime);
  188. $parts[] = $this->hex16($this->hash($this->canonical_request()));
  189. $this->string_to_sign = implode("\n", $parts);
  190. return $this->string_to_sign;
  191. }
  192. /**
  193. * Generates the credential string to use for signing.
  194. *
  195. * @param string $datetime (Required) The current timestamp.
  196. * @return string The credential string.
  197. */
  198. protected function credential_string($datetime)
  199. {
  200. $parts = array();
  201. $parts[] = substr($datetime, 0, 8);
  202. $parts[] = $this->region();
  203. $parts[] = $this->service();
  204. $parts[] = 'aws4_request';
  205. return implode('/', $parts);
  206. }
  207. /**
  208. * Calculate the canonical request.
  209. *
  210. * @return string The canonical request.
  211. */
  212. protected function canonical_request()
  213. {
  214. $parts = array();
  215. $parts[] = 'POST';
  216. $parts[] = $this->canonical_uri();
  217. $parts[] = ''; // $parts[] = $this->canonical_querystring();
  218. $parts[] = implode("\n", $this->canonical_headers) . "\n";
  219. $parts[] = implode(';', $this->signed_headers);
  220. $parts[] = $this->hex16($this->hash($this->body));
  221. $this->canonical_request = implode("\n", $parts);
  222. return $this->canonical_request;
  223. }
  224. /**
  225. * The region ID to use in the signature.
  226. *
  227. * @return return The region ID.
  228. */
  229. protected function region()
  230. {
  231. $pieces = explode('.', $this->endpoint);
  232. // Handle cases with single/no region (i.e., service.amazonaws.com vs. service.region.amazonaws.com)
  233. if (count($pieces) < 4)
  234. {
  235. return 'us-east-1';
  236. }
  237. return $pieces[1];
  238. }
  239. /**
  240. * The service ID to use in the signature.
  241. *
  242. * @return return The service ID.
  243. */
  244. protected function service()
  245. {
  246. $pieces = explode('.', $this->endpoint);
  247. return $pieces[0];
  248. }
  249. /**
  250. * The request URI path.
  251. *
  252. * @return string The request URI path.
  253. */
  254. protected function canonical_uri()
  255. {
  256. return '/';
  257. }
  258. /**
  259. * The canonical query string.
  260. *
  261. * @return string The canonical query string.
  262. */
  263. protected function canonical_querystring()
  264. {
  265. if (!isset($this->canonical_querystring))
  266. {
  267. $this->canonical_querystring = $this->util->to_signable_string($this->query);
  268. }
  269. return $this->canonical_querystring;
  270. }
  271. /**
  272. * Hex16-pack the data.
  273. *
  274. * @param string $value (Required) The data to hex16 pack.
  275. * @return string The hex16-packed data.
  276. */
  277. protected function hex16($value)
  278. {
  279. $result = unpack('H*', $value);
  280. return reset($result);
  281. }
  282. /**
  283. * Applies HMAC SHA-256 encryption to the string, salted by the key.
  284. *
  285. * @return string Raw HMAC SHA-256 hashed string.
  286. */
  287. protected function hmac($key, $string)
  288. {
  289. return hash_hmac('sha256', $string, $key, true);
  290. }
  291. /**
  292. * SHA-256 hashes the string.
  293. *
  294. * @return string Raw SHA-256 hashed string.
  295. */
  296. protected function hash($string)
  297. {
  298. return hash('sha256', $string, true);
  299. }
  300. }