credentials_provider_sts.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/auth/credentials.h>
  6. #include <aws/auth/private/credentials_utils.h>
  7. #include <aws/auth/signable.h>
  8. #include <aws/auth/signing.h>
  9. #include <aws/auth/signing_config.h>
  10. #include <aws/auth/signing_result.h>
  11. #include <aws/common/xml_parser.h>
  12. #include <aws/common/clock.h>
  13. #include <aws/common/string.h>
  14. #include <aws/http/connection.h>
  15. #include <aws/http/connection_manager.h>
  16. #include <aws/http/request_response.h>
  17. #include <aws/http/status_code.h>
  18. #include <aws/io/channel_bootstrap.h>
  19. #include <aws/io/retry_strategy.h>
  20. #include <aws/io/socket.h>
  21. #include <aws/io/stream.h>
  22. #include <aws/io/tls_channel_handler.h>
  23. #include <aws/io/uri.h>
  24. #include <inttypes.h>
  25. #ifdef _MSC_VER
  26. /* allow non-constant declared initializers. */
  27. # pragma warning(disable : 4204)
  28. /* allow passing of address of automatic variable */
  29. # pragma warning(disable : 4221)
  30. /* function pointer to dll symbol */
  31. # pragma warning(disable : 4232)
  32. #endif
  33. static struct aws_http_header s_host_header = {
  34. .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("host"),
  35. .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("sts.amazonaws.com"),
  36. };
  37. static struct aws_http_header s_content_type_header = {
  38. .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("content-type"),
  39. .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("application/x-www-form-urlencoded"),
  40. };
  41. static struct aws_byte_cursor s_content_length = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("content-length");
  42. static struct aws_byte_cursor s_path = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/");
  43. static struct aws_byte_cursor s_signing_region = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("us-east-1");
  44. static struct aws_byte_cursor s_service_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("sts");
  45. static struct aws_byte_cursor s_assume_role_root_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("AssumeRoleResponse");
  46. static struct aws_byte_cursor s_assume_role_result_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("AssumeRoleResult");
  47. static struct aws_byte_cursor s_assume_role_credentials_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Credentials");
  48. static struct aws_byte_cursor s_assume_role_session_token_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("SessionToken");
  49. static struct aws_byte_cursor s_assume_role_secret_key_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("SecretAccessKey");
  50. static struct aws_byte_cursor s_assume_role_access_key_id_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("AccessKeyId");
  51. static const int s_max_retries = 8;
  52. const uint16_t aws_sts_assume_role_default_duration_secs = 900;
  53. struct aws_credentials_provider_sts_impl {
  54. struct aws_http_connection_manager *connection_manager;
  55. struct aws_string *assume_role_profile;
  56. struct aws_string *role_session_name;
  57. uint16_t duration_seconds;
  58. struct aws_credentials_provider *provider;
  59. struct aws_credentials_provider_shutdown_options source_shutdown_options;
  60. const struct aws_auth_http_system_vtable *function_table;
  61. struct aws_retry_strategy *retry_strategy;
  62. aws_io_clock_fn *system_clock_fn;
  63. };
  64. struct sts_creds_provider_user_data {
  65. struct aws_allocator *allocator;
  66. struct aws_credentials_provider *provider;
  67. struct aws_credentials *credentials;
  68. struct aws_string *access_key_id;
  69. struct aws_string *secret_access_key;
  70. struct aws_string *session_token;
  71. aws_on_get_credentials_callback_fn *callback;
  72. struct aws_http_connection *connection;
  73. struct aws_byte_buf payload_body;
  74. struct aws_input_stream *input_stream;
  75. struct aws_signable *signable;
  76. struct aws_signing_config_aws signing_config;
  77. struct aws_http_message *message;
  78. struct aws_byte_buf output_buf;
  79. struct aws_retry_token *retry_token;
  80. int error_code;
  81. void *user_data;
  82. };
  83. static void s_reset_request_specific_data(struct sts_creds_provider_user_data *user_data) {
  84. if (user_data->connection) {
  85. struct aws_credentials_provider_sts_impl *provider_impl = user_data->provider->impl;
  86. provider_impl->function_table->aws_http_connection_manager_release_connection(
  87. provider_impl->connection_manager, user_data->connection);
  88. user_data->connection = NULL;
  89. }
  90. if (user_data->signable) {
  91. aws_signable_destroy(user_data->signable);
  92. user_data->signable = NULL;
  93. }
  94. if (user_data->input_stream) {
  95. aws_input_stream_destroy(user_data->input_stream);
  96. user_data->input_stream = NULL;
  97. }
  98. aws_byte_buf_clean_up(&user_data->payload_body);
  99. if (user_data->message) {
  100. aws_http_message_destroy(user_data->message);
  101. user_data->message = NULL;
  102. }
  103. aws_byte_buf_clean_up(&user_data->output_buf);
  104. aws_string_destroy(user_data->access_key_id);
  105. user_data->access_key_id = NULL;
  106. aws_string_destroy_secure(user_data->secret_access_key);
  107. user_data->secret_access_key = NULL;
  108. aws_string_destroy(user_data->session_token);
  109. user_data->session_token = NULL;
  110. }
  111. static void s_clean_up_user_data(struct sts_creds_provider_user_data *user_data) {
  112. user_data->callback(user_data->credentials, user_data->error_code, user_data->user_data);
  113. aws_credentials_release(user_data->credentials);
  114. s_reset_request_specific_data(user_data);
  115. aws_credentials_provider_release(user_data->provider);
  116. aws_retry_token_release(user_data->retry_token);
  117. aws_mem_release(user_data->allocator, user_data);
  118. }
  119. static int s_write_body_to_buffer(struct aws_credentials_provider *provider, struct aws_byte_buf *body) {
  120. struct aws_credentials_provider_sts_impl *provider_impl = provider->impl;
  121. struct aws_byte_cursor working_cur = aws_byte_cursor_from_c_str("Version=2011-06-15&Action=AssumeRole&RoleArn=");
  122. if (aws_byte_buf_append_dynamic(body, &working_cur)) {
  123. return AWS_OP_ERR;
  124. }
  125. struct aws_byte_cursor role_cur = aws_byte_cursor_from_string(provider_impl->assume_role_profile);
  126. if (aws_byte_buf_append_encoding_uri_param(body, &role_cur)) {
  127. return AWS_OP_ERR;
  128. }
  129. working_cur = aws_byte_cursor_from_c_str("&RoleSessionName=");
  130. if (aws_byte_buf_append_dynamic(body, &working_cur)) {
  131. return AWS_OP_ERR;
  132. }
  133. struct aws_byte_cursor session_cur = aws_byte_cursor_from_string(provider_impl->role_session_name);
  134. if (aws_byte_buf_append_encoding_uri_param(body, &session_cur)) {
  135. return AWS_OP_ERR;
  136. }
  137. working_cur = aws_byte_cursor_from_c_str("&DurationSeconds=");
  138. if (aws_byte_buf_append_dynamic(body, &working_cur)) {
  139. return AWS_OP_ERR;
  140. }
  141. char duration_seconds[6];
  142. AWS_ZERO_ARRAY(duration_seconds);
  143. snprintf(duration_seconds, sizeof(duration_seconds), "%" PRIu16, provider_impl->duration_seconds);
  144. working_cur = aws_byte_cursor_from_c_str(duration_seconds);
  145. if (aws_byte_buf_append_dynamic(body, &working_cur)) {
  146. return AWS_OP_ERR;
  147. }
  148. return AWS_OP_SUCCESS;
  149. }
  150. static int s_on_incoming_body_fn(struct aws_http_stream *stream, const struct aws_byte_cursor *data, void *user_data) {
  151. (void)stream;
  152. struct sts_creds_provider_user_data *provider_user_data = user_data;
  153. return aws_byte_buf_append_dynamic(&provider_user_data->output_buf, data);
  154. }
  155. /* parse doc of form
  156. <AssumeRoleResponse>
  157. <AssumeRoleResult>
  158. <Credentials>
  159. <AccessKeyId>accessKeyId</AccessKeyId>
  160. <SecretKey>secretKey</SecretKey>
  161. <SessionToken>sessionToken</SessionToken>
  162. </Credentials>
  163. <AssumedRoleUser>
  164. ... more stuff we don't care about.
  165. </AssumedRoleUser>
  166. ... more stuff we don't care about
  167. </AssumeRoleResult>
  168. </AssumeRoleResponse>
  169. */
  170. static bool s_on_node_encountered_fn(struct aws_xml_parser *parser, struct aws_xml_node *node, void *user_data) {
  171. struct aws_byte_cursor node_name;
  172. AWS_ZERO_STRUCT(node_name);
  173. if (aws_xml_node_get_name(node, &node_name)) {
  174. AWS_LOGF_ERROR(
  175. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  176. "(id=%p): While parsing credentials xml response for sts credentials provider, could not get xml node name "
  177. "for function s_on_node_encountered_fn.",
  178. user_data);
  179. return false;
  180. }
  181. if (aws_byte_cursor_eq_ignore_case(&node_name, &s_assume_role_root_name) ||
  182. aws_byte_cursor_eq_ignore_case(&node_name, &s_assume_role_result_name) ||
  183. aws_byte_cursor_eq_ignore_case(&node_name, &s_assume_role_credentials_name)) {
  184. return aws_xml_node_traverse(parser, node, s_on_node_encountered_fn, user_data);
  185. }
  186. struct sts_creds_provider_user_data *provider_user_data = user_data;
  187. struct aws_byte_cursor credential_data;
  188. AWS_ZERO_STRUCT(credential_data);
  189. if (aws_byte_cursor_eq_ignore_case(&node_name, &s_assume_role_access_key_id_name)) {
  190. aws_xml_node_as_body(parser, node, &credential_data);
  191. provider_user_data->access_key_id =
  192. aws_string_new_from_array(provider_user_data->allocator, credential_data.ptr, credential_data.len);
  193. if (provider_user_data->access_key_id) {
  194. AWS_LOGF_DEBUG(
  195. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  196. "(id=%p): Read AccessKeyId %s",
  197. (void *)provider_user_data->provider,
  198. aws_string_c_str(provider_user_data->access_key_id));
  199. }
  200. }
  201. if (aws_byte_cursor_eq_ignore_case(&node_name, &s_assume_role_secret_key_name)) {
  202. aws_xml_node_as_body(parser, node, &credential_data);
  203. provider_user_data->secret_access_key =
  204. aws_string_new_from_array(provider_user_data->allocator, credential_data.ptr, credential_data.len);
  205. }
  206. if (aws_byte_cursor_eq_ignore_case(&node_name, &s_assume_role_session_token_name)) {
  207. aws_xml_node_as_body(parser, node, &credential_data);
  208. provider_user_data->session_token =
  209. aws_string_new_from_array(provider_user_data->allocator, credential_data.ptr, credential_data.len);
  210. }
  211. return true;
  212. }
  213. static void s_start_make_request(
  214. struct aws_credentials_provider *provider,
  215. struct sts_creds_provider_user_data *provider_user_data);
  216. static void s_on_retry_ready(struct aws_retry_token *token, int error_code, void *user_data) {
  217. (void)token;
  218. struct sts_creds_provider_user_data *provider_user_data = user_data;
  219. if (!error_code) {
  220. s_start_make_request(provider_user_data->provider, provider_user_data);
  221. } else {
  222. AWS_LOGF_ERROR(
  223. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  224. "(id=%p): retry task failed: %s",
  225. (void *)provider_user_data->provider,
  226. aws_error_str(aws_last_error()));
  227. s_clean_up_user_data(provider_user_data);
  228. }
  229. }
  230. /* called upon completion of http request */
  231. static void s_on_stream_complete_fn(struct aws_http_stream *stream, int error_code, void *user_data) {
  232. int http_response_code = 0;
  233. struct sts_creds_provider_user_data *provider_user_data = user_data;
  234. struct aws_credentials_provider_sts_impl *provider_impl = provider_user_data->provider->impl;
  235. struct aws_xml_parser *xml_parser = NULL;
  236. provider_user_data->error_code = error_code;
  237. if (provider_impl->function_table->aws_http_stream_get_incoming_response_status(stream, &http_response_code)) {
  238. goto finish;
  239. }
  240. if (http_response_code != 200) {
  241. provider_user_data->error_code = AWS_AUTH_CREDENTIALS_PROVIDER_HTTP_STATUS_FAILURE;
  242. }
  243. provider_impl->function_table->aws_http_stream_release(stream);
  244. AWS_LOGF_DEBUG(
  245. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  246. "(id=%p): AssumeRole call completed with http status %d",
  247. (void *)provider_user_data->provider,
  248. http_response_code);
  249. if (error_code || http_response_code != AWS_HTTP_STATUS_CODE_200_OK) {
  250. /* prevent connection reuse. */
  251. provider_impl->function_table->aws_http_connection_close(provider_user_data->connection);
  252. enum aws_retry_error_type error_type =
  253. aws_credentials_provider_compute_retry_error_type(http_response_code, error_code);
  254. s_reset_request_specific_data(provider_user_data);
  255. /* don't retry client errors at all. */
  256. if (error_type != AWS_RETRY_ERROR_TYPE_CLIENT_ERROR) {
  257. if (aws_retry_strategy_schedule_retry(
  258. provider_user_data->retry_token, error_type, s_on_retry_ready, provider_user_data)) {
  259. AWS_LOGF_ERROR(
  260. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  261. "(id=%p): failed to schedule retry: %s",
  262. (void *)provider_user_data->provider,
  263. aws_error_str(aws_last_error()));
  264. goto finish;
  265. }
  266. return;
  267. }
  268. }
  269. if (!error_code && http_response_code == AWS_HTTP_STATUS_CODE_200_OK) {
  270. /* update the book keeping so we can let the retry strategy make determinations about when the service is
  271. * healthy after an outage. */
  272. if (aws_retry_token_record_success(provider_user_data->retry_token)) {
  273. AWS_LOGF_ERROR(
  274. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  275. "(id=%p): failed to register operation success: %s",
  276. (void *)provider_user_data->provider,
  277. aws_error_str(aws_last_error()));
  278. goto finish;
  279. }
  280. struct aws_xml_parser_options options;
  281. AWS_ZERO_STRUCT(options);
  282. options.doc = aws_byte_cursor_from_buf(&provider_user_data->output_buf);
  283. xml_parser = aws_xml_parser_new(provider_user_data->provider->allocator, &options);
  284. if (xml_parser == NULL) {
  285. goto finish;
  286. }
  287. uint64_t now = UINT64_MAX;
  288. if (provider_impl->system_clock_fn(&now) != AWS_OP_SUCCESS) {
  289. goto finish;
  290. }
  291. uint64_t now_seconds = aws_timestamp_convert(now, AWS_TIMESTAMP_NANOS, AWS_TIMESTAMP_SECS, NULL);
  292. if (aws_xml_parser_parse(xml_parser, s_on_node_encountered_fn, provider_user_data)) {
  293. provider_user_data->error_code = aws_last_error();
  294. AWS_LOGF_ERROR(
  295. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  296. "(id=%p): credentials parsing failed with error %s",
  297. (void *)provider_user_data->credentials,
  298. aws_error_debug_str(provider_user_data->error_code));
  299. goto finish;
  300. }
  301. if (provider_user_data->access_key_id && provider_user_data->secret_access_key &&
  302. provider_user_data->session_token) {
  303. provider_user_data->credentials = aws_credentials_new_from_string(
  304. provider_user_data->allocator,
  305. provider_user_data->access_key_id,
  306. provider_user_data->secret_access_key,
  307. provider_user_data->session_token,
  308. now_seconds + provider_impl->duration_seconds);
  309. } else {
  310. AWS_LOGF_ERROR(
  311. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  312. "(id=%p): credentials document was corrupted, treating as an error.",
  313. (void *)provider_user_data->provider);
  314. }
  315. }
  316. finish:
  317. if (xml_parser != NULL) {
  318. aws_xml_parser_destroy(xml_parser);
  319. xml_parser = NULL;
  320. }
  321. s_clean_up_user_data(provider_user_data);
  322. }
  323. /* called upon acquiring a connection from the pool */
  324. static void s_on_connection_setup_fn(struct aws_http_connection *connection, int error_code, void *user_data) {
  325. struct sts_creds_provider_user_data *provider_user_data = user_data;
  326. struct aws_credentials_provider_sts_impl *provider_impl = provider_user_data->provider->impl;
  327. struct aws_http_stream *stream = NULL;
  328. AWS_LOGF_DEBUG(
  329. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  330. "(id=%p): connection returned with error code %d",
  331. (void *)provider_user_data->provider,
  332. error_code);
  333. if (error_code) {
  334. aws_raise_error(error_code);
  335. goto error;
  336. }
  337. provider_user_data->connection = connection;
  338. if (aws_byte_buf_init(&provider_user_data->output_buf, provider_impl->provider->allocator, 2048)) {
  339. goto error;
  340. }
  341. struct aws_http_make_request_options options = {
  342. .user_data = user_data,
  343. .request = provider_user_data->message,
  344. .self_size = sizeof(struct aws_http_make_request_options),
  345. .on_response_headers = NULL,
  346. .on_response_header_block_done = NULL,
  347. .on_response_body = s_on_incoming_body_fn,
  348. .on_complete = s_on_stream_complete_fn,
  349. };
  350. stream = provider_impl->function_table->aws_http_connection_make_request(connection, &options);
  351. if (!stream) {
  352. goto error;
  353. }
  354. if (provider_impl->function_table->aws_http_stream_activate(stream)) {
  355. goto error;
  356. }
  357. return;
  358. error:
  359. provider_impl->function_table->aws_http_stream_release(stream);
  360. s_clean_up_user_data(provider_user_data);
  361. }
  362. /* called once sigv4 signing is complete. */
  363. void s_on_signing_complete(struct aws_signing_result *result, int error_code, void *userdata) {
  364. struct sts_creds_provider_user_data *provider_user_data = userdata;
  365. struct aws_credentials_provider_sts_impl *sts_impl = provider_user_data->provider->impl;
  366. AWS_LOGF_DEBUG(
  367. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  368. "(id=%p): signing completed with error code %d",
  369. (void *)provider_user_data->provider,
  370. error_code);
  371. if (error_code) {
  372. aws_raise_error(error_code);
  373. goto error;
  374. }
  375. if (aws_apply_signing_result_to_http_request(
  376. provider_user_data->message, provider_user_data->provider->allocator, result)) {
  377. goto error;
  378. }
  379. sts_impl->function_table->aws_http_connection_manager_acquire_connection(
  380. sts_impl->connection_manager, s_on_connection_setup_fn, provider_user_data);
  381. return;
  382. error:
  383. s_clean_up_user_data(provider_user_data);
  384. }
  385. static void s_start_make_request(
  386. struct aws_credentials_provider *provider,
  387. struct sts_creds_provider_user_data *provider_user_data) {
  388. provider_user_data->message = aws_http_message_new_request(provider->allocator);
  389. if (!provider_user_data->message) {
  390. goto error;
  391. }
  392. if (aws_http_message_add_header(provider_user_data->message, s_host_header)) {
  393. goto error;
  394. }
  395. if (aws_http_message_add_header(provider_user_data->message, s_content_type_header)) {
  396. goto error;
  397. }
  398. if (aws_byte_buf_init(&provider_user_data->payload_body, provider->allocator, 256)) {
  399. goto error;
  400. }
  401. if (s_write_body_to_buffer(provider, &provider_user_data->payload_body)) {
  402. goto error;
  403. }
  404. char content_length[21];
  405. AWS_ZERO_ARRAY(content_length);
  406. snprintf(content_length, sizeof(content_length), "%" PRIu64, (uint64_t)provider_user_data->payload_body.len);
  407. struct aws_http_header content_len_header = {
  408. .name = s_content_length,
  409. .value = aws_byte_cursor_from_c_str(content_length),
  410. };
  411. if (aws_http_message_add_header(provider_user_data->message, content_len_header)) {
  412. goto error;
  413. }
  414. struct aws_byte_cursor payload_cur = aws_byte_cursor_from_buf(&provider_user_data->payload_body);
  415. provider_user_data->input_stream =
  416. aws_input_stream_new_from_cursor(provider_user_data->provider->allocator, &payload_cur);
  417. if (!provider_user_data->input_stream) {
  418. goto error;
  419. }
  420. aws_http_message_set_body_stream(provider_user_data->message, provider_user_data->input_stream);
  421. if (aws_http_message_set_request_method(provider_user_data->message, aws_http_method_post)) {
  422. goto error;
  423. }
  424. if (aws_http_message_set_request_path(provider_user_data->message, s_path)) {
  425. goto error;
  426. }
  427. provider_user_data->signable = aws_signable_new_http_request(provider->allocator, provider_user_data->message);
  428. if (!provider_user_data->signable) {
  429. goto error;
  430. }
  431. struct aws_credentials_provider_sts_impl *impl = provider->impl;
  432. provider_user_data->signing_config.algorithm = AWS_SIGNING_ALGORITHM_V4;
  433. provider_user_data->signing_config.signature_type = AWS_ST_HTTP_REQUEST_HEADERS;
  434. provider_user_data->signing_config.signed_body_header = AWS_SBHT_NONE;
  435. provider_user_data->signing_config.config_type = AWS_SIGNING_CONFIG_AWS;
  436. provider_user_data->signing_config.credentials_provider = impl->provider;
  437. aws_date_time_init_now(&provider_user_data->signing_config.date);
  438. provider_user_data->signing_config.region = s_signing_region;
  439. provider_user_data->signing_config.service = s_service_name;
  440. provider_user_data->signing_config.flags.use_double_uri_encode = false;
  441. if (aws_sign_request_aws(
  442. provider->allocator,
  443. provider_user_data->signable,
  444. (struct aws_signing_config_base *)&provider_user_data->signing_config,
  445. s_on_signing_complete,
  446. provider_user_data)) {
  447. goto error;
  448. }
  449. return;
  450. error:
  451. AWS_LOGF_ERROR(
  452. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  453. "(id=%p): error occurred while creating an http request for signing: %s",
  454. (void *)provider_user_data->provider,
  455. aws_error_debug_str(aws_last_error()));
  456. if (provider_user_data) {
  457. s_clean_up_user_data(provider_user_data);
  458. } else {
  459. provider_user_data->callback(NULL, provider_user_data->error_code, provider_user_data->user_data);
  460. }
  461. }
  462. static void s_on_retry_token_acquired(
  463. struct aws_retry_strategy *strategy,
  464. int error_code,
  465. struct aws_retry_token *token,
  466. void *user_data) {
  467. (void)strategy;
  468. struct sts_creds_provider_user_data *provider_user_data = user_data;
  469. if (!error_code) {
  470. provider_user_data->retry_token = token;
  471. s_start_make_request(provider_user_data->provider, provider_user_data);
  472. } else {
  473. AWS_LOGF_ERROR(
  474. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  475. "(id=%p): failed to acquire retry token: %s",
  476. (void *)provider_user_data->provider,
  477. aws_error_debug_str(error_code));
  478. s_clean_up_user_data(provider_user_data);
  479. }
  480. }
  481. static int s_sts_get_creds(
  482. struct aws_credentials_provider *provider,
  483. aws_on_get_credentials_callback_fn callback,
  484. void *user_data) {
  485. struct aws_credentials_provider_sts_impl *impl = provider->impl;
  486. AWS_LOGF_DEBUG(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "(id=%p): fetching credentials", (void *)provider);
  487. struct sts_creds_provider_user_data *provider_user_data =
  488. aws_mem_calloc(provider->allocator, 1, sizeof(struct sts_creds_provider_user_data));
  489. if (!provider_user_data) {
  490. AWS_LOGF_ERROR(
  491. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  492. "(id=%p): error occurred while allocating memory: %s",
  493. (void *)provider,
  494. aws_error_debug_str(aws_last_error()));
  495. callback(NULL, aws_last_error(), user_data);
  496. return AWS_OP_ERR;
  497. }
  498. provider_user_data->allocator = provider->allocator;
  499. provider_user_data->provider = provider;
  500. aws_credentials_provider_acquire(provider);
  501. provider_user_data->callback = callback;
  502. provider_user_data->user_data = user_data;
  503. if (aws_retry_strategy_acquire_retry_token(
  504. impl->retry_strategy, NULL, s_on_retry_token_acquired, provider_user_data, 100)) {
  505. AWS_LOGF_ERROR(
  506. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  507. "(id=%p): failed to acquire retry token: %s",
  508. (void *)provider_user_data->provider,
  509. aws_error_debug_str(aws_last_error()));
  510. callback(NULL, aws_last_error(), user_data);
  511. s_clean_up_user_data(user_data);
  512. return AWS_OP_ERR;
  513. }
  514. return AWS_OP_SUCCESS;
  515. }
  516. static void s_on_credentials_provider_shutdown(void *user_data) {
  517. struct aws_credentials_provider *provider = user_data;
  518. if (provider == NULL) {
  519. return;
  520. }
  521. struct aws_credentials_provider_sts_impl *impl = provider->impl;
  522. if (impl == NULL) {
  523. return;
  524. }
  525. /* The wrapped provider has shut down, invoke its shutdown callback if there was one */
  526. if (impl->source_shutdown_options.shutdown_callback != NULL) {
  527. impl->source_shutdown_options.shutdown_callback(impl->source_shutdown_options.shutdown_user_data);
  528. }
  529. /* Invoke our own shutdown callback */
  530. aws_credentials_provider_invoke_shutdown_callback(provider);
  531. aws_string_destroy(impl->role_session_name);
  532. aws_string_destroy(impl->assume_role_profile);
  533. aws_mem_release(provider->allocator, provider);
  534. }
  535. void s_destroy(struct aws_credentials_provider *provider) {
  536. AWS_LOGF_TRACE(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "(id=%p): cleaning up credentials provider", (void *)provider);
  537. struct aws_credentials_provider_sts_impl *sts_impl = provider->impl;
  538. if (sts_impl->connection_manager) {
  539. sts_impl->function_table->aws_http_connection_manager_release(sts_impl->connection_manager);
  540. }
  541. aws_retry_strategy_release(sts_impl->retry_strategy);
  542. aws_credentials_provider_release(sts_impl->provider);
  543. }
  544. static struct aws_credentials_provider_vtable s_aws_credentials_provider_sts_vtable = {
  545. .get_credentials = s_sts_get_creds,
  546. .destroy = s_destroy,
  547. };
  548. struct aws_credentials_provider *aws_credentials_provider_new_sts(
  549. struct aws_allocator *allocator,
  550. const struct aws_credentials_provider_sts_options *options) {
  551. if (!options->bootstrap) {
  552. AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "a client bootstrap is necessary for quering STS");
  553. aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  554. return NULL;
  555. }
  556. if (!options->tls_ctx) {
  557. AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "a TLS context is necessary for querying STS");
  558. aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  559. return NULL;
  560. }
  561. struct aws_credentials_provider *provider = NULL;
  562. struct aws_credentials_provider_sts_impl *impl = NULL;
  563. aws_mem_acquire_many(
  564. allocator,
  565. 2,
  566. &provider,
  567. sizeof(struct aws_credentials_provider),
  568. &impl,
  569. sizeof(struct aws_credentials_provider_sts_impl));
  570. AWS_LOGF_DEBUG(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "static: creating STS credentials provider");
  571. if (!provider) {
  572. return NULL;
  573. }
  574. AWS_ZERO_STRUCT(*provider);
  575. AWS_ZERO_STRUCT(*impl);
  576. aws_credentials_provider_init_base(provider, allocator, &s_aws_credentials_provider_sts_vtable, impl);
  577. impl->function_table = g_aws_credentials_provider_http_function_table;
  578. if (options->function_table) {
  579. impl->function_table = options->function_table;
  580. }
  581. struct aws_tls_connection_options tls_connection_options;
  582. AWS_ZERO_STRUCT(tls_connection_options);
  583. if (!options->creds_provider) {
  584. AWS_LOGF_ERROR(
  585. AWS_LS_AUTH_CREDENTIALS_PROVIDER, "(id=%p): A credentials provider must be specified", (void *)provider);
  586. aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  587. goto cleanup_provider;
  588. }
  589. impl->role_session_name =
  590. aws_string_new_from_array(allocator, options->session_name.ptr, options->session_name.len);
  591. if (!impl->role_session_name) {
  592. goto cleanup_provider;
  593. }
  594. AWS_LOGF_DEBUG(
  595. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  596. "(id=%p): using session_name %s",
  597. (void *)provider,
  598. aws_string_c_str(impl->role_session_name));
  599. impl->assume_role_profile = aws_string_new_from_array(allocator, options->role_arn.ptr, options->role_arn.len);
  600. if (!impl->assume_role_profile) {
  601. goto cleanup_provider;
  602. }
  603. AWS_LOGF_DEBUG(
  604. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  605. "(id=%p): using assume_role_arn %s",
  606. (void *)provider,
  607. aws_string_c_str(impl->assume_role_profile));
  608. impl->duration_seconds = options->duration_seconds;
  609. if (options->system_clock_fn != NULL) {
  610. impl->system_clock_fn = options->system_clock_fn;
  611. } else {
  612. impl->system_clock_fn = aws_sys_clock_get_ticks;
  613. }
  614. /* minimum for STS is 900 seconds*/
  615. if (impl->duration_seconds < aws_sts_assume_role_default_duration_secs) {
  616. impl->duration_seconds = aws_sts_assume_role_default_duration_secs;
  617. }
  618. AWS_LOGF_DEBUG(
  619. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  620. "(id=%p): using credentials duration %" PRIu16,
  621. (void *)provider,
  622. impl->duration_seconds);
  623. impl->provider = options->creds_provider;
  624. aws_credentials_provider_acquire(impl->provider);
  625. aws_tls_connection_options_init_from_ctx(&tls_connection_options, options->tls_ctx);
  626. if (aws_tls_connection_options_set_server_name(&tls_connection_options, allocator, &s_host_header.value)) {
  627. AWS_LOGF_ERROR(
  628. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  629. "(id=%p): failed to create a tls connection options with error %s",
  630. (void *)provider,
  631. aws_error_debug_str(aws_last_error()));
  632. goto cleanup_provider;
  633. }
  634. struct aws_socket_options socket_options = {
  635. .type = AWS_SOCKET_STREAM,
  636. .domain = AWS_SOCKET_IPV6,
  637. .connect_timeout_ms = 3000,
  638. };
  639. struct aws_http_connection_manager_options connection_manager_options = {
  640. .bootstrap = options->bootstrap,
  641. .host = s_host_header.value,
  642. .initial_window_size = SIZE_MAX,
  643. .max_connections = 2,
  644. .port = 443,
  645. .socket_options = &socket_options,
  646. .tls_connection_options = &tls_connection_options,
  647. .proxy_options = options->http_proxy_options,
  648. };
  649. impl->connection_manager =
  650. impl->function_table->aws_http_connection_manager_new(allocator, &connection_manager_options);
  651. if (!impl->connection_manager) {
  652. AWS_LOGF_ERROR(
  653. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  654. "(id=%p): failed to create a connection manager with error %s",
  655. (void *)provider,
  656. aws_error_debug_str(aws_last_error()));
  657. goto cleanup_provider;
  658. }
  659. /*
  660. * Save the wrapped provider's shutdown callback and then swap it with our own.
  661. */
  662. impl->source_shutdown_options = impl->provider->shutdown_options;
  663. impl->provider->shutdown_options.shutdown_callback = s_on_credentials_provider_shutdown;
  664. impl->provider->shutdown_options.shutdown_user_data = provider;
  665. provider->shutdown_options = options->shutdown_options;
  666. struct aws_standard_retry_options retry_options = {
  667. .backoff_retry_options =
  668. {
  669. .el_group = options->bootstrap->event_loop_group,
  670. .max_retries = s_max_retries,
  671. },
  672. };
  673. impl->retry_strategy = aws_retry_strategy_new_standard(allocator, &retry_options);
  674. if (!impl->retry_strategy) {
  675. AWS_LOGF_ERROR(
  676. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  677. "(id=%p): failed to create a retry strategy with error %s",
  678. (void *)provider,
  679. aws_error_debug_str(aws_last_error()));
  680. goto cleanup_provider;
  681. }
  682. aws_tls_connection_options_clean_up(&tls_connection_options);
  683. return provider;
  684. cleanup_provider:
  685. aws_tls_connection_options_clean_up(&tls_connection_options);
  686. aws_credentials_provider_release(provider);
  687. return NULL;
  688. }