123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859 |
- /**
- * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
- * SPDX-License-Identifier: Apache-2.0.
- */
- #include <aws/auth/credentials.h>
- #include <aws/auth/private/credentials_utils.h>
- #include <aws/common/clock.h>
- #include <aws/common/json.h>
- #include <aws/common/string.h>
- #include <aws/http/connection.h>
- #include <aws/http/connection_manager.h>
- #include <aws/http/request_response.h>
- #include <aws/http/status_code.h>
- #include <aws/io/channel_bootstrap.h>
- #include <aws/io/retry_strategy.h>
- #include <aws/io/socket.h>
- #include <aws/io/stream.h>
- #include <aws/io/tls_channel_handler.h>
- #include <inttypes.h>
- #define COGNITO_CONNECT_TIMEOUT_DEFAULT_IN_SECONDS 5
- #define COGNITO_MAX_RETRIES 8
- #define HTTP_REQUEST_BODY_INITIAL_SIZE 1024
- #define HTTP_RESPONSE_BODY_INITIAL_SIZE 4096
- static void s_on_connection_manager_shutdown(void *user_data);
- static void s_on_connection_setup_fn(struct aws_http_connection *connection, int error_code, void *user_data);
- struct aws_cognito_login {
- struct aws_byte_cursor identity_provider_name;
- struct aws_byte_cursor identity_provider_token;
- struct aws_byte_buf login_buffer;
- };
- static int s_aws_cognito_login_init(
- struct aws_cognito_login *login,
- struct aws_allocator *allocator,
- struct aws_byte_cursor identity_provider_name,
- struct aws_byte_cursor identity_provider_token) {
- AWS_ZERO_STRUCT(*login);
- login->identity_provider_name = identity_provider_name;
- login->identity_provider_token = identity_provider_token;
- return aws_byte_buf_init_cache_and_update_cursors(
- &login->login_buffer, allocator, &login->identity_provider_name, &login->identity_provider_token, NULL);
- }
- static void s_aws_cognito_login_clean_up(struct aws_cognito_login *login) {
- aws_byte_buf_clean_up(&login->login_buffer);
- AWS_ZERO_STRUCT(*login);
- }
- struct aws_credentials_provider_cognito_impl {
- struct aws_http_connection_manager *connection_manager;
- struct aws_retry_strategy *retry_strategy;
- const struct aws_auth_http_system_vtable *function_table;
- struct aws_string *endpoint;
- struct aws_string *identity;
- struct aws_array_list logins;
- struct aws_string *custom_role_arn;
- };
- struct cognito_user_data {
- struct aws_allocator *allocator;
- struct aws_credentials_provider *provider;
- aws_on_get_credentials_callback_fn *original_callback;
- void *original_user_data;
- struct aws_http_connection *connection;
- struct aws_http_message *get_credentials_request;
- struct aws_byte_buf request_body_buffer;
- struct aws_input_stream *request_body_stream;
- struct aws_retry_token *retry_token;
- struct aws_credentials *credentials;
- struct aws_byte_buf response_body;
- };
- static void s_user_data_reset(struct cognito_user_data *user_data) {
- aws_byte_buf_clean_up(&user_data->request_body_buffer);
- user_data->request_body_stream = aws_input_stream_release(user_data->request_body_stream);
- user_data->get_credentials_request = aws_http_message_release(user_data->get_credentials_request);
- struct aws_credentials_provider_cognito_impl *impl = user_data->provider->impl;
- if (user_data->connection != NULL) {
- impl->function_table->aws_http_connection_manager_release_connection(
- impl->connection_manager, user_data->connection);
- user_data->connection = NULL;
- }
- aws_byte_buf_reset(&user_data->response_body, false);
- }
- static void s_user_data_destroy(struct cognito_user_data *user_data) {
- if (user_data == NULL) {
- return;
- }
- s_user_data_reset(user_data);
- aws_byte_buf_clean_up(&user_data->response_body);
- aws_retry_token_release(user_data->retry_token);
- aws_credentials_provider_release(user_data->provider);
- aws_credentials_release(user_data->credentials);
- aws_mem_release(user_data->allocator, user_data);
- }
- static struct cognito_user_data *s_user_data_new(
- struct aws_credentials_provider *provider,
- aws_on_get_credentials_callback_fn callback,
- void *user_data) {
- struct aws_allocator *allocator = provider->allocator;
- struct cognito_user_data *cognito_user_data = aws_mem_calloc(allocator, 1, sizeof(struct cognito_user_data));
- cognito_user_data->allocator = allocator;
- aws_byte_buf_init(&cognito_user_data->response_body, cognito_user_data->allocator, HTTP_RESPONSE_BODY_INITIAL_SIZE);
- cognito_user_data->provider = aws_credentials_provider_acquire(provider);
- cognito_user_data->original_callback = callback;
- cognito_user_data->original_user_data = user_data;
- return cognito_user_data;
- }
- static void s_finalize_credentials_query(struct cognito_user_data *user_data, int error_code) {
- AWS_FATAL_ASSERT(user_data != NULL);
- if (user_data->credentials == NULL && error_code == AWS_ERROR_SUCCESS) {
- error_code = AWS_AUTH_CREDENTIALS_PROVIDER_COGNITO_SOURCE_FAILURE;
- }
- (user_data->original_callback)(user_data->credentials, error_code, user_data->original_user_data);
- s_user_data_destroy(user_data);
- }
- /* Keys per Cognito-Identity service model */
- AWS_STATIC_STRING_FROM_LITERAL(s_credentials_key, "Credentials");
- AWS_STATIC_STRING_FROM_LITERAL(s_access_key_id_name, "AccessKeyId");
- AWS_STATIC_STRING_FROM_LITERAL(s_secret_access_key_name, "SecretKey");
- AWS_STATIC_STRING_FROM_LITERAL(s_session_token_name, "SessionToken");
- AWS_STATIC_STRING_FROM_LITERAL(s_expiration_name, "Expiration");
- static int s_parse_credentials_from_response(struct cognito_user_data *user_data) {
- int result = AWS_OP_ERR;
- struct aws_json_value *response_document =
- aws_json_value_new_from_string(user_data->allocator, aws_byte_cursor_from_buf(&user_data->response_body));
- if (response_document == NULL) {
- goto done;
- }
- struct aws_json_value *credentials_entry =
- aws_json_value_get_from_object(response_document, aws_byte_cursor_from_string(s_credentials_key));
- if (credentials_entry == NULL) {
- goto done;
- }
- struct aws_parse_credentials_from_json_doc_options credentials_parse_options = {
- .access_key_id_name = aws_string_c_str(s_access_key_id_name),
- .secret_access_key_name = aws_string_c_str(s_secret_access_key_name),
- .token_name = aws_string_c_str(s_session_token_name),
- .expiration_name = aws_string_c_str(s_expiration_name),
- .expiration_format = AWS_PCEF_NUMBER_UNIX_EPOCH,
- .token_required = true,
- .expiration_required = true,
- };
- user_data->credentials =
- aws_parse_credentials_from_aws_json_object(user_data->allocator, credentials_entry, &credentials_parse_options);
- if (user_data->credentials == NULL) {
- goto done;
- }
- result = AWS_OP_SUCCESS;
- done:
- aws_json_value_destroy(response_document);
- if (result != AWS_OP_SUCCESS) {
- aws_raise_error(AWS_AUTH_PROVIDER_PARSER_UNEXPECTED_RESPONSE);
- }
- return result;
- }
- static void s_on_retry_ready(struct aws_retry_token *token, int error_code, void *user_data) {
- (void)token;
- struct cognito_user_data *provider_user_data = user_data;
- if (error_code != AWS_ERROR_SUCCESS) {
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): Cognito credentials provider retry task failed: %s",
- (void *)provider_user_data->provider,
- aws_error_str(error_code));
- s_finalize_credentials_query(user_data, error_code);
- return;
- }
- s_user_data_reset(provider_user_data);
- struct aws_credentials_provider_cognito_impl *impl = provider_user_data->provider->impl;
- impl->function_table->aws_http_connection_manager_acquire_connection(
- impl->connection_manager, s_on_connection_setup_fn, provider_user_data);
- }
- static void s_on_stream_complete_fn(struct aws_http_stream *stream, int error_code, void *user_data) {
- struct cognito_user_data *provider_user_data = user_data;
- struct aws_credentials_provider_cognito_impl *impl = provider_user_data->provider->impl;
- int http_response_code = 0;
- impl->function_table->aws_http_stream_get_incoming_response_status(stream, &http_response_code);
- if (http_response_code != 200) {
- error_code = AWS_AUTH_CREDENTIALS_PROVIDER_HTTP_STATUS_FAILURE;
- }
- impl->function_table->aws_http_stream_release(stream);
- AWS_LOGF_DEBUG(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): GetCredentialsForIdentity call completed with http status %d",
- (void *)provider_user_data->provider,
- http_response_code);
- if (http_response_code == AWS_HTTP_STATUS_CODE_200_OK) {
- aws_retry_token_record_success(provider_user_data->retry_token);
- if (s_parse_credentials_from_response(provider_user_data) == AWS_OP_SUCCESS) {
- s_finalize_credentials_query(user_data, AWS_ERROR_SUCCESS);
- return;
- }
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): Cognito credentials provider failed to parse GetCredentialsForIdentity response",
- (void *)provider_user_data->provider);
- error_code = AWS_AUTH_PROVIDER_PARSER_UNEXPECTED_RESPONSE;
- }
- /* Success path is done, error-only from here on out */
- /* Unsure if this should be unconditional or a function of status code. STS does this unconditionally. */
- impl->function_table->aws_http_connection_close(provider_user_data->connection);
- enum aws_retry_error_type error_type =
- aws_credentials_provider_compute_retry_error_type(http_response_code, error_code);
- bool can_retry = http_response_code == 0 || error_type != AWS_RETRY_ERROR_TYPE_CLIENT_ERROR;
- if (!can_retry) {
- s_finalize_credentials_query(user_data, error_code);
- return;
- }
- if (aws_retry_strategy_schedule_retry(
- provider_user_data->retry_token, error_type, s_on_retry_ready, provider_user_data)) {
- error_code = aws_last_error();
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): Cognito credentials provider failed to schedule retry: %s",
- (void *)provider_user_data->provider,
- aws_error_str(error_code));
- s_finalize_credentials_query(user_data, error_code);
- return;
- }
- }
- static int s_on_incoming_body_fn(struct aws_http_stream *stream, const struct aws_byte_cursor *data, void *user_data) {
- (void)stream;
- struct cognito_user_data *provider_user_data = user_data;
- return aws_byte_buf_append_dynamic(&provider_user_data->response_body, data);
- }
- AWS_STATIC_STRING_FROM_LITERAL(s_identity_id_key, "IdentityId");
- AWS_STATIC_STRING_FROM_LITERAL(s_custom_role_arn_key, "CustomRoleArn");
- AWS_STATIC_STRING_FROM_LITERAL(s_logins_key, "Logins");
- int s_create_get_credentials_for_identity_body_buffer(
- struct aws_byte_buf *buffer,
- struct cognito_user_data *provider_user_data) {
- struct aws_allocator *allocator = provider_user_data->allocator;
- struct aws_credentials_provider_cognito_impl *impl = provider_user_data->provider->impl;
- int result = AWS_OP_ERR;
- struct aws_json_value *json_body = aws_json_value_new_object(allocator);
- if (json_body == NULL) {
- return AWS_OP_ERR;
- }
- struct aws_json_value *identity_string =
- aws_json_value_new_string(allocator, aws_byte_cursor_from_string(impl->identity));
- if (identity_string == NULL) {
- goto done;
- }
- if (aws_json_value_add_to_object(json_body, aws_byte_cursor_from_string(s_identity_id_key), identity_string)) {
- aws_json_value_destroy(identity_string);
- goto done;
- }
- if (impl->custom_role_arn != NULL) {
- struct aws_json_value *custom_role_arn_string =
- aws_json_value_new_string(allocator, aws_byte_cursor_from_string(impl->custom_role_arn));
- if (custom_role_arn_string == NULL) {
- goto done;
- }
- if (aws_json_value_add_to_object(
- json_body, aws_byte_cursor_from_string(s_custom_role_arn_key), custom_role_arn_string)) {
- aws_json_value_destroy(custom_role_arn_string);
- goto done;
- }
- }
- size_t login_count = aws_array_list_length(&impl->logins);
- if (login_count > 0) {
- struct aws_json_value *logins = aws_json_value_new_object(allocator);
- if (logins == NULL) {
- goto done;
- }
- if (aws_json_value_add_to_object(json_body, aws_byte_cursor_from_string(s_logins_key), logins)) {
- aws_json_value_destroy(logins);
- goto done;
- }
- for (size_t i = 0; i < login_count; ++i) {
- struct aws_cognito_login login;
- if (aws_array_list_get_at(&impl->logins, &login, i)) {
- goto done;
- }
- struct aws_json_value *login_value_string =
- aws_json_value_new_string(allocator, login.identity_provider_token);
- if (login_value_string == NULL) {
- goto done;
- }
- if (aws_json_value_add_to_object(logins, login.identity_provider_name, login_value_string)) {
- aws_json_value_destroy(login_value_string);
- goto done;
- }
- }
- }
- if (aws_byte_buf_append_json_string(json_body, buffer)) {
- goto done;
- }
- result = AWS_OP_SUCCESS;
- done:
- aws_json_value_destroy(json_body);
- return result;
- }
- static struct aws_http_header s_content_type_header = {
- .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("content-type"),
- .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("application/x-amz-json-1.1"),
- };
- AWS_STATIC_STRING_FROM_LITERAL(s_get_credentials_for_identity_path, "/");
- static struct aws_http_header s_x_amz_target_header = {
- .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("X-Amz-Target"),
- .value = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("AWSCognitoIdentityService.GetCredentialsForIdentity"),
- };
- static int s_create_get_credentials_for_identity_request(struct cognito_user_data *provider_user_data) {
- struct aws_credentials_provider_cognito_impl *impl = provider_user_data->provider->impl;
- struct aws_byte_buf body_buffer;
- AWS_ZERO_STRUCT(body_buffer);
- struct aws_input_stream *body_stream = NULL;
- struct aws_http_message *request = aws_http_message_new_request(provider_user_data->allocator);
- if (request == NULL) {
- return AWS_OP_ERR;
- }
- if (aws_http_message_set_request_method(request, aws_http_method_post)) {
- goto on_error;
- }
- if (aws_http_message_set_request_path(request, aws_byte_cursor_from_string(s_get_credentials_for_identity_path))) {
- goto on_error;
- }
- struct aws_http_header host_header = {
- .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("host"),
- .value = aws_byte_cursor_from_string(impl->endpoint),
- };
- if (aws_http_message_add_header(request, host_header)) {
- goto on_error;
- }
- if (aws_http_message_add_header(request, s_content_type_header)) {
- goto on_error;
- }
- if (aws_http_message_add_header(request, s_x_amz_target_header)) {
- goto on_error;
- }
- if (aws_byte_buf_init(&body_buffer, provider_user_data->allocator, HTTP_REQUEST_BODY_INITIAL_SIZE)) {
- goto on_error;
- }
- if (s_create_get_credentials_for_identity_body_buffer(&body_buffer, provider_user_data)) {
- goto on_error;
- }
- char content_length[21];
- AWS_ZERO_ARRAY(content_length);
- snprintf(content_length, sizeof(content_length), "%" PRIu64, (uint64_t)body_buffer.len);
- struct aws_http_header content_length_header = {
- .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Content-Length"),
- .value = aws_byte_cursor_from_c_str(content_length),
- };
- if (aws_http_message_add_header(request, content_length_header)) {
- goto on_error;
- }
- struct aws_byte_cursor payload_cur = aws_byte_cursor_from_buf(&body_buffer);
- body_stream = aws_input_stream_new_from_cursor(provider_user_data->allocator, &payload_cur);
- if (body_stream == NULL) {
- goto on_error;
- }
- aws_http_message_set_body_stream(request, body_stream);
- provider_user_data->get_credentials_request = request;
- provider_user_data->request_body_buffer = body_buffer;
- provider_user_data->request_body_stream = body_stream;
- return AWS_OP_SUCCESS;
- on_error:
- aws_byte_buf_clean_up(&body_buffer);
- aws_input_stream_release(body_stream);
- aws_http_message_release(request);
- return AWS_OP_ERR;
- }
- static void s_on_connection_setup_fn(struct aws_http_connection *connection, int error_code, void *user_data) {
- struct cognito_user_data *wrapped_user_data = user_data;
- struct aws_http_stream *stream = NULL;
- struct aws_credentials_provider_cognito_impl *impl = wrapped_user_data->provider->impl;
- if (connection == NULL) {
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): Cognito credentials provider failed to acquire http connection: %s",
- (void *)wrapped_user_data->provider,
- aws_error_debug_str(error_code));
- goto on_error;
- }
- wrapped_user_data->connection = connection;
- if (s_create_get_credentials_for_identity_request(wrapped_user_data)) {
- error_code = aws_last_error();
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): Cognito credentials provider failed to create http request: %s",
- (void *)wrapped_user_data->provider,
- aws_error_debug_str(error_code));
- goto on_error;
- }
- struct aws_http_make_request_options options = {
- .user_data = user_data,
- .request = wrapped_user_data->get_credentials_request,
- .self_size = sizeof(struct aws_http_make_request_options),
- .on_response_headers = NULL,
- .on_response_header_block_done = NULL,
- .on_response_body = s_on_incoming_body_fn,
- .on_complete = s_on_stream_complete_fn,
- };
- stream = impl->function_table->aws_http_connection_make_request(connection, &options);
- if (!stream) {
- error_code = aws_last_error();
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): Cognito credentials provider failed to create http stream: %s",
- (void *)wrapped_user_data->provider,
- aws_error_debug_str(error_code));
- goto on_error;
- }
- if (impl->function_table->aws_http_stream_activate(stream)) {
- error_code = aws_last_error();
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): Cognito credentials provider failed to activate http stream: %s",
- (void *)wrapped_user_data->provider,
- aws_error_debug_str(error_code));
- goto on_error;
- }
- return;
- on_error:
- impl->function_table->aws_http_stream_release(stream);
- s_finalize_credentials_query(wrapped_user_data, error_code);
- }
- static void s_on_retry_token_acquired(
- struct aws_retry_strategy *strategy,
- int error_code,
- struct aws_retry_token *token,
- void *user_data) {
- (void)strategy;
- struct cognito_user_data *wrapped_user_data = user_data;
- if (token == NULL) {
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): Cognito credentials provider failed to acquire retry token: %s",
- (void *)wrapped_user_data->provider,
- aws_error_debug_str(error_code));
- s_finalize_credentials_query(wrapped_user_data, error_code);
- return;
- }
- wrapped_user_data->retry_token = token;
- struct aws_credentials_provider_cognito_impl *impl = wrapped_user_data->provider->impl;
- impl->function_table->aws_http_connection_manager_acquire_connection(
- impl->connection_manager, s_on_connection_setup_fn, wrapped_user_data);
- }
- static int s_credentials_provider_cognito_get_credentials_async(
- struct aws_credentials_provider *provider,
- aws_on_get_credentials_callback_fn callback,
- void *user_data) {
- struct aws_credentials_provider_cognito_impl *impl = provider->impl;
- struct cognito_user_data *wrapped_user_data = s_user_data_new(provider, callback, user_data);
- if (wrapped_user_data == NULL) {
- goto on_error;
- }
- if (aws_retry_strategy_acquire_retry_token(
- impl->retry_strategy, NULL, s_on_retry_token_acquired, wrapped_user_data, 100)) {
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): Cognito credentials provider failed to acquire retry token with error %s",
- (void *)provider,
- aws_error_debug_str(aws_last_error()));
- goto on_error;
- }
- return AWS_OP_SUCCESS;
- on_error:
- s_user_data_destroy(wrapped_user_data);
- return AWS_OP_ERR;
- }
- static void s_credentials_provider_cognito_destroy(struct aws_credentials_provider *provider) {
- struct aws_credentials_provider_cognito_impl *impl = provider->impl;
- if (impl == NULL) {
- return;
- }
- /* aws_http_connection_manager_release will eventually leads to call of s_on_connection_manager_shutdown,
- * which will do memory release for provider and impl.
- */
- if (impl->connection_manager) {
- impl->function_table->aws_http_connection_manager_release(impl->connection_manager);
- } else {
- /* If provider setup failed halfway through, connection_manager might not exist.
- * In this case invoke shutdown completion callback directly to finish cleanup */
- s_on_connection_manager_shutdown(provider);
- }
- /* freeing the provider takes place in the shutdown callback below */
- }
- static struct aws_credentials_provider_vtable s_aws_credentials_provider_cognito_vtable = {
- .get_credentials = s_credentials_provider_cognito_get_credentials_async,
- .destroy = s_credentials_provider_cognito_destroy,
- };
- static void s_on_connection_manager_shutdown(void *user_data) {
- struct aws_credentials_provider *provider = user_data;
- aws_credentials_provider_invoke_shutdown_callback(provider);
- struct aws_credentials_provider_cognito_impl *impl = provider->impl;
- aws_retry_strategy_release(impl->retry_strategy);
- aws_string_destroy(impl->endpoint);
- aws_string_destroy(impl->identity);
- aws_string_destroy(impl->custom_role_arn);
- for (size_t i = 0; i < aws_array_list_length(&impl->logins); ++i) {
- struct aws_cognito_login login;
- if (aws_array_list_get_at(&impl->logins, &login, i)) {
- continue;
- }
- s_aws_cognito_login_clean_up(&login);
- }
- aws_array_list_clean_up(&impl->logins);
- aws_mem_release(provider->allocator, provider);
- }
- static int s_validate_options(const struct aws_credentials_provider_cognito_options *options) {
- if (options == NULL) {
- return AWS_OP_ERR;
- }
- if (options->tls_ctx == NULL) {
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(static) Cognito credentials provider options must include a TLS context");
- return AWS_OP_ERR;
- }
- if (options->bootstrap == NULL) {
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(static) Cognito credentials provider options must include a client bootstrap");
- return AWS_OP_ERR;
- }
- if (options->endpoint.len == 0) {
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(static) Cognito credentials provider options must have a non-empty endpoint");
- return AWS_OP_ERR;
- }
- if (options->identity.len == 0) {
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(static) Cognito credentials provider options must have a non-empty identity");
- return AWS_OP_ERR;
- }
- return AWS_OP_SUCCESS;
- }
- struct aws_credentials_provider *aws_credentials_provider_new_cognito(
- struct aws_allocator *allocator,
- const struct aws_credentials_provider_cognito_options *options) {
- struct aws_credentials_provider *provider = NULL;
- struct aws_credentials_provider_cognito_impl *impl = NULL;
- if (s_validate_options(options)) {
- aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
- return NULL;
- }
- aws_mem_acquire_many(
- allocator,
- 2,
- &provider,
- sizeof(struct aws_credentials_provider),
- &impl,
- sizeof(struct aws_credentials_provider_cognito_impl));
- if (!provider) {
- return NULL;
- }
- AWS_ZERO_STRUCT(*provider);
- AWS_ZERO_STRUCT(*impl);
- aws_credentials_provider_init_base(provider, allocator, &s_aws_credentials_provider_cognito_vtable, impl);
- struct aws_tls_connection_options tls_connection_options;
- AWS_ZERO_STRUCT(tls_connection_options);
- aws_tls_connection_options_init_from_ctx(&tls_connection_options, options->tls_ctx);
- struct aws_byte_cursor host = options->endpoint;
- if (aws_tls_connection_options_set_server_name(&tls_connection_options, allocator, &host)) {
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): Cognito credentials provider failed to create tls connection options with error %s",
- (void *)provider,
- aws_error_debug_str(aws_last_error()));
- goto on_error;
- }
- struct aws_socket_options socket_options;
- AWS_ZERO_STRUCT(socket_options);
- socket_options.type = AWS_SOCKET_STREAM;
- socket_options.domain = AWS_SOCKET_IPV4;
- socket_options.connect_timeout_ms = (uint32_t)aws_timestamp_convert(
- COGNITO_CONNECT_TIMEOUT_DEFAULT_IN_SECONDS, AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_MILLIS, NULL);
- struct aws_http_connection_manager_options manager_options;
- AWS_ZERO_STRUCT(manager_options);
- manager_options.bootstrap = options->bootstrap;
- manager_options.initial_window_size = SIZE_MAX;
- manager_options.socket_options = &socket_options;
- manager_options.host = options->endpoint;
- manager_options.port = 443;
- manager_options.max_connections = 2;
- manager_options.shutdown_complete_callback = s_on_connection_manager_shutdown;
- manager_options.shutdown_complete_user_data = provider;
- manager_options.tls_connection_options = &tls_connection_options;
- manager_options.proxy_options = options->http_proxy_options;
- impl->function_table = options->function_table;
- if (impl->function_table == NULL) {
- impl->function_table = g_aws_credentials_provider_http_function_table;
- }
- impl->connection_manager = impl->function_table->aws_http_connection_manager_new(allocator, &manager_options);
- if (impl->connection_manager == NULL) {
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): Cognito credentials provider failed to create http connection manager with error %s",
- (void *)provider,
- aws_error_debug_str(aws_last_error()));
- goto on_error;
- }
- impl->endpoint = aws_string_new_from_cursor(allocator, &options->endpoint);
- impl->identity = aws_string_new_from_cursor(allocator, &options->identity);
- if (options->custom_role_arn != NULL) {
- impl->custom_role_arn = aws_string_new_from_cursor(allocator, options->custom_role_arn);
- }
- aws_array_list_init_dynamic(&impl->logins, allocator, options->login_count, sizeof(struct aws_cognito_login));
- for (size_t i = 0; i < options->login_count; ++i) {
- struct aws_cognito_identity_provider_token_pair *login_token_pair = &options->logins[i];
- struct aws_cognito_login login;
- if (s_aws_cognito_login_init(
- &login,
- allocator,
- login_token_pair->identity_provider_name,
- login_token_pair->identity_provider_token)) {
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): Cognito credentials provider failed to initialize login entry with error %s",
- (void *)provider,
- aws_error_debug_str(aws_last_error()));
- goto on_error;
- }
- aws_array_list_push_back(&impl->logins, &login);
- }
- struct aws_standard_retry_options retry_options = {
- .backoff_retry_options =
- {
- .el_group = options->bootstrap->event_loop_group,
- .max_retries = COGNITO_MAX_RETRIES,
- },
- };
- impl->retry_strategy = aws_retry_strategy_new_standard(allocator, &retry_options);
- if (!impl->retry_strategy) {
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): Cognito credentials provider failed to create a retry strategy with error %s",
- (void *)provider,
- aws_error_debug_str(aws_last_error()));
- goto on_error;
- }
- provider->shutdown_options = options->shutdown_options;
- aws_tls_connection_options_clean_up(&tls_connection_options);
- return provider;
- on_error:
- aws_tls_connection_options_clean_up(&tls_connection_options);
- aws_credentials_provider_destroy(provider);
- return NULL;
- }
- /*************************************************************************/
- #define DEFAULT_CREDENTIAL_PROVIDER_REFRESH_MS (15 * 60 * 1000)
- /*
- * Cognito provider with caching implementation
- */
- struct aws_credentials_provider *aws_credentials_provider_new_cognito_caching(
- struct aws_allocator *allocator,
- const struct aws_credentials_provider_cognito_options *options) {
- struct aws_credentials_provider *cognito_provider = NULL;
- struct aws_credentials_provider *caching_provider = NULL;
- cognito_provider = aws_credentials_provider_new_cognito(allocator, options);
- if (cognito_provider == NULL) {
- goto on_error;
- }
- struct aws_credentials_provider_cached_options cached_options = {
- .source = cognito_provider,
- .refresh_time_in_milliseconds = DEFAULT_CREDENTIAL_PROVIDER_REFRESH_MS,
- };
- caching_provider = aws_credentials_provider_new_cached(allocator, &cached_options);
- if (caching_provider == NULL) {
- goto on_error;
- }
- aws_credentials_provider_release(cognito_provider);
- return caching_provider;
- on_error:
- aws_credentials_provider_release(caching_provider);
- aws_credentials_provider_release(cognito_provider);
- return NULL;
- }
|