credentials_provider_process.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  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/process.h>
  12. #include <aws/common/string.h>
  13. #if defined(_MSC_VER)
  14. # pragma warning(disable : 4204)
  15. #endif /* _MSC_VER */
  16. struct aws_credentials_provider_process_impl {
  17. struct aws_string *command;
  18. };
  19. static int s_get_credentials_from_process(
  20. struct aws_credentials_provider *provider,
  21. aws_on_get_credentials_callback_fn callback,
  22. void *user_data) {
  23. struct aws_credentials_provider_process_impl *impl = provider->impl;
  24. struct aws_credentials *credentials = NULL;
  25. struct aws_run_command_options options = {
  26. .command = aws_string_c_str(impl->command),
  27. };
  28. struct aws_run_command_result result;
  29. int ret = AWS_OP_ERR;
  30. if (aws_run_command_result_init(provider->allocator, &result)) {
  31. goto on_finish;
  32. }
  33. if (aws_run_command(provider->allocator, &options, &result) || result.ret_code || !result.std_out) {
  34. AWS_LOGF_ERROR(
  35. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  36. "(id=%p) Failed to source credentials from running process credentials provider with command: %s, err:%s",
  37. (void *)provider,
  38. aws_string_c_str(impl->command),
  39. aws_error_str(aws_last_error()));
  40. goto on_finish;
  41. }
  42. struct aws_parse_credentials_from_json_doc_options parse_options = {
  43. .access_key_id_name = "AccessKeyId",
  44. .secret_access_key_name = "SecretAccessKey",
  45. .token_name = "Token",
  46. .expiration_name = "Expiration",
  47. .token_required = false,
  48. .expiration_required = false,
  49. };
  50. credentials = aws_parse_credentials_from_json_document(
  51. provider->allocator, aws_byte_cursor_from_string(result.std_out), &parse_options);
  52. if (!credentials) {
  53. AWS_LOGF_INFO(
  54. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  55. "(id=%p) Process credentials provider failed to parse credentials from command output (output is not "
  56. "logged in case sensitive information).",
  57. (void *)provider);
  58. goto on_finish;
  59. }
  60. AWS_LOGF_INFO(
  61. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  62. "(id=%p) Process credentials provider successfully sourced credentials.",
  63. (void *)provider);
  64. ret = AWS_OP_SUCCESS;
  65. on_finish:
  66. ;
  67. int error_code = AWS_ERROR_SUCCESS;
  68. if (credentials == NULL) {
  69. error_code = aws_last_error();
  70. if (error_code == AWS_ERROR_SUCCESS) {
  71. error_code = AWS_AUTH_CREDENTIALS_PROVIDER_PROCESS_SOURCE_FAILURE;
  72. }
  73. }
  74. callback(credentials, error_code, user_data);
  75. aws_run_command_result_cleanup(&result);
  76. aws_credentials_release(credentials);
  77. return ret;
  78. }
  79. static void s_credentials_provider_process_destroy(struct aws_credentials_provider *provider) {
  80. struct aws_credentials_provider_process_impl *impl = provider->impl;
  81. if (impl) {
  82. aws_string_destroy_secure(impl->command);
  83. }
  84. aws_credentials_provider_invoke_shutdown_callback(provider);
  85. aws_mem_release(provider->allocator, provider);
  86. }
  87. AWS_STATIC_STRING_FROM_LITERAL(s_credentials_process, "credential_process");
  88. static struct aws_byte_cursor s_default_profile_name_cursor = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("default");
  89. static struct aws_profile_collection *s_load_profile(struct aws_allocator *allocator) {
  90. struct aws_profile_collection *config_profiles = NULL;
  91. struct aws_string *config_file_path = NULL;
  92. config_file_path = aws_get_config_file_path(allocator, NULL);
  93. if (!config_file_path) {
  94. AWS_LOGF_ERROR(
  95. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  96. "Failed to resolve config file path during process credentials provider initialization: %s",
  97. aws_error_str(aws_last_error()));
  98. goto on_done;
  99. }
  100. config_profiles = aws_profile_collection_new_from_file(allocator, config_file_path, AWS_PST_CONFIG);
  101. if (config_profiles != NULL) {
  102. AWS_LOGF_DEBUG(
  103. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  104. "Successfully built config profile collection from file at (%s)",
  105. aws_string_c_str(config_file_path));
  106. } else {
  107. AWS_LOGF_ERROR(
  108. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  109. "Failed to build config profile collection from file at (%s) : %s",
  110. aws_string_c_str(config_file_path),
  111. aws_error_str(aws_last_error()));
  112. goto on_done;
  113. }
  114. on_done:
  115. aws_string_destroy(config_file_path);
  116. return config_profiles;
  117. }
  118. static void s_check_or_get_with_profile_config(
  119. struct aws_allocator *allocator,
  120. const struct aws_profile *profile,
  121. const struct aws_string *config_key,
  122. struct aws_byte_buf *target) {
  123. if (!allocator || !profile || !config_key || !target) {
  124. return;
  125. }
  126. if (!target->len) {
  127. aws_byte_buf_clean_up(target);
  128. const struct aws_profile_property *property = aws_profile_get_property(profile, config_key);
  129. if (property) {
  130. aws_byte_buf_init_copy_from_cursor(
  131. target, allocator, aws_byte_cursor_from_string(aws_profile_property_get_value(property)));
  132. }
  133. }
  134. }
  135. static struct aws_byte_cursor s_stderr_redirect_to_stdout = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL(" 2>&1");
  136. static struct aws_string *s_get_command(struct aws_allocator *allocator, struct aws_byte_cursor profile_cursor) {
  137. struct aws_byte_buf command_buf;
  138. AWS_ZERO_STRUCT(command_buf);
  139. struct aws_string *command = NULL;
  140. struct aws_profile_collection *config_profiles = NULL;
  141. struct aws_string *profile_name = NULL;
  142. const struct aws_profile *profile = NULL;
  143. config_profiles = s_load_profile(allocator);
  144. if (profile_cursor.len == 0) {
  145. profile_name = aws_get_profile_name(allocator, &s_default_profile_name_cursor);
  146. } else {
  147. profile_name = aws_string_new_from_array(allocator, profile_cursor.ptr, profile_cursor.len);
  148. }
  149. if (config_profiles && profile_name) {
  150. profile = aws_profile_collection_get_profile(config_profiles, profile_name);
  151. }
  152. if (!profile) {
  153. AWS_LOGF_ERROR(
  154. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  155. "Failed to resolve config profile during process credentials provider initialization.");
  156. goto on_finish;
  157. }
  158. s_check_or_get_with_profile_config(allocator, profile, s_credentials_process, &command_buf);
  159. if (!command_buf.len) {
  160. AWS_LOGF_ERROR(
  161. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  162. "Failed to resolve credentials_process command during process credentials provider initialization.");
  163. goto on_finish;
  164. }
  165. if (aws_byte_buf_append_dynamic(&command_buf, &s_stderr_redirect_to_stdout)) {
  166. goto on_finish;
  167. }
  168. command = aws_string_new_from_array(allocator, command_buf.buffer, command_buf.len);
  169. if (!command) {
  170. goto on_finish;
  171. }
  172. AWS_LOGF_DEBUG(
  173. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  174. "Successfully loaded credentials_process command for process credentials provider.");
  175. on_finish:
  176. aws_string_destroy(profile_name);
  177. aws_profile_collection_destroy(config_profiles);
  178. aws_byte_buf_clean_up_secure(&command_buf);
  179. return command;
  180. }
  181. static struct aws_credentials_provider_vtable s_aws_credentials_provider_process_vtable = {
  182. .get_credentials = s_get_credentials_from_process,
  183. .destroy = s_credentials_provider_process_destroy,
  184. };
  185. struct aws_credentials_provider *aws_credentials_provider_new_process(
  186. struct aws_allocator *allocator,
  187. const struct aws_credentials_provider_process_options *options) {
  188. struct aws_credentials_provider *provider = NULL;
  189. struct aws_credentials_provider_process_impl *impl = NULL;
  190. aws_mem_acquire_many(
  191. allocator,
  192. 2,
  193. &provider,
  194. sizeof(struct aws_credentials_provider),
  195. &impl,
  196. sizeof(struct aws_credentials_provider_process_impl));
  197. if (!provider) {
  198. goto on_error;
  199. }
  200. AWS_ZERO_STRUCT(*provider);
  201. AWS_ZERO_STRUCT(*impl);
  202. impl->command = s_get_command(allocator, options->profile_to_use);
  203. if (!impl->command) {
  204. goto on_error;
  205. }
  206. aws_credentials_provider_init_base(provider, allocator, &s_aws_credentials_provider_process_vtable, impl);
  207. provider->shutdown_options = options->shutdown_options;
  208. AWS_LOGF_TRACE(
  209. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  210. "(id=%p): Successfully initializing a process credentials provider.",
  211. (void *)provider);
  212. return provider;
  213. on_error:
  214. aws_mem_release(allocator, provider);
  215. return NULL;
  216. }