token_provider_sso_profile.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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/auth/private/sso_token_providers.h>
  9. #include <aws/auth/private/sso_token_utils.h>
  10. #include <aws/common/clock.h>
  11. #ifdef _MSC_VER
  12. /* allow non-constant declared initializers. */
  13. # pragma warning(disable : 4204)
  14. #endif
  15. /*
  16. * sso-token profile provider implementation
  17. */
  18. struct aws_token_provider_profile_impl {
  19. struct aws_string *sso_token_file_path;
  20. aws_io_clock_fn *system_clock_fn;
  21. };
  22. static int s_token_provider_profile_get_token(
  23. struct aws_credentials_provider *provider,
  24. aws_on_get_credentials_callback_fn callback,
  25. void *user_data) {
  26. struct aws_token_provider_profile_impl *impl = provider->impl;
  27. struct aws_sso_token *sso_token = NULL;
  28. struct aws_credentials *credentials = NULL;
  29. int result = AWS_OP_ERR;
  30. sso_token = aws_sso_token_new_from_file(provider->allocator, impl->sso_token_file_path);
  31. if (!sso_token) {
  32. AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "(id=%p) failed to get sso token from file", (void *)provider);
  33. goto done;
  34. }
  35. /* check token expiration. */
  36. uint64_t now_ns = UINT64_MAX;
  37. if (impl->system_clock_fn(&now_ns) != AWS_OP_SUCCESS) {
  38. goto done;
  39. }
  40. if (aws_date_time_as_nanos(&sso_token->expiration) <= now_ns) {
  41. AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "(id=%p) cached sso token is expired.", (void *)provider);
  42. aws_raise_error(AWS_AUTH_SSO_TOKEN_EXPIRED);
  43. goto done;
  44. }
  45. credentials = aws_credentials_new_token(
  46. provider->allocator,
  47. aws_byte_cursor_from_string(sso_token->access_token),
  48. (uint64_t)aws_date_time_as_epoch_secs(&sso_token->expiration));
  49. if (!credentials) {
  50. AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "(id=%p) Unable to construct credentials.", (void *)provider);
  51. goto done;
  52. }
  53. callback(credentials, AWS_OP_SUCCESS, user_data);
  54. result = AWS_OP_SUCCESS;
  55. done:
  56. aws_sso_token_destroy(sso_token);
  57. aws_credentials_release(credentials);
  58. return result;
  59. }
  60. static void s_token_provider_profile_destroy(struct aws_credentials_provider *provider) {
  61. struct aws_token_provider_profile_impl *impl = provider->impl;
  62. if (impl == NULL) {
  63. return;
  64. }
  65. aws_string_destroy(impl->sso_token_file_path);
  66. aws_credentials_provider_invoke_shutdown_callback(provider);
  67. aws_mem_release(provider->allocator, provider);
  68. }
  69. static struct aws_credentials_provider_vtable s_aws_token_provider_profile_vtable = {
  70. .get_credentials = s_token_provider_profile_get_token,
  71. .destroy = s_token_provider_profile_destroy,
  72. };
  73. AWS_STRING_FROM_LITERAL(s_profile_sso_start_url_name, "sso_start_url");
  74. static struct aws_string *s_construct_profile_sso_token_path(
  75. struct aws_allocator *allocator,
  76. const struct aws_token_provider_sso_profile_options *options) {
  77. struct aws_profile_collection *config_collection = NULL;
  78. struct aws_string *profile_name = NULL;
  79. struct aws_string *sso_token_path = NULL;
  80. profile_name = aws_get_profile_name(allocator, &options->profile_name_override);
  81. if (!profile_name) {
  82. AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "token-provider-sso-profile: failed to resolve profile name");
  83. aws_raise_error(AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE);
  84. goto cleanup;
  85. }
  86. if (options->config_file_cached) {
  87. /* Use cached config file */
  88. config_collection = aws_profile_collection_acquire(options->config_file_cached);
  89. } else {
  90. /* load config file */
  91. config_collection = aws_load_profile_collection_from_config_file(allocator, options->config_file_name_override);
  92. }
  93. if (!config_collection) {
  94. AWS_LOGF_ERROR(
  95. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  96. "token-provider-sso-profile: could not load or parse"
  97. " a config file.");
  98. aws_raise_error(AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE);
  99. goto cleanup;
  100. }
  101. const struct aws_profile *profile = aws_profile_collection_get_profile(config_collection, profile_name);
  102. if (!profile) {
  103. AWS_LOGF_ERROR(
  104. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  105. "token-provider-sso-profile: could not load"
  106. " a profile at %s.",
  107. aws_string_c_str(profile_name));
  108. aws_raise_error(AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE);
  109. goto cleanup;
  110. }
  111. const struct aws_profile_property *sso_start_url_property =
  112. aws_profile_get_property(profile, s_profile_sso_start_url_name);
  113. if (!sso_start_url_property) {
  114. AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "token-provider-sso-profile: failed to find sso_start_url");
  115. aws_raise_error(AWS_AUTH_SSO_TOKEN_PROVIDER_SOURCE_FAILURE);
  116. goto cleanup;
  117. }
  118. sso_token_path = aws_construct_sso_token_path(allocator, aws_profile_property_get_value(sso_start_url_property));
  119. if (!sso_token_path) {
  120. AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "token-provider-sso-profile: failed to construct token path");
  121. goto cleanup;
  122. }
  123. cleanup:
  124. aws_string_destroy(profile_name);
  125. aws_profile_collection_release(config_collection);
  126. return sso_token_path;
  127. }
  128. struct aws_credentials_provider *aws_token_provider_new_sso_profile(
  129. struct aws_allocator *allocator,
  130. const struct aws_token_provider_sso_profile_options *options) {
  131. struct aws_string *token_path = s_construct_profile_sso_token_path(allocator, options);
  132. if (!token_path) {
  133. return NULL;
  134. }
  135. struct aws_credentials_provider *provider = NULL;
  136. struct aws_token_provider_profile_impl *impl = NULL;
  137. aws_mem_acquire_many(
  138. allocator,
  139. 2,
  140. &provider,
  141. sizeof(struct aws_credentials_provider),
  142. &impl,
  143. sizeof(struct aws_token_provider_profile_impl));
  144. AWS_ZERO_STRUCT(*provider);
  145. AWS_ZERO_STRUCT(*impl);
  146. aws_credentials_provider_init_base(provider, allocator, &s_aws_token_provider_profile_vtable, impl);
  147. impl->sso_token_file_path = aws_string_new_from_string(allocator, token_path);
  148. provider->shutdown_options = options->shutdown_options;
  149. if (options->system_clock_fn) {
  150. impl->system_clock_fn = options->system_clock_fn;
  151. } else {
  152. impl->system_clock_fn = aws_sys_clock_get_ticks;
  153. }
  154. aws_string_destroy(token_path);
  155. return provider;
  156. }