credentials_provider_sts_web_identity.c 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188
  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/aws_profile.h>
  7. #include <aws/auth/private/credentials_utils.h>
  8. #include <aws/common/clock.h>
  9. #include <aws/common/date_time.h>
  10. #include <aws/common/environment.h>
  11. #include <aws/common/string.h>
  12. #include <aws/common/uuid.h>
  13. #include <aws/common/xml_parser.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/file_utils.h>
  19. #include <aws/io/logging.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. #if defined(_MSC_VER)
  26. # pragma warning(disable : 4204)
  27. # pragma warning(disable : 4232)
  28. #endif /* _MSC_VER */
  29. #define STS_WEB_IDENTITY_RESPONSE_SIZE_INITIAL 2048
  30. #define STS_WEB_IDENTITY_RESPONSE_SIZE_LIMIT 10000
  31. #define STS_WEB_IDENTITY_CONNECT_TIMEOUT_DEFAULT_IN_SECONDS 2
  32. #define STS_WEB_IDENTITY_CREDS_DEFAULT_DURATION_SECONDS 900
  33. #define STS_WEB_IDENTITY_MAX_ATTEMPTS 3
  34. static void s_on_connection_manager_shutdown(void *user_data);
  35. struct aws_credentials_provider_sts_web_identity_impl {
  36. struct aws_http_connection_manager *connection_manager;
  37. const struct aws_auth_http_system_vtable *function_table;
  38. struct aws_string *role_arn;
  39. struct aws_string *role_session_name;
  40. struct aws_string *token_file_path;
  41. };
  42. /*
  43. * Tracking structure for each outstanding async query to an sts_web_identity provider
  44. */
  45. struct sts_web_identity_user_data {
  46. /* immutable post-creation */
  47. struct aws_allocator *allocator;
  48. struct aws_credentials_provider *sts_web_identity_provider;
  49. aws_on_get_credentials_callback_fn *original_callback;
  50. void *original_user_data;
  51. /* mutable */
  52. struct aws_http_connection *connection;
  53. struct aws_http_message *request;
  54. struct aws_byte_buf response;
  55. struct aws_string *access_key_id;
  56. struct aws_string *secret_access_key;
  57. struct aws_string *session_token;
  58. uint64_t expiration_timepoint_in_seconds;
  59. struct aws_byte_buf payload_buf;
  60. int status_code;
  61. int error_code;
  62. int attempt_count;
  63. };
  64. static void s_user_data_reset_request_and_response(struct sts_web_identity_user_data *user_data) {
  65. aws_byte_buf_reset(&user_data->response, true /*zero out*/);
  66. aws_byte_buf_reset(&user_data->payload_buf, true /*zero out*/);
  67. user_data->status_code = 0;
  68. if (user_data->request) {
  69. aws_input_stream_destroy(aws_http_message_get_body_stream(user_data->request));
  70. }
  71. aws_http_message_destroy(user_data->request);
  72. user_data->request = NULL;
  73. aws_string_destroy(user_data->access_key_id);
  74. user_data->access_key_id = NULL;
  75. aws_string_destroy_secure(user_data->secret_access_key);
  76. user_data->secret_access_key = NULL;
  77. aws_string_destroy_secure(user_data->session_token);
  78. user_data->session_token = NULL;
  79. }
  80. static void s_user_data_destroy(struct sts_web_identity_user_data *user_data) {
  81. if (user_data == NULL) {
  82. return;
  83. }
  84. struct aws_credentials_provider_sts_web_identity_impl *impl = user_data->sts_web_identity_provider->impl;
  85. if (user_data->connection) {
  86. impl->function_table->aws_http_connection_manager_release_connection(
  87. impl->connection_manager, user_data->connection);
  88. }
  89. s_user_data_reset_request_and_response(user_data);
  90. aws_byte_buf_clean_up(&user_data->response);
  91. aws_string_destroy(user_data->access_key_id);
  92. aws_string_destroy_secure(user_data->secret_access_key);
  93. aws_string_destroy_secure(user_data->session_token);
  94. aws_byte_buf_clean_up(&user_data->payload_buf);
  95. aws_credentials_provider_release(user_data->sts_web_identity_provider);
  96. aws_mem_release(user_data->allocator, user_data);
  97. }
  98. static struct sts_web_identity_user_data *s_user_data_new(
  99. struct aws_credentials_provider *sts_web_identity_provider,
  100. aws_on_get_credentials_callback_fn callback,
  101. void *user_data) {
  102. struct sts_web_identity_user_data *wrapped_user_data =
  103. aws_mem_calloc(sts_web_identity_provider->allocator, 1, sizeof(struct sts_web_identity_user_data));
  104. if (wrapped_user_data == NULL) {
  105. goto on_error;
  106. }
  107. wrapped_user_data->allocator = sts_web_identity_provider->allocator;
  108. wrapped_user_data->sts_web_identity_provider = sts_web_identity_provider;
  109. aws_credentials_provider_acquire(sts_web_identity_provider);
  110. wrapped_user_data->original_user_data = user_data;
  111. wrapped_user_data->original_callback = callback;
  112. if (aws_byte_buf_init(
  113. &wrapped_user_data->response,
  114. sts_web_identity_provider->allocator,
  115. STS_WEB_IDENTITY_RESPONSE_SIZE_INITIAL)) {
  116. goto on_error;
  117. }
  118. if (aws_byte_buf_init(&wrapped_user_data->payload_buf, sts_web_identity_provider->allocator, 1024)) {
  119. goto on_error;
  120. }
  121. return wrapped_user_data;
  122. on_error:
  123. s_user_data_destroy(wrapped_user_data);
  124. return NULL;
  125. }
  126. /*
  127. * In general, the STS_WEB_IDENTITY response document looks something like:
  128. <AssumeRoleWithWebIdentityResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
  129. <AssumeRoleWithWebIdentityResult>
  130. <SubjectFromWebIdentityToken>amzn1.account.AF6RHO7KZU5XRVQJGXK6HB56KR2A</SubjectFromWebIdentityToken>
  131. <Audience>client.5498841531868486423.1548@apps.example.com</Audience>
  132. <AssumedRoleUser>
  133. <Arn>arn:aws:sts::123456789012:assumed-role/FederatedWebIdentityRole/app1</Arn>
  134. <AssumedRoleId>AROACLKWSDQRAOEXAMPLE:app1</AssumedRoleId>
  135. </AssumedRoleUser>
  136. <Credentials>
  137. <SessionToken>AQoDYXdzEE0a8ANXXXXXXXXNO1ewxE5TijQyp+IEXAMPLE</SessionToken>
  138. <SecretAccessKey>wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY</SecretAccessKey>
  139. <Expiration>2014-10-24T23:00:23Z</Expiration>
  140. <AccessKeyId>ASgeIAIOSFODNN7EXAMPLE</AccessKeyId>
  141. </Credentials>
  142. <Provider>www.amazon.com</Provider>
  143. </AssumeRoleWithWebIdentityResult>
  144. <ResponseMetadata>
  145. <RequestId>ad4156e9-bce1-11e2-82e6-6b6efEXAMPLE</RequestId>
  146. </ResponseMetadata>
  147. </AssumeRoleWithWebIdentityResponse>
  148. Error Response looks like:
  149. <?xml version="1.0" encoding="UTF-8"?>
  150. <Error>
  151. <Code>ExceptionName</Code>
  152. <Message>XXX</Message>
  153. <Resource>YYY</Resource>
  154. <RequestId>4442587FB7D0A2F9</RequestId>
  155. </Error>
  156. */
  157. static bool s_on_error_node_encountered_fn(struct aws_xml_parser *parser, struct aws_xml_node *node, void *user_data) {
  158. struct aws_byte_cursor node_name;
  159. AWS_ZERO_STRUCT(node_name);
  160. if (aws_xml_node_get_name(node, &node_name)) {
  161. AWS_LOGF_ERROR(
  162. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  163. "(id=%p): While parsing xml error response for sts web identity credentials provider, could not get xml "
  164. "node name for function s_on_error_node_encountered_fn.",
  165. user_data);
  166. return false;
  167. }
  168. if (aws_byte_cursor_eq_c_str_ignore_case(&node_name, "Error")) {
  169. return aws_xml_node_traverse(parser, node, s_on_error_node_encountered_fn, user_data);
  170. }
  171. bool *get_retryable_error = user_data;
  172. struct aws_byte_cursor data_cursor;
  173. AWS_ZERO_STRUCT(data_cursor);
  174. if (aws_byte_cursor_eq_c_str_ignore_case(&node_name, "Code")) {
  175. aws_xml_node_as_body(parser, node, &data_cursor);
  176. if (aws_byte_cursor_eq_c_str_ignore_case(&data_cursor, "IDPCommunicationError") ||
  177. aws_byte_cursor_eq_c_str_ignore_case(&data_cursor, "InvalidIdentityToken")) {
  178. *get_retryable_error = true;
  179. }
  180. }
  181. return true;
  182. }
  183. static bool s_parse_retryable_error_from_response(struct aws_allocator *allocator, struct aws_byte_buf *response) {
  184. struct aws_xml_parser_options options;
  185. AWS_ZERO_STRUCT(options);
  186. options.doc = aws_byte_cursor_from_buf(response);
  187. struct aws_xml_parser *xml_parser = aws_xml_parser_new(allocator, &options);
  188. if (xml_parser == NULL) {
  189. AWS_LOGF_ERROR(
  190. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  191. "Failed to init xml parser for sts web identity credentials provider to parse error information.");
  192. return false;
  193. }
  194. bool get_retryable_error = false;
  195. if (aws_xml_parser_parse(xml_parser, s_on_error_node_encountered_fn, &get_retryable_error)) {
  196. AWS_LOGF_ERROR(
  197. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  198. "Failed to parse xml error response for sts web identity with error %s",
  199. aws_error_str(aws_last_error()));
  200. aws_xml_parser_destroy(xml_parser);
  201. return false;
  202. }
  203. aws_xml_parser_destroy(xml_parser);
  204. return get_retryable_error;
  205. }
  206. static bool s_on_creds_node_encountered_fn(struct aws_xml_parser *parser, struct aws_xml_node *node, void *user_data) {
  207. struct aws_byte_cursor node_name;
  208. AWS_ZERO_STRUCT(node_name);
  209. if (aws_xml_node_get_name(node, &node_name)) {
  210. AWS_LOGF_ERROR(
  211. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  212. "(id=%p): While parsing credentials xml response for sts web identity credentials provider, could not get "
  213. "xml node name for function s_on_creds_node_encountered_fn.",
  214. user_data);
  215. return false;
  216. }
  217. if (aws_byte_cursor_eq_c_str_ignore_case(&node_name, "AssumeRoleWithWebIdentityResponse") ||
  218. aws_byte_cursor_eq_c_str_ignore_case(&node_name, "AssumeRoleWithWebIdentityResult") ||
  219. aws_byte_cursor_eq_c_str_ignore_case(&node_name, "Credentials")) {
  220. return aws_xml_node_traverse(parser, node, s_on_creds_node_encountered_fn, user_data);
  221. }
  222. struct sts_web_identity_user_data *query_user_data = user_data;
  223. struct aws_byte_cursor credential_data;
  224. AWS_ZERO_STRUCT(credential_data);
  225. if (aws_byte_cursor_eq_c_str_ignore_case(&node_name, "AccessKeyId")) {
  226. aws_xml_node_as_body(parser, node, &credential_data);
  227. query_user_data->access_key_id =
  228. aws_string_new_from_array(query_user_data->allocator, credential_data.ptr, credential_data.len);
  229. }
  230. if (aws_byte_cursor_eq_c_str_ignore_case(&node_name, "SecretAccessKey")) {
  231. aws_xml_node_as_body(parser, node, &credential_data);
  232. query_user_data->secret_access_key =
  233. aws_string_new_from_array(query_user_data->allocator, credential_data.ptr, credential_data.len);
  234. }
  235. if (aws_byte_cursor_eq_c_str_ignore_case(&node_name, "SessionToken")) {
  236. aws_xml_node_as_body(parser, node, &credential_data);
  237. query_user_data->session_token =
  238. aws_string_new_from_array(query_user_data->allocator, credential_data.ptr, credential_data.len);
  239. }
  240. /* As long as we parsed an usable expiration, use it, otherwise use
  241. * the existing one: now + 900s, initialized before parsing.
  242. */
  243. if (aws_byte_cursor_eq_c_str_ignore_case(&node_name, "Expiration")) {
  244. aws_xml_node_as_body(parser, node, &credential_data);
  245. if (credential_data.len != 0) {
  246. struct aws_date_time expiration;
  247. if (aws_date_time_init_from_str_cursor(&expiration, &credential_data, AWS_DATE_FORMAT_ISO_8601) ==
  248. AWS_OP_SUCCESS) {
  249. query_user_data->expiration_timepoint_in_seconds = (uint64_t)aws_date_time_as_epoch_secs(&expiration);
  250. } else {
  251. query_user_data->error_code = aws_last_error();
  252. AWS_LOGF_ERROR(
  253. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  254. "Failed to parse time string from sts web identity xml response: %s",
  255. aws_error_str(query_user_data->error_code));
  256. }
  257. }
  258. }
  259. return true;
  260. }
  261. static struct aws_credentials *s_parse_credentials_from_response(
  262. struct sts_web_identity_user_data *query_user_data,
  263. struct aws_byte_buf *response) {
  264. if (!response || response->len == 0) {
  265. return NULL;
  266. }
  267. struct aws_credentials *credentials = NULL;
  268. struct aws_xml_parser_options options;
  269. AWS_ZERO_STRUCT(options);
  270. options.doc = aws_byte_cursor_from_buf(response);
  271. struct aws_xml_parser *xml_parser = aws_xml_parser_new(query_user_data->allocator, &options);
  272. if (xml_parser == NULL) {
  273. AWS_LOGF_ERROR(
  274. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  275. "Failed to init xml parser for sts web identity credentials provider to parse error information.");
  276. return NULL;
  277. }
  278. uint64_t now = UINT64_MAX;
  279. if (aws_sys_clock_get_ticks(&now) != AWS_OP_SUCCESS) {
  280. AWS_LOGF_ERROR(
  281. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  282. "Failed to get sys clock for sts web identity credentials provider to parse error information.");
  283. goto on_finish;
  284. }
  285. uint64_t now_seconds = aws_timestamp_convert(now, AWS_TIMESTAMP_NANOS, AWS_TIMESTAMP_SECS, NULL);
  286. query_user_data->expiration_timepoint_in_seconds = now_seconds + STS_WEB_IDENTITY_CREDS_DEFAULT_DURATION_SECONDS;
  287. if (aws_xml_parser_parse(xml_parser, s_on_creds_node_encountered_fn, query_user_data)) {
  288. AWS_LOGF_ERROR(
  289. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  290. "Failed to parse xml response for sts web identity with error: %s",
  291. aws_error_str(aws_last_error()));
  292. goto on_finish;
  293. }
  294. if (!query_user_data->access_key_id || !query_user_data->secret_access_key) {
  295. goto on_finish;
  296. }
  297. credentials = aws_credentials_new(
  298. query_user_data->allocator,
  299. aws_byte_cursor_from_string(query_user_data->access_key_id),
  300. aws_byte_cursor_from_string(query_user_data->secret_access_key),
  301. aws_byte_cursor_from_string(query_user_data->session_token),
  302. query_user_data->expiration_timepoint_in_seconds);
  303. on_finish:
  304. if (credentials == NULL) {
  305. query_user_data->error_code = aws_last_error();
  306. }
  307. if (xml_parser != NULL) {
  308. aws_xml_parser_destroy(xml_parser);
  309. xml_parser = NULL;
  310. }
  311. return credentials;
  312. }
  313. /*
  314. * No matter the result, this always gets called assuming that user_data is successfully allocated
  315. */
  316. static void s_finalize_get_credentials_query(struct sts_web_identity_user_data *user_data) {
  317. /* Try to build credentials from whatever, if anything, was in the result */
  318. struct aws_credentials *credentials = NULL;
  319. if (user_data->status_code == AWS_HTTP_STATUS_CODE_200_OK) {
  320. credentials = s_parse_credentials_from_response(user_data, &user_data->response);
  321. }
  322. if (credentials != NULL) {
  323. AWS_LOGF_INFO(
  324. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  325. "(id=%p) STS_WEB_IDENTITY credentials provider successfully queried credentials",
  326. (void *)user_data->sts_web_identity_provider);
  327. } else {
  328. AWS_LOGF_WARN(
  329. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  330. "(id=%p) STS_WEB_IDENTITY credentials provider failed to query credentials",
  331. (void *)user_data->sts_web_identity_provider);
  332. if (user_data->error_code == AWS_ERROR_SUCCESS) {
  333. user_data->error_code = AWS_AUTH_CREDENTIALS_PROVIDER_STS_WEB_IDENTITY_SOURCE_FAILURE;
  334. }
  335. }
  336. /* pass the credentials back */
  337. user_data->original_callback(credentials, user_data->error_code, user_data->original_user_data);
  338. /* clean up */
  339. s_user_data_destroy(user_data);
  340. aws_credentials_release(credentials);
  341. }
  342. static int s_on_incoming_body_fn(
  343. struct aws_http_stream *stream,
  344. const struct aws_byte_cursor *body,
  345. void *wrapped_user_data) {
  346. (void)stream;
  347. struct sts_web_identity_user_data *user_data = wrapped_user_data;
  348. struct aws_credentials_provider_sts_web_identity_impl *impl = user_data->sts_web_identity_provider->impl;
  349. AWS_LOGF_TRACE(
  350. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  351. "(id=%p) STS_WEB_IDENTITY credentials provider received %zu response bytes",
  352. (void *)user_data->sts_web_identity_provider,
  353. body->len);
  354. if (body->len + user_data->response.len > STS_WEB_IDENTITY_RESPONSE_SIZE_LIMIT) {
  355. impl->function_table->aws_http_connection_close(user_data->connection);
  356. AWS_LOGF_ERROR(
  357. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  358. "(id=%p) STS_WEB_IDENTITY credentials provider query response exceeded maximum allowed length",
  359. (void *)user_data->sts_web_identity_provider);
  360. return aws_raise_error(AWS_ERROR_SHORT_BUFFER);
  361. }
  362. if (aws_byte_buf_append_dynamic(&user_data->response, body)) {
  363. impl->function_table->aws_http_connection_close(user_data->connection);
  364. AWS_LOGF_ERROR(
  365. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  366. "(id=%p) STS_WEB_IDENTITY credentials provider query error appending response: %s",
  367. (void *)user_data->sts_web_identity_provider,
  368. aws_error_str(aws_last_error()));
  369. return AWS_OP_ERR;
  370. }
  371. return AWS_OP_SUCCESS;
  372. }
  373. static int s_on_incoming_headers_fn(
  374. struct aws_http_stream *stream,
  375. enum aws_http_header_block header_block,
  376. const struct aws_http_header *header_array,
  377. size_t num_headers,
  378. void *wrapped_user_data) {
  379. (void)header_array;
  380. (void)num_headers;
  381. if (header_block != AWS_HTTP_HEADER_BLOCK_MAIN) {
  382. return AWS_OP_SUCCESS;
  383. }
  384. struct sts_web_identity_user_data *user_data = wrapped_user_data;
  385. if (header_block == AWS_HTTP_HEADER_BLOCK_MAIN) {
  386. if (user_data->status_code == 0) {
  387. struct aws_credentials_provider_sts_web_identity_impl *impl = user_data->sts_web_identity_provider->impl;
  388. if (impl->function_table->aws_http_stream_get_incoming_response_status(stream, &user_data->status_code)) {
  389. AWS_LOGF_ERROR(
  390. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  391. "(id=%p) STS_WEB_IDENTITY credentials provider failed to get http status code: %s",
  392. (void *)user_data->sts_web_identity_provider,
  393. aws_error_str(aws_last_error()));
  394. return AWS_OP_ERR;
  395. }
  396. AWS_LOGF_DEBUG(
  397. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  398. "(id=%p) STS_WEB_IDENTITY credentials provider query received http status code %d",
  399. (void *)user_data->sts_web_identity_provider,
  400. user_data->status_code);
  401. }
  402. }
  403. return AWS_OP_SUCCESS;
  404. }
  405. static void s_query_credentials(struct sts_web_identity_user_data *user_data);
  406. static void s_on_stream_complete_fn(struct aws_http_stream *stream, int error_code, void *data) {
  407. struct sts_web_identity_user_data *user_data = data;
  408. struct aws_credentials_provider_sts_web_identity_impl *impl = user_data->sts_web_identity_provider->impl;
  409. struct aws_http_connection *connection = impl->function_table->aws_http_stream_get_connection(stream);
  410. impl->function_table->aws_http_stream_release(stream);
  411. impl->function_table->aws_http_connection_manager_release_connection(impl->connection_manager, connection);
  412. /*
  413. * On anything other than a 200, if we can retry the request based on
  414. * error response, retry it, otherwise, call the finalize function.
  415. */
  416. if (user_data->status_code != AWS_HTTP_STATUS_CODE_200_OK || error_code != AWS_OP_SUCCESS) {
  417. if (++user_data->attempt_count < STS_WEB_IDENTITY_MAX_ATTEMPTS && user_data->response.len) {
  418. if (s_parse_retryable_error_from_response(user_data->allocator, &user_data->response)) {
  419. s_query_credentials(user_data);
  420. return;
  421. }
  422. }
  423. }
  424. s_finalize_get_credentials_query(user_data);
  425. }
  426. static struct aws_http_header s_host_header = {
  427. .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("host"),
  428. .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("sts.amazonaws.com"),
  429. };
  430. static struct aws_http_header s_content_type_header = {
  431. .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("content-type"),
  432. .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("application/x-www-form-urlencoded"),
  433. };
  434. static struct aws_http_header s_api_version_header = {
  435. .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("x-amz-api-version"),
  436. .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("2011-06-15"),
  437. };
  438. static struct aws_http_header s_accept_header = {
  439. .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Accept"),
  440. .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("*/*"),
  441. };
  442. static struct aws_http_header s_user_agent_header = {
  443. .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("User-Agent"),
  444. .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("aws-sdk-crt/sts-web-identity-credentials-provider"),
  445. };
  446. static struct aws_http_header s_keep_alive_header = {
  447. .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Connection"),
  448. .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("keep-alive"),
  449. };
  450. static struct aws_byte_cursor s_content_length = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("content-length");
  451. static struct aws_byte_cursor s_path = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("/");
  452. static int s_make_sts_web_identity_http_query(
  453. struct sts_web_identity_user_data *user_data,
  454. struct aws_byte_cursor *body_cursor) {
  455. AWS_FATAL_ASSERT(user_data->connection);
  456. struct aws_http_stream *stream = NULL;
  457. struct aws_input_stream *input_stream = NULL;
  458. struct aws_http_message *request = aws_http_message_new_request(user_data->allocator);
  459. if (request == NULL) {
  460. return AWS_OP_ERR;
  461. }
  462. struct aws_credentials_provider_sts_web_identity_impl *impl = user_data->sts_web_identity_provider->impl;
  463. char content_length[21];
  464. AWS_ZERO_ARRAY(content_length);
  465. snprintf(content_length, sizeof(content_length), "%" PRIu64, (uint64_t)body_cursor->len);
  466. struct aws_http_header content_len_header = {
  467. .name = s_content_length,
  468. .value = aws_byte_cursor_from_c_str(content_length),
  469. };
  470. if (aws_http_message_add_header(request, content_len_header)) {
  471. goto on_error;
  472. }
  473. if (aws_http_message_add_header(request, s_content_type_header)) {
  474. goto on_error;
  475. }
  476. if (aws_http_message_add_header(request, s_host_header)) {
  477. goto on_error;
  478. }
  479. if (aws_http_message_add_header(request, s_api_version_header)) {
  480. goto on_error;
  481. }
  482. if (aws_http_message_add_header(request, s_accept_header)) {
  483. goto on_error;
  484. }
  485. if (aws_http_message_add_header(request, s_user_agent_header)) {
  486. goto on_error;
  487. }
  488. if (aws_http_message_add_header(request, s_keep_alive_header)) {
  489. goto on_error;
  490. }
  491. input_stream = aws_input_stream_new_from_cursor(user_data->allocator, body_cursor);
  492. if (!input_stream) {
  493. goto on_error;
  494. }
  495. aws_http_message_set_body_stream(request, input_stream);
  496. if (aws_http_message_set_request_path(request, s_path)) {
  497. goto on_error;
  498. }
  499. if (aws_http_message_set_request_method(request, aws_http_method_post)) {
  500. goto on_error;
  501. }
  502. user_data->request = request;
  503. struct aws_http_make_request_options request_options = {
  504. .self_size = sizeof(request_options),
  505. .on_response_headers = s_on_incoming_headers_fn,
  506. .on_response_header_block_done = NULL,
  507. .on_response_body = s_on_incoming_body_fn,
  508. .on_complete = s_on_stream_complete_fn,
  509. .user_data = user_data,
  510. .request = request,
  511. };
  512. stream = impl->function_table->aws_http_connection_make_request(user_data->connection, &request_options);
  513. if (!stream) {
  514. goto on_error;
  515. }
  516. if (impl->function_table->aws_http_stream_activate(stream)) {
  517. goto on_error;
  518. }
  519. return AWS_OP_SUCCESS;
  520. on_error:
  521. impl->function_table->aws_http_stream_release(stream);
  522. aws_input_stream_destroy(input_stream);
  523. aws_http_message_destroy(request);
  524. user_data->request = NULL;
  525. return AWS_OP_ERR;
  526. }
  527. static void s_query_credentials(struct sts_web_identity_user_data *user_data) {
  528. AWS_FATAL_ASSERT(user_data->connection);
  529. struct aws_credentials_provider_sts_web_identity_impl *impl = user_data->sts_web_identity_provider->impl;
  530. /* "Clear" the result */
  531. s_user_data_reset_request_and_response(user_data);
  532. /*
  533. * Calculate body message:
  534. * "Action=AssumeRoleWithWebIdentity"
  535. * + "&Version=2011-06-15"
  536. * + "&RoleSessionName=" + url_encode(role_session_name)
  537. * + "&RoleArn=" + url_encode(role_arn)
  538. * + "&WebIdentityToken=" + url_encode(token);
  539. */
  540. struct aws_byte_buf token_buf;
  541. bool success = false;
  542. AWS_ZERO_STRUCT(token_buf);
  543. struct aws_byte_cursor work_cursor =
  544. aws_byte_cursor_from_c_str("Action=AssumeRoleWithWebIdentity&Version=2011-06-15&RoleArn=");
  545. if (aws_byte_buf_append_dynamic(&user_data->payload_buf, &work_cursor)) {
  546. goto on_finish;
  547. }
  548. work_cursor = aws_byte_cursor_from_string(impl->role_arn);
  549. if (aws_byte_buf_append_encoding_uri_param(&user_data->payload_buf, &work_cursor)) {
  550. goto on_finish;
  551. }
  552. work_cursor = aws_byte_cursor_from_c_str("&RoleSessionName=");
  553. if (aws_byte_buf_append_dynamic(&user_data->payload_buf, &work_cursor)) {
  554. goto on_finish;
  555. }
  556. work_cursor = aws_byte_cursor_from_string(impl->role_session_name);
  557. if (aws_byte_buf_append_encoding_uri_param(&user_data->payload_buf, &work_cursor)) {
  558. goto on_finish;
  559. }
  560. work_cursor = aws_byte_cursor_from_c_str("&WebIdentityToken=");
  561. if (aws_byte_buf_append_dynamic(&user_data->payload_buf, &work_cursor)) {
  562. goto on_finish;
  563. }
  564. if (aws_byte_buf_init_from_file(&token_buf, user_data->allocator, aws_string_c_str(impl->token_file_path))) {
  565. goto on_finish;
  566. }
  567. work_cursor = aws_byte_cursor_from_buf(&token_buf);
  568. if (aws_byte_buf_append_encoding_uri_param(&user_data->payload_buf, &work_cursor)) {
  569. goto on_finish;
  570. }
  571. struct aws_byte_cursor body_cursor = aws_byte_cursor_from_buf(&user_data->payload_buf);
  572. if (s_make_sts_web_identity_http_query(user_data, &body_cursor) == AWS_OP_ERR) {
  573. goto on_finish;
  574. }
  575. success = true;
  576. on_finish:
  577. aws_byte_buf_clean_up(&token_buf);
  578. if (!success) {
  579. s_finalize_get_credentials_query(user_data);
  580. }
  581. }
  582. static void s_on_acquire_connection(struct aws_http_connection *connection, int error_code, void *data) {
  583. struct sts_web_identity_user_data *user_data = data;
  584. if (connection == NULL) {
  585. AWS_LOGF_WARN(
  586. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  587. "id=%p: STS_WEB_IDENTITY provider failed to acquire a connection, error code %d(%s)",
  588. (void *)user_data->sts_web_identity_provider,
  589. error_code,
  590. aws_error_str(error_code));
  591. s_finalize_get_credentials_query(user_data);
  592. return;
  593. }
  594. user_data->connection = connection;
  595. s_query_credentials(user_data);
  596. }
  597. static int s_credentials_provider_sts_web_identity_get_credentials_async(
  598. struct aws_credentials_provider *provider,
  599. aws_on_get_credentials_callback_fn callback,
  600. void *user_data) {
  601. struct aws_credentials_provider_sts_web_identity_impl *impl = provider->impl;
  602. struct sts_web_identity_user_data *wrapped_user_data = s_user_data_new(provider, callback, user_data);
  603. if (wrapped_user_data == NULL) {
  604. goto error;
  605. }
  606. impl->function_table->aws_http_connection_manager_acquire_connection(
  607. impl->connection_manager, s_on_acquire_connection, wrapped_user_data);
  608. return AWS_OP_SUCCESS;
  609. error:
  610. s_user_data_destroy(wrapped_user_data);
  611. return AWS_OP_ERR;
  612. }
  613. static void s_credentials_provider_sts_web_identity_destroy(struct aws_credentials_provider *provider) {
  614. struct aws_credentials_provider_sts_web_identity_impl *impl = provider->impl;
  615. if (impl == NULL) {
  616. return;
  617. }
  618. aws_string_destroy(impl->role_arn);
  619. aws_string_destroy(impl->role_session_name);
  620. aws_string_destroy(impl->token_file_path);
  621. /* aws_http_connection_manager_release will eventually leads to call of s_on_connection_manager_shutdown,
  622. * which will do memory release for provider and impl. So We should be freeing impl
  623. * related memory first, then call aws_http_connection_manager_release.
  624. */
  625. if (impl->connection_manager) {
  626. impl->function_table->aws_http_connection_manager_release(impl->connection_manager);
  627. } else {
  628. /* If provider setup failed halfway through, connection_manager might not exist.
  629. * In this case invoke shutdown completion callback directly to finish cleanup */
  630. s_on_connection_manager_shutdown(provider);
  631. }
  632. /* freeing the provider takes place in the shutdown callback below */
  633. }
  634. static struct aws_credentials_provider_vtable s_aws_credentials_provider_sts_web_identity_vtable = {
  635. .get_credentials = s_credentials_provider_sts_web_identity_get_credentials_async,
  636. .destroy = s_credentials_provider_sts_web_identity_destroy,
  637. };
  638. static void s_on_connection_manager_shutdown(void *user_data) {
  639. struct aws_credentials_provider *provider = user_data;
  640. aws_credentials_provider_invoke_shutdown_callback(provider);
  641. aws_mem_release(provider->allocator, provider);
  642. }
  643. AWS_STATIC_STRING_FROM_LITERAL(s_region_config, "region");
  644. AWS_STATIC_STRING_FROM_LITERAL(s_region_env, "AWS_DEFAULT_REGION");
  645. AWS_STATIC_STRING_FROM_LITERAL(s_role_arn_config, "role_arn");
  646. AWS_STATIC_STRING_FROM_LITERAL(s_role_arn_env, "AWS_ROLE_ARN");
  647. AWS_STATIC_STRING_FROM_LITERAL(s_role_session_name_config, "role_session_name");
  648. AWS_STATIC_STRING_FROM_LITERAL(s_role_session_name_env, "AWS_ROLE_SESSION_NAME");
  649. AWS_STATIC_STRING_FROM_LITERAL(s_token_file_path_config, "web_identity_token_file");
  650. AWS_STATIC_STRING_FROM_LITERAL(s_token_file_path_env, "AWS_WEB_IDENTITY_TOKEN_FILE");
  651. struct sts_web_identity_parameters {
  652. struct aws_allocator *allocator;
  653. /* region is actually used to construct endpoint */
  654. struct aws_byte_buf endpoint;
  655. struct aws_byte_buf role_arn;
  656. struct aws_byte_buf role_session_name;
  657. struct aws_byte_buf token_file_path;
  658. };
  659. struct aws_profile_collection *s_load_profile(struct aws_allocator *allocator) {
  660. struct aws_profile_collection *config_profiles = NULL;
  661. struct aws_string *config_file_path = NULL;
  662. config_file_path = aws_get_config_file_path(allocator, NULL);
  663. if (!config_file_path) {
  664. AWS_LOGF_ERROR(
  665. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  666. "Failed to resolve config file path during sts web identity provider initialization: %s",
  667. aws_error_str(aws_last_error()));
  668. goto on_error;
  669. }
  670. config_profiles = aws_profile_collection_new_from_file(allocator, config_file_path, AWS_PST_CONFIG);
  671. if (config_profiles != NULL) {
  672. AWS_LOGF_DEBUG(
  673. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  674. "Successfully built config profile collection from file at (%s)",
  675. aws_string_c_str(config_file_path));
  676. } else {
  677. AWS_LOGF_ERROR(
  678. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  679. "Failed to build config profile collection from file at (%s) : %s",
  680. aws_string_c_str(config_file_path),
  681. aws_error_str(aws_last_error()));
  682. goto on_error;
  683. }
  684. aws_string_destroy(config_file_path);
  685. return config_profiles;
  686. on_error:
  687. aws_string_destroy(config_file_path);
  688. aws_profile_collection_destroy(config_profiles);
  689. return NULL;
  690. }
  691. static struct aws_byte_cursor s_default_profile_name_cursor = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("default");
  692. static struct aws_byte_cursor s_dot_cursor = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(".");
  693. static struct aws_byte_cursor s_amazonaws_cursor = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(".amazonaws.com");
  694. static struct aws_byte_cursor s_cn_cursor = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(".cn");
  695. AWS_STATIC_STRING_FROM_LITERAL(s_sts_service_name, "sts");
  696. static int s_construct_endpoint(
  697. struct aws_allocator *allocator,
  698. struct aws_byte_buf *endpoint,
  699. const struct aws_string *region,
  700. const struct aws_string *service_name) {
  701. if (!allocator || !endpoint || !region || !service_name) {
  702. return AWS_ERROR_INVALID_ARGUMENT;
  703. }
  704. aws_byte_buf_clean_up(endpoint);
  705. struct aws_byte_cursor service_cursor = aws_byte_cursor_from_string(service_name);
  706. if (aws_byte_buf_init_copy_from_cursor(endpoint, allocator, service_cursor)) {
  707. goto on_error;
  708. }
  709. if (aws_byte_buf_append_dynamic(endpoint, &s_dot_cursor)) {
  710. goto on_error;
  711. }
  712. struct aws_byte_cursor region_cursor;
  713. region_cursor = aws_byte_cursor_from_array(region->bytes, region->len);
  714. if (aws_byte_buf_append_dynamic(endpoint, &region_cursor)) {
  715. goto on_error;
  716. }
  717. if (aws_byte_buf_append_dynamic(endpoint, &s_amazonaws_cursor)) {
  718. goto on_error;
  719. }
  720. if (aws_string_eq_c_str_ignore_case(region, "cn-north-1") ||
  721. aws_string_eq_c_str_ignore_case(region, "cn-northwest-1")) {
  722. if (aws_byte_buf_append_dynamic(endpoint, &s_cn_cursor)) {
  723. goto on_error;
  724. }
  725. }
  726. return AWS_OP_SUCCESS;
  727. on_error:
  728. aws_byte_buf_clean_up(endpoint);
  729. return AWS_OP_ERR;
  730. }
  731. static int s_generate_uuid_to_buf(struct aws_allocator *allocator, struct aws_byte_buf *dst) {
  732. if (!allocator || !dst) {
  733. return AWS_ERROR_INVALID_ARGUMENT;
  734. }
  735. struct aws_uuid uuid;
  736. if (aws_uuid_init(&uuid)) {
  737. AWS_LOGF_ERROR(
  738. AWS_LS_AUTH_CREDENTIALS_PROVIDER, "Failed to initiate an uuid struct: %s", aws_error_str(aws_last_error()));
  739. return aws_last_error();
  740. }
  741. char uuid_str[AWS_UUID_STR_LEN] = {0};
  742. struct aws_byte_buf uuid_buf = aws_byte_buf_from_array(uuid_str, sizeof(uuid_str));
  743. uuid_buf.len = 0;
  744. if (aws_uuid_to_str(&uuid, &uuid_buf)) {
  745. AWS_LOGF_ERROR(
  746. AWS_LS_AUTH_CREDENTIALS_PROVIDER, "Failed to stringify uuid: %s", aws_error_str(aws_last_error()));
  747. return aws_last_error();
  748. }
  749. if (aws_byte_buf_init_copy(dst, allocator, &uuid_buf)) {
  750. AWS_LOGF_ERROR(
  751. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  752. "Failed to generate role session name during sts web identity provider initialization: %s",
  753. aws_error_str(aws_last_error()));
  754. return aws_last_error();
  755. }
  756. return AWS_OP_SUCCESS;
  757. }
  758. static void s_check_or_get_with_profile_config(
  759. struct aws_allocator *allocator,
  760. const struct aws_profile *profile,
  761. struct aws_string **target,
  762. const struct aws_string *config_key) {
  763. if (!allocator || !profile || !config_key) {
  764. return;
  765. }
  766. if ((!(*target) || !(*target)->len)) {
  767. if (*target) {
  768. aws_string_destroy(*target);
  769. }
  770. const struct aws_profile_property *property = aws_profile_get_property(profile, config_key);
  771. if (property) {
  772. *target = aws_string_new_from_string(allocator, aws_profile_property_get_value(property));
  773. }
  774. }
  775. }
  776. static void s_parameters_destroy(struct sts_web_identity_parameters *parameters) {
  777. if (!parameters) {
  778. return;
  779. }
  780. aws_byte_buf_clean_up(&parameters->endpoint);
  781. aws_byte_buf_clean_up(&parameters->role_arn);
  782. aws_byte_buf_clean_up(&parameters->role_session_name);
  783. aws_byte_buf_clean_up(&parameters->token_file_path);
  784. aws_mem_release(parameters->allocator, parameters);
  785. }
  786. static struct sts_web_identity_parameters *s_parameters_new(
  787. struct aws_allocator *allocator,
  788. struct aws_profile_collection *config_profile_collection_cached) {
  789. struct sts_web_identity_parameters *parameters =
  790. aws_mem_calloc(allocator, 1, sizeof(struct sts_web_identity_parameters));
  791. if (parameters == NULL) {
  792. return NULL;
  793. }
  794. parameters->allocator = allocator;
  795. bool success = false;
  796. struct aws_string *region = NULL;
  797. struct aws_string *role_arn = NULL;
  798. struct aws_string *role_session_name = NULL;
  799. struct aws_string *token_file_path = NULL;
  800. /* check environment variables */
  801. aws_get_environment_value(allocator, s_region_env, &region);
  802. aws_get_environment_value(allocator, s_role_arn_env, &role_arn);
  803. aws_get_environment_value(allocator, s_role_session_name_env, &role_session_name);
  804. aws_get_environment_value(allocator, s_token_file_path_env, &token_file_path);
  805. /**
  806. * check config profile if either region, role_arn or token_file_path or role_session_name is not resolved from
  807. * environment variable. Role session name can also be generated by us using uuid if not found from both sources.
  808. */
  809. struct aws_profile_collection *config_profile = NULL;
  810. struct aws_string *profile_name = NULL;
  811. const struct aws_profile *profile = NULL;
  812. bool get_all_parameters =
  813. (region && region->len && role_arn && role_arn->len && token_file_path && token_file_path->len);
  814. if (!get_all_parameters) {
  815. if (config_profile_collection_cached) {
  816. /* Use cached profile collection */
  817. config_profile = aws_profile_collection_acquire(config_profile_collection_cached);
  818. } else {
  819. /* Load profile collection from files */
  820. config_profile = s_load_profile(allocator);
  821. if (!config_profile) {
  822. goto on_finish;
  823. }
  824. }
  825. profile_name = aws_get_profile_name(allocator, &s_default_profile_name_cursor);
  826. if (profile_name) {
  827. profile = aws_profile_collection_get_profile(config_profile, profile_name);
  828. }
  829. if (!profile) {
  830. AWS_LOGF_ERROR(
  831. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  832. "Failed to resolve either region, role arn or token file path during sts web identity provider "
  833. "initialization.");
  834. goto on_finish;
  835. } else {
  836. s_check_or_get_with_profile_config(allocator, profile, &region, s_region_config);
  837. s_check_or_get_with_profile_config(allocator, profile, &role_arn, s_role_arn_config);
  838. s_check_or_get_with_profile_config(allocator, profile, &role_session_name, s_role_session_name_config);
  839. s_check_or_get_with_profile_config(allocator, profile, &token_file_path, s_token_file_path_config);
  840. }
  841. }
  842. /* determin endpoint */
  843. if (s_construct_endpoint(allocator, &parameters->endpoint, region, s_sts_service_name)) {
  844. AWS_LOGF_ERROR(
  845. AWS_LS_AUTH_CREDENTIALS_PROVIDER, "Failed to construct sts endpoint with, probably region is missing.");
  846. goto on_finish;
  847. }
  848. /* determine role_arn */
  849. if (!role_arn || !role_arn->len ||
  850. aws_byte_buf_init_copy_from_cursor(&parameters->role_arn, allocator, aws_byte_cursor_from_string(role_arn))) {
  851. AWS_LOGF_ERROR(
  852. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  853. "Failed to resolve role arn during sts web identity provider initialization.");
  854. goto on_finish;
  855. }
  856. /* determine token_file_path */
  857. if (!token_file_path || !token_file_path->len ||
  858. aws_byte_buf_init_copy_from_cursor(
  859. &parameters->token_file_path, allocator, aws_byte_cursor_from_string(token_file_path))) {
  860. AWS_LOGF_ERROR(
  861. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  862. "Failed to resolve token file path during sts web identity provider initialization.");
  863. goto on_finish;
  864. }
  865. /* determine role_session_name */
  866. if (role_session_name && role_session_name->len) {
  867. if (aws_byte_buf_init_copy_from_cursor(
  868. &parameters->role_session_name, allocator, aws_byte_cursor_from_string(role_session_name))) {
  869. goto on_finish;
  870. }
  871. } else if (s_generate_uuid_to_buf(allocator, &parameters->role_session_name)) {
  872. goto on_finish;
  873. }
  874. AWS_LOGF_DEBUG(
  875. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  876. "Successfully loaded all required parameters for sts web identity credentials provider.");
  877. success = true;
  878. on_finish:
  879. aws_string_destroy(region);
  880. aws_string_destroy(role_arn);
  881. aws_string_destroy(role_session_name);
  882. aws_string_destroy(token_file_path);
  883. aws_string_destroy(profile_name);
  884. aws_profile_collection_release(config_profile);
  885. if (!success) {
  886. s_parameters_destroy(parameters);
  887. parameters = NULL;
  888. }
  889. return parameters;
  890. }
  891. struct aws_credentials_provider *aws_credentials_provider_new_sts_web_identity(
  892. struct aws_allocator *allocator,
  893. const struct aws_credentials_provider_sts_web_identity_options *options) {
  894. struct sts_web_identity_parameters *parameters =
  895. s_parameters_new(allocator, options->config_profile_collection_cached);
  896. if (!parameters) {
  897. return NULL;
  898. }
  899. struct aws_tls_connection_options tls_connection_options;
  900. AWS_ZERO_STRUCT(tls_connection_options);
  901. struct aws_credentials_provider *provider = NULL;
  902. struct aws_credentials_provider_sts_web_identity_impl *impl = NULL;
  903. aws_mem_acquire_many(
  904. allocator,
  905. 2,
  906. &provider,
  907. sizeof(struct aws_credentials_provider),
  908. &impl,
  909. sizeof(struct aws_credentials_provider_sts_web_identity_impl));
  910. if (!provider) {
  911. goto on_error;
  912. }
  913. AWS_ZERO_STRUCT(*provider);
  914. AWS_ZERO_STRUCT(*impl);
  915. aws_credentials_provider_init_base(provider, allocator, &s_aws_credentials_provider_sts_web_identity_vtable, impl);
  916. if (!options->tls_ctx) {
  917. AWS_LOGF_ERROR(
  918. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  919. "a TLS context must be provided to the STS web identity credentials provider");
  920. aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  921. return NULL;
  922. }
  923. aws_tls_connection_options_init_from_ctx(&tls_connection_options, options->tls_ctx);
  924. struct aws_byte_cursor host = aws_byte_cursor_from_buf(&parameters->endpoint);
  925. if (aws_tls_connection_options_set_server_name(&tls_connection_options, allocator, &host)) {
  926. AWS_LOGF_ERROR(
  927. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  928. "(id=%p): failed to create a tls connection options with error %s",
  929. (void *)provider,
  930. aws_error_str(aws_last_error()));
  931. goto on_error;
  932. }
  933. struct aws_socket_options socket_options;
  934. AWS_ZERO_STRUCT(socket_options);
  935. socket_options.type = AWS_SOCKET_STREAM;
  936. socket_options.domain = AWS_SOCKET_IPV4;
  937. socket_options.connect_timeout_ms = (uint32_t)aws_timestamp_convert(
  938. STS_WEB_IDENTITY_CONNECT_TIMEOUT_DEFAULT_IN_SECONDS, AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_MILLIS, NULL);
  939. struct aws_http_connection_manager_options manager_options;
  940. AWS_ZERO_STRUCT(manager_options);
  941. manager_options.bootstrap = options->bootstrap;
  942. manager_options.initial_window_size = STS_WEB_IDENTITY_RESPONSE_SIZE_LIMIT;
  943. manager_options.socket_options = &socket_options;
  944. manager_options.host = host;
  945. manager_options.port = 443;
  946. manager_options.max_connections = 2;
  947. manager_options.shutdown_complete_callback = s_on_connection_manager_shutdown;
  948. manager_options.shutdown_complete_user_data = provider;
  949. manager_options.tls_connection_options = &tls_connection_options;
  950. impl->function_table = options->function_table;
  951. if (impl->function_table == NULL) {
  952. impl->function_table = g_aws_credentials_provider_http_function_table;
  953. }
  954. impl->connection_manager = impl->function_table->aws_http_connection_manager_new(allocator, &manager_options);
  955. if (impl->connection_manager == NULL) {
  956. goto on_error;
  957. }
  958. impl->role_arn = aws_string_new_from_array(allocator, parameters->role_arn.buffer, parameters->role_arn.len);
  959. if (impl->role_arn == NULL) {
  960. goto on_error;
  961. }
  962. impl->role_session_name =
  963. aws_string_new_from_array(allocator, parameters->role_session_name.buffer, parameters->role_session_name.len);
  964. if (impl->role_session_name == NULL) {
  965. goto on_error;
  966. }
  967. impl->token_file_path =
  968. aws_string_new_from_array(allocator, parameters->token_file_path.buffer, parameters->token_file_path.len);
  969. if (impl->token_file_path == NULL) {
  970. goto on_error;
  971. }
  972. provider->shutdown_options = options->shutdown_options;
  973. s_parameters_destroy(parameters);
  974. aws_tls_connection_options_clean_up(&tls_connection_options);
  975. return provider;
  976. on_error:
  977. aws_credentials_provider_destroy(provider);
  978. s_parameters_destroy(parameters);
  979. aws_tls_connection_options_clean_up(&tls_connection_options);
  980. return NULL;
  981. }