diff --git a/include/aws/auth/credentials.h b/include/aws/auth/credentials.h index 1388cb03..b260a2cc 100644 --- a/include/aws/auth/credentials.h +++ b/include/aws/auth/credentials.h @@ -715,6 +715,24 @@ struct aws_credentials_provider_cognito_options { struct aws_auth_http_system_vtable *function_table; }; +/** + * Configuration options for `aws_credentials_new_with_options` + */ +struct aws_credentials_options { + + /* Value for the aws access key id field */ + struct aws_byte_cursor access_key_id_cursor; + /* Value for the secret access key field */ + struct aws_byte_cursor secret_access_key_cursor; + /* (Optional) security token associated with the credentials */ + struct aws_byte_cursor session_token_cursor; + /* (Optional) account id associated with the credentials */ + struct aws_byte_cursor account_id_cursor; + /* Time point, in seconds since epoch, that the credentials will no longer be valid. + * For credentials that do not expire, use UINT64_MAX. */ + uint64_t expiration_timepoint_seconds; +}; + AWS_EXTERN_C_BEGIN /* @@ -758,13 +776,9 @@ struct aws_credentials *aws_credentials_new( * @return a valid credentials object, or NULL */ AWS_AUTH_API -struct aws_credentials *aws_credentials_new_with_account_id( +struct aws_credentials *aws_credentials_new_with_options( struct aws_allocator *allocator, - struct aws_byte_cursor access_key_id_cursor, - struct aws_byte_cursor secret_access_key_cursor, - struct aws_byte_cursor session_token_cursor, - struct aws_byte_cursor account_id_cursor, - uint64_t expiration_timepoint_seconds); + const struct aws_credentials_options *options); /** * Creates a new set of aws anonymous credentials. diff --git a/include/aws/auth/private/credentials_utils.h b/include/aws/auth/private/credentials_utils.h index 041023b0..dddaf865 100644 --- a/include/aws/auth/private/credentials_utils.h +++ b/include/aws/auth/private/credentials_utils.h @@ -84,6 +84,7 @@ struct aws_parse_credentials_from_json_doc_options { const char *secret_access_key_name; const char *token_name; const char *expiration_name; + const char *account_id_name; const char *top_level_object_name; enum aws_parse_credentials_expiration_format expiration_format; bool token_required; @@ -192,6 +193,13 @@ struct aws_profile_collection *aws_load_profile_collection_from_config_file( AWS_AUTH_API struct aws_string *aws_credentials_provider_resolve_region_from_env(struct aws_allocator *allocator); +/* + * Parses account_id from arn with the format arn:partition:service:region:account-id:resource-id + * Returns an empty cursor if the account_id is not present or unable to parse the account_id + */ +AWS_AUTH_API +struct aws_byte_cursor aws_parse_account_id_from_arn(struct aws_byte_cursor arn); + AWS_EXTERN_C_END #endif /* AWS_AUTH_CREDENTIALS_PRIVATE_H */ diff --git a/source/aws_profile.c b/source/aws_profile.c index 26a6b153..36b13dea 100644 --- a/source/aws_profile.c +++ b/source/aws_profile.c @@ -24,6 +24,7 @@ static const struct aws_string *s_profile_get_property_value( AWS_STATIC_STRING_FROM_LITERAL(s_access_key_id_profile_var, "aws_access_key_id"); AWS_STATIC_STRING_FROM_LITERAL(s_secret_access_key_profile_var, "aws_secret_access_key"); AWS_STATIC_STRING_FROM_LITERAL(s_session_token_profile_var, "aws_session_token"); +AWS_STATIC_STRING_FROM_LITERAL(s_account_id_profile_var, "aws_account_id"); struct aws_credentials *aws_credentials_new_from_profile( struct aws_allocator *allocator, @@ -35,6 +36,14 @@ struct aws_credentials *aws_credentials_new_from_profile( } const struct aws_string *session_token = s_profile_get_property_value(profile, s_session_token_profile_var); - - return aws_credentials_new_from_string(allocator, access_key, secret_key, session_token, UINT64_MAX); + const struct aws_string *account_id = s_profile_get_property_value(profile, s_account_id_profile_var); + struct aws_credentials_options creds_option = { + .access_key_id_cursor = aws_byte_cursor_from_string(access_key), + .secret_access_key_cursor = aws_byte_cursor_from_string(secret_key), + .session_token_cursor = aws_byte_cursor_from_string(session_token), + .account_id_cursor = aws_byte_cursor_from_string(account_id), + .expiration_timepoint_seconds = UINT64_MAX, + }; + + return aws_credentials_new_with_options(allocator, &creds_option); } diff --git a/source/credentials.c b/source/credentials.c index b4e4b731..200e9471 100644 --- a/source/credentials.c +++ b/source/credentials.c @@ -96,30 +96,25 @@ struct aws_credentials *aws_credentials_new( struct aws_byte_cursor account_id; AWS_ZERO_STRUCT(account_id); - - return aws_credentials_new_with_account_id( - allocator, - access_key_id_cursor, - secret_access_key_cursor, - session_token_cursor, - account_id, - expiration_timepoint_seconds); + struct aws_credentials_options creds_option = { + .access_key_id_cursor = access_key_id_cursor, + .secret_access_key_cursor = secret_access_key_cursor, + .session_token_cursor = session_token_cursor, + .account_id_cursor = account_id, + .expiration_timepoint_seconds = expiration_timepoint_seconds, + }; + return aws_credentials_new_with_options(allocator, &creds_option); } - -struct aws_credentials *aws_credentials_new_with_account_id( +struct aws_credentials *aws_credentials_new_with_options( struct aws_allocator *allocator, - struct aws_byte_cursor access_key_id_cursor, - struct aws_byte_cursor secret_access_key_cursor, - struct aws_byte_cursor session_token_cursor, - struct aws_byte_cursor account_id_cursor, - uint64_t expiration_timepoint_seconds) { + const struct aws_credentials_options *options) { - if (access_key_id_cursor.ptr == NULL || access_key_id_cursor.len == 0) { + if (options->access_key_id_cursor.ptr == NULL || options->access_key_id_cursor.len == 0) { aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); return NULL; } - if (secret_access_key_cursor.ptr == NULL || secret_access_key_cursor.len == 0) { + if (options->secret_access_key_cursor.ptr == NULL || options->secret_access_key_cursor.len == 0) { aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); return NULL; } @@ -136,34 +131,34 @@ struct aws_credentials *aws_credentials_new_with_account_id( credentials->identity_type = AWS_CREDENTIALS_IDENTITY; struct aws_credentials_identity *credentials_identity = &credentials->identity.credentials_identity; credentials_identity->access_key_id = - aws_string_new_from_array(allocator, access_key_id_cursor.ptr, access_key_id_cursor.len); + aws_string_new_from_array(allocator, options->access_key_id_cursor.ptr, options->access_key_id_cursor.len); if (credentials_identity->access_key_id == NULL) { goto error; } - credentials_identity->secret_access_key = - aws_string_new_from_array(allocator, secret_access_key_cursor.ptr, secret_access_key_cursor.len); + credentials_identity->secret_access_key = aws_string_new_from_array( + allocator, options->secret_access_key_cursor.ptr, options->secret_access_key_cursor.len); if (credentials_identity->secret_access_key == NULL) { goto error; } - if (session_token_cursor.ptr != NULL && session_token_cursor.len > 0) { + if (options->session_token_cursor.ptr != NULL && options->session_token_cursor.len > 0) { credentials_identity->session_token = - aws_string_new_from_array(allocator, session_token_cursor.ptr, session_token_cursor.len); + aws_string_new_from_array(allocator, options->session_token_cursor.ptr, options->session_token_cursor.len); if (credentials_identity->session_token == NULL) { goto error; } } - if (account_id_cursor.ptr != NULL && account_id_cursor.len > 0) { + if (options->account_id_cursor.ptr != NULL && options->account_id_cursor.len > 0) { credentials_identity->account_id = - aws_string_new_from_array(allocator, account_id_cursor.ptr, account_id_cursor.len); + aws_string_new_from_array(allocator, options->account_id_cursor.ptr, options->account_id_cursor.len); if (credentials_identity->account_id == NULL) { goto error; } } - credentials->expiration_timepoint_seconds = expiration_timepoint_seconds; + credentials->expiration_timepoint_seconds = options->expiration_timepoint_seconds; return credentials; @@ -334,6 +329,7 @@ struct aws_credentials *aws_credentials_new_from_string( const struct aws_string *secret_access_key, const struct aws_string *session_token, uint64_t expiration_timepoint_seconds) { + struct aws_byte_cursor access_key_cursor = aws_byte_cursor_from_string(access_key_id); struct aws_byte_cursor secret_access_key_cursor = aws_byte_cursor_from_string(secret_access_key); struct aws_byte_cursor session_token_cursor; diff --git a/source/credentials_provider_ecs.c b/source/credentials_provider_ecs.c index e38c782c..303d0b04 100644 --- a/source/credentials_provider_ecs.c +++ b/source/credentials_provider_ecs.c @@ -188,6 +188,7 @@ static void s_ecs_finalize_get_credentials_query(struct aws_credentials_provider .access_key_id_name = "AccessKeyId", .secret_access_key_name = "SecretAccessKey", .token_name = "Token", + .account_id_name = "AccountId", .expiration_name = "Expiration", .token_required = true, .expiration_required = true, diff --git a/source/credentials_provider_environment.c b/source/credentials_provider_environment.c index 4b070d9f..c895bd17 100644 --- a/source/credentials_provider_environment.c +++ b/source/credentials_provider_environment.c @@ -12,6 +12,7 @@ AWS_STATIC_STRING_FROM_LITERAL(s_access_key_id_env_var, "AWS_ACCESS_KEY_ID"); AWS_STATIC_STRING_FROM_LITERAL(s_secret_access_key_env_var, "AWS_SECRET_ACCESS_KEY"); AWS_STATIC_STRING_FROM_LITERAL(s_session_token_env_var, "AWS_SESSION_TOKEN"); +AWS_STATIC_STRING_FROM_LITERAL(s_account_id_env_var, "AWS_ACCOUNT_ID"); static int s_credentials_provider_environment_get_credentials_async( struct aws_credentials_provider *provider, @@ -23,16 +24,24 @@ static int s_credentials_provider_environment_get_credentials_async( struct aws_string *access_key_id = NULL; struct aws_string *secret_access_key = NULL; struct aws_string *session_token = NULL; + struct aws_string *account_id = NULL; struct aws_credentials *credentials = NULL; int error_code = AWS_ERROR_SUCCESS; aws_get_environment_value(allocator, s_access_key_id_env_var, &access_key_id); aws_get_environment_value(allocator, s_secret_access_key_env_var, &secret_access_key); aws_get_environment_value(allocator, s_session_token_env_var, &session_token); + aws_get_environment_value(allocator, s_account_id_env_var, &account_id); if (access_key_id != NULL && access_key_id->len > 0 && secret_access_key != NULL && secret_access_key->len > 0) { - credentials = - aws_credentials_new_from_string(allocator, access_key_id, secret_access_key, session_token, UINT64_MAX); + struct aws_credentials_options creds_option = { + .access_key_id_cursor = aws_byte_cursor_from_string(access_key_id), + .secret_access_key_cursor = aws_byte_cursor_from_string(secret_access_key), + .session_token_cursor = aws_byte_cursor_from_string(session_token), + .account_id_cursor = aws_byte_cursor_from_string(account_id), + .expiration_timepoint_seconds = UINT64_MAX, + }; + credentials = aws_credentials_new_with_options(allocator, &creds_option); if (credentials == NULL) { error_code = aws_last_error(); } @@ -54,6 +63,7 @@ static int s_credentials_provider_environment_get_credentials_async( callback(credentials, error_code, user_data); aws_credentials_release(credentials); + aws_string_destroy(account_id); aws_string_destroy(session_token); aws_string_destroy(secret_access_key); aws_string_destroy(access_key_id); diff --git a/source/credentials_provider_process.c b/source/credentials_provider_process.c index a78c661a..611424d2 100644 --- a/source/credentials_provider_process.c +++ b/source/credentials_provider_process.c @@ -50,6 +50,7 @@ static int s_get_credentials_from_process( .access_key_id_name = "AccessKeyId", .secret_access_key_name = "SecretAccessKey", .token_name = "SessionToken", + .account_id_name = "AccountId", .expiration_name = "Expiration", .token_required = false, .expiration_required = false, diff --git a/source/credentials_provider_sso.c b/source/credentials_provider_sso.c index 818cbeb3..44bdffa5 100644 --- a/source/credentials_provider_sso.c +++ b/source/credentials_provider_sso.c @@ -56,6 +56,7 @@ struct aws_sso_query_context { struct aws_retry_token *retry_token; struct aws_byte_buf path_and_query; struct aws_string *token; + struct aws_string *sso_account_id; int status_code; int error_code; @@ -91,6 +92,7 @@ static void s_sso_query_context_destroy(struct aws_sso_query_context *sso_query_ s_sso_query_context_reset_request_specific_data(sso_query_context); aws_byte_buf_clean_up(&sso_query_context->payload); aws_byte_buf_clean_up(&sso_query_context->path_and_query); + aws_string_destroy(sso_query_context->sso_account_id); aws_credentials_provider_release(sso_query_context->provider); aws_retry_token_release(sso_query_context->retry_token); aws_mem_release(sso_query_context->allocator, sso_query_context); @@ -108,6 +110,7 @@ static struct aws_sso_query_context *s_sso_query_context_new( sso_query_context->provider = aws_credentials_provider_acquire(provider); sso_query_context->original_user_data = user_data; sso_query_context->original_callback = callback; + sso_query_context->sso_account_id = aws_string_new_from_string(provider->allocator, impl->sso_account_id); /* construct path and query */ struct aws_byte_cursor account_id_cursor = aws_byte_cursor_from_string(impl->sso_account_id); @@ -139,6 +142,7 @@ static struct aws_sso_query_context *s_sso_query_context_new( */ static void s_finalize_get_credentials_query(struct aws_sso_query_context *sso_query_context) { struct aws_credentials *credentials = NULL; + struct aws_credentials *credentials_with_account_id = NULL; if (sso_query_context->error_code == AWS_ERROR_SUCCESS) { /* parse credentials */ @@ -162,6 +166,14 @@ static void s_finalize_get_credentials_query(struct aws_sso_query_context *sso_q AWS_LS_AUTH_CREDENTIALS_PROVIDER, "(id=%p) successfully queried credentials", (void *)sso_query_context->provider); + struct aws_credentials_options creds_option = { + .access_key_id_cursor = aws_credentials_get_access_key_id(credentials), + .secret_access_key_cursor = aws_credentials_get_secret_access_key(credentials), + .session_token_cursor = aws_credentials_get_session_token(credentials), + .account_id_cursor = aws_byte_cursor_from_string(sso_query_context->sso_account_id), + .expiration_timepoint_seconds = aws_credentials_get_expiration_timepoint_seconds(credentials), + }; + credentials_with_account_id = aws_credentials_new_with_options(sso_query_context->allocator, &creds_option); } else { AWS_LOGF_ERROR( AWS_LS_AUTH_CREDENTIALS_PROVIDER, @@ -175,11 +187,12 @@ static void s_finalize_get_credentials_query(struct aws_sso_query_context *sso_q /* pass the credentials back */ sso_query_context->original_callback( - credentials, sso_query_context->error_code, sso_query_context->original_user_data); + credentials_with_account_id, sso_query_context->error_code, sso_query_context->original_user_data); /* clean up */ s_sso_query_context_destroy(sso_query_context); aws_credentials_release(credentials); + aws_credentials_release(credentials_with_account_id); } static void s_on_retry_ready(struct aws_retry_token *token, int error_code, void *user_data); diff --git a/source/credentials_provider_static.c b/source/credentials_provider_static.c index 41d678c6..5e9eb8f1 100644 --- a/source/credentials_provider_static.c +++ b/source/credentials_provider_static.c @@ -50,14 +50,14 @@ struct aws_credentials_provider *aws_credentials_provider_new_static( } AWS_ZERO_STRUCT(*provider); - - struct aws_credentials *credentials = aws_credentials_new_with_account_id( - allocator, - options->access_key_id, - options->secret_access_key, - options->session_token, - options->account_id, - UINT64_MAX); + struct aws_credentials_options creds_option = { + .access_key_id_cursor = options->access_key_id, + .secret_access_key_cursor = options->secret_access_key, + .session_token_cursor = options->session_token, + .account_id_cursor = options->account_id, + .expiration_timepoint_seconds = UINT64_MAX, + }; + struct aws_credentials *credentials = aws_credentials_new_with_options(allocator, &creds_option); if (credentials == NULL) { goto on_new_credentials_failure; } diff --git a/source/credentials_provider_sts.c b/source/credentials_provider_sts.c index 38927711..7793065b 100644 --- a/source/credentials_provider_sts.c +++ b/source/credentials_provider_sts.c @@ -40,6 +40,7 @@ static int s_sts_xml_on_AssumeRoleResponse_child(struct aws_xml_node *, void *); static int s_sts_xml_on_AssumeRoleResult_child(struct aws_xml_node *, void *); static int s_sts_xml_on_Credentials_child(struct aws_xml_node *, void *); +static int s_sts_xml_on_AssumedRoleUser_child(struct aws_xml_node *, void *); static struct aws_http_header s_content_type_header = { .name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("content-type"), @@ -75,6 +76,7 @@ struct sts_creds_provider_user_data { struct aws_string *access_key_id; struct aws_string *secret_access_key; struct aws_string *session_token; + struct aws_string *account_id; aws_on_get_credentials_callback_fn *callback; struct aws_http_connection *connection; struct aws_byte_buf payload_body; @@ -124,6 +126,9 @@ static void s_reset_request_specific_data(struct sts_creds_provider_user_data *u aws_string_destroy(user_data->session_token); user_data->session_token = NULL; + + aws_string_destroy(user_data->account_id); + user_data->account_id = NULL; } static void s_clean_up_user_data(struct sts_creds_provider_user_data *user_data) { user_data->callback(user_data->credentials, user_data->error_code, user_data->user_data); @@ -229,6 +234,27 @@ static int s_sts_xml_on_AssumeRoleResult_child(struct aws_xml_node *node, void * if (aws_byte_cursor_eq_c_str_ignore_case(&node_name, "Credentials")) { return aws_xml_node_traverse(node, s_sts_xml_on_Credentials_child, user_data); } + if (aws_byte_cursor_eq_c_str_ignore_case(&node_name, "AssumedRoleUser")) { + return aws_xml_node_traverse(node, s_sts_xml_on_AssumedRoleUser_child, user_data); + } + + return AWS_OP_SUCCESS; +} + +static int s_sts_xml_on_AssumedRoleUser_child(struct aws_xml_node *node, void *user_data) { + struct sts_creds_provider_user_data *provider_user_data = user_data; + struct aws_byte_cursor node_name = aws_xml_node_get_name(node); + struct aws_byte_cursor arn_cursor; + AWS_ZERO_STRUCT(arn_cursor); + + if (aws_byte_cursor_eq_c_str_ignore_case(&node_name, "Arn")) { + if (aws_xml_node_as_body(node, &arn_cursor)) { + return AWS_OP_ERR; + } + struct aws_byte_cursor account_id = aws_parse_account_id_from_arn(arn_cursor); + provider_user_data->account_id = aws_string_new_from_cursor(provider_user_data->allocator, &account_id); + } + return AWS_OP_SUCCESS; } @@ -373,13 +399,15 @@ static void s_on_stream_complete_fn(struct aws_http_stream *stream, int error_co if (provider_user_data->access_key_id && provider_user_data->secret_access_key && provider_user_data->session_token) { - - provider_user_data->credentials = aws_credentials_new_from_string( - provider_user_data->allocator, - provider_user_data->access_key_id, - provider_user_data->secret_access_key, - provider_user_data->session_token, - now_seconds + provider_impl->duration_seconds); + struct aws_credentials_options creds_option = { + .access_key_id_cursor = aws_byte_cursor_from_string(provider_user_data->access_key_id), + .secret_access_key_cursor = aws_byte_cursor_from_string(provider_user_data->secret_access_key), + .session_token_cursor = aws_byte_cursor_from_string(provider_user_data->session_token), + .account_id_cursor = aws_byte_cursor_from_string(provider_user_data->account_id), + .expiration_timepoint_seconds = now_seconds + provider_impl->duration_seconds, + }; + provider_user_data->credentials = + aws_credentials_new_with_options(provider_user_data->allocator, &creds_option); } if (provider_user_data->credentials == NULL) { diff --git a/source/credentials_provider_sts_web_identity.c b/source/credentials_provider_sts_web_identity.c index f42244b8..ede5f983 100644 --- a/source/credentials_provider_sts_web_identity.c +++ b/source/credentials_provider_sts_web_identity.c @@ -41,6 +41,7 @@ static int s_stswebid_error_xml_on_Error_child(struct aws_xml_node *, void *); static int s_stswebid_200_xml_on_AssumeRoleWithWebIdentityResponse_child(struct aws_xml_node *, void *); static int s_stswebid_200_xml_on_AssumeRoleWithWebIdentityResult_child(struct aws_xml_node *, void *); static int s_stswebid_200_xml_on_Credentials_child(struct aws_xml_node *, void *); +static int s_stswebid_xml_on_AssumedRoleUser_child(struct aws_xml_node *, void *); struct aws_credentials_provider_sts_web_identity_impl { struct aws_http_connection_manager *connection_manager; @@ -69,6 +70,7 @@ struct sts_web_identity_user_data { struct aws_string *access_key_id; struct aws_string *secret_access_key; struct aws_string *session_token; + struct aws_string *account_id; uint64_t expiration_timepoint_in_seconds; struct aws_byte_buf payload_buf; @@ -96,6 +98,9 @@ static void s_user_data_reset_request_and_response(struct sts_web_identity_user_ aws_string_destroy_secure(user_data->session_token); user_data->session_token = NULL; + + aws_string_destroy(user_data->account_id); + user_data->account_id = NULL; } static void s_user_data_destroy(struct sts_web_identity_user_data *user_data) { @@ -261,15 +266,32 @@ static int s_stswebid_200_xml_on_AssumeRoleWithWebIdentityResponse_child( return AWS_OP_SUCCESS; } -static int s_stswebid_200_xml_on_AssumeRoleWithWebIdentityResult_child( - struct aws_xml_node *node, - - void *user_data) { +static int s_stswebid_200_xml_on_AssumeRoleWithWebIdentityResult_child(struct aws_xml_node *node, void *user_data) { struct aws_byte_cursor node_name = aws_xml_node_get_name(node); if (aws_byte_cursor_eq_c_str_ignore_case(&node_name, "Credentials")) { return aws_xml_node_traverse(node, s_stswebid_200_xml_on_Credentials_child, user_data); } + if (aws_byte_cursor_eq_c_str_ignore_case(&node_name, "AssumedRoleUser")) { + return aws_xml_node_traverse(node, s_stswebid_xml_on_AssumedRoleUser_child, user_data); + } + return AWS_OP_SUCCESS; +} + +static int s_stswebid_xml_on_AssumedRoleUser_child(struct aws_xml_node *node, void *user_data) { + struct sts_web_identity_user_data *query_user_data = user_data; + struct aws_byte_cursor node_name = aws_xml_node_get_name(node); + struct aws_byte_cursor arn_cursor; + AWS_ZERO_STRUCT(arn_cursor); + + if (aws_byte_cursor_eq_c_str_ignore_case(&node_name, "Arn")) { + if (aws_xml_node_as_body(node, &arn_cursor)) { + return AWS_OP_ERR; + } + struct aws_byte_cursor account_id = aws_parse_account_id_from_arn(arn_cursor); + query_user_data->account_id = aws_string_new_from_cursor(query_user_data->allocator, &account_id); + } + return AWS_OP_SUCCESS; } @@ -363,13 +385,14 @@ static struct aws_credentials *s_parse_credentials_from_response( AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "STS web identity not found in XML response."); goto on_finish; } - - credentials = aws_credentials_new( - query_user_data->allocator, - aws_byte_cursor_from_string(query_user_data->access_key_id), - aws_byte_cursor_from_string(query_user_data->secret_access_key), - aws_byte_cursor_from_string(query_user_data->session_token), - query_user_data->expiration_timepoint_in_seconds); + struct aws_credentials_options creds_option = { + .access_key_id_cursor = aws_byte_cursor_from_string(query_user_data->access_key_id), + .secret_access_key_cursor = aws_byte_cursor_from_string(query_user_data->secret_access_key), + .session_token_cursor = aws_byte_cursor_from_string(query_user_data->session_token), + .account_id_cursor = aws_byte_cursor_from_string(query_user_data->account_id), + .expiration_timepoint_seconds = query_user_data->expiration_timepoint_in_seconds, + }; + credentials = aws_credentials_new_with_options(query_user_data->allocator, &creds_option); if (credentials == NULL) { AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "Failed to create credentials for sts web identity"); diff --git a/source/credentials_utils.c b/source/credentials_utils.c index 35323fa3..cf500584 100644 --- a/source/credentials_utils.c +++ b/source/credentials_utils.c @@ -171,8 +171,9 @@ struct aws_credentials *aws_parse_credentials_from_aws_json_object( struct aws_credentials *credentials = NULL; struct aws_json_value *access_key_id = NULL; - struct aws_json_value *secrete_access_key = NULL; + struct aws_json_value *secret_access_key = NULL; struct aws_json_value *token = NULL; + struct aws_json_value *account_id = NULL; struct aws_json_value *creds_expiration = NULL; bool parse_error = true; @@ -189,19 +190,21 @@ struct aws_credentials *aws_parse_credentials_from_aws_json_object( goto done; } - struct aws_byte_cursor secrete_access_key_cursor; - secrete_access_key = aws_json_value_get_from_object( + struct aws_byte_cursor secret_access_key_cursor; + secret_access_key = aws_json_value_get_from_object( document_root, aws_byte_cursor_from_c_str((char *)options->secret_access_key_name)); - if (!aws_json_value_is_string(secrete_access_key) || - aws_json_value_get_string(secrete_access_key, &secrete_access_key_cursor) == AWS_OP_ERR) { + if (!aws_json_value_is_string(secret_access_key) || + aws_json_value_get_string(secret_access_key, &secret_access_key_cursor) == AWS_OP_ERR) { AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "Failed to parse SecretAccessKey from Json document."); goto done; } struct aws_byte_cursor token_cursor; + AWS_ZERO_STRUCT(token_cursor); if (options->token_name) { token = aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str((char *)options->token_name)); - if (!aws_json_value_is_string(token) || aws_json_value_get_string(token, &token_cursor) == AWS_OP_ERR) { + if (!aws_json_value_is_string(token) || aws_json_value_get_string(token, &token_cursor) == AWS_OP_ERR || + token_cursor.len == 0) { if (options->token_required) { AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "Failed to parse Token from Json document."); goto done; @@ -209,6 +212,17 @@ struct aws_credentials *aws_parse_credentials_from_aws_json_object( } } + struct aws_byte_cursor account_id_cursor; + AWS_ZERO_STRUCT(account_id_cursor); + if (options->account_id_name) { + account_id = + aws_json_value_get_from_object(document_root, aws_byte_cursor_from_c_str((char *)options->account_id_name)); + if (!aws_json_value_is_string(account_id) || + aws_json_value_get_string(account_id, &account_id_cursor) == AWS_OP_ERR) { + AWS_LOGF_DEBUG(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "Failed to parse account_id from Json document."); + } + } + // needed to avoid uninitialized local variable error uint64_t expiration_timepoint_in_seconds = UINT64_MAX; if (options->expiration_name) { @@ -226,31 +240,20 @@ struct aws_credentials *aws_parse_credentials_from_aws_json_object( /* * Build the credentials */ - if (access_key_id_cursor.len == 0 || secrete_access_key_cursor.len == 0) { + if (access_key_id_cursor.len == 0 || secret_access_key_cursor.len == 0) { AWS_LOGF_ERROR( AWS_LS_AUTH_CREDENTIALS_PROVIDER, "Parsed an unexpected credentials json document, either access key, secret key is empty."); goto done; } - - struct aws_byte_cursor session_token_cursor; - AWS_ZERO_STRUCT(session_token_cursor); - - if (token) { - aws_json_value_get_string(token, &session_token_cursor); - if (options->token_required && session_token_cursor.len == 0) { - AWS_LOGF_ERROR( - AWS_LS_AUTH_CREDENTIALS_PROVIDER, "Parsed an unexpected credentials json document with empty token."); - goto done; - } - } - - credentials = aws_credentials_new( - allocator, - access_key_id_cursor, - secrete_access_key_cursor, - session_token_cursor, - expiration_timepoint_in_seconds); + struct aws_credentials_options creds_option = { + .access_key_id_cursor = access_key_id_cursor, + .secret_access_key_cursor = secret_access_key_cursor, + .session_token_cursor = token_cursor, + .account_id_cursor = account_id_cursor, + .expiration_timepoint_seconds = expiration_timepoint_in_seconds, + }; + credentials = aws_credentials_new_with_options(allocator, &creds_option); if (credentials == NULL) { AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "Failed to allocate memory for credentials."); @@ -463,3 +466,22 @@ struct aws_string *aws_credentials_provider_resolve_region_from_env(struct aws_a aws_get_environment_value(allocator, s_default_region_env, ®ion); return region; } + +struct aws_byte_cursor aws_parse_account_id_from_arn(struct aws_byte_cursor arn) { + struct aws_byte_cursor account_id; + AWS_ZERO_STRUCT(account_id); + /* The format of the Arn is arn:partition:service:region:account-id:resource-ID and we need to parse the + * account-id out of it which is the fifth element. */ + for (int i = 0; i < 5; i++) { + if (!aws_byte_cursor_next_split(&arn, ':', &account_id)) { + AWS_LOGF_ERROR( + AWS_LS_AUTH_CREDENTIALS_PROVIDER, + "Failed to parse account_id string from STS xml response: %s", + aws_error_str(aws_last_error())); + struct aws_byte_cursor empty; + AWS_ZERO_STRUCT(empty); + return empty; + } + } + return account_id; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 478efddd..b4a7d98f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -19,6 +19,7 @@ add_test_case(cached_credentials_provider_queued_async_test) add_test_case(profile_credentials_provider_new_destroy_defaults_test) add_test_case(profile_credentials_provider_cached_test) add_test_case(profile_credentials_provider_default_test) +add_test_case(profile_credentials_provider_account_id_test) add_test_case(profile_credentials_provider_nondefault_test) add_test_case(profile_credentials_provider_environment_test) add_test_case(credentials_provider_first_in_chain_test) @@ -51,6 +52,7 @@ add_net_test_case(credentials_provider_ecs_request_failure) add_net_test_case(credentials_provider_ecs_bad_document_failure) add_net_test_case(credentials_provider_ecs_bad_host_failure) add_net_test_case(credentials_provider_ecs_basic_success) +add_net_test_case(credentials_provider_ecs_basic_success_with_account_id) add_net_test_case(credentials_provider_ecs_basic_success_token_file) add_net_test_case(credentials_provider_ecs_basic_success_uri_env) add_net_test_case(credentials_provider_ecs_no_auth_token_success) @@ -113,6 +115,8 @@ add_test_case(credentials_provider_process_new_failed) add_test_case(credentials_provider_process_bad_command) add_test_case(credentials_provider_process_incorrect_command_output) add_test_case(credentials_provider_process_basic_success) +add_test_case(credentials_provider_process_basic_success_without_session_token) +add_test_case(credentials_provider_process_basic_success_with_account_id) add_test_case(credentials_provider_process_success_ignores_stderr) add_test_case(credentials_provider_process_basic_success_from_profile_provider) add_test_case(credentials_provider_process_basic_success_cached) @@ -191,6 +195,7 @@ add_test_case(profile_override_test) add_test_case(profile_environment_test) add_test_case(credentials_utils_construct_endpoint_test) +add_test_case(credentials_utils_parse_account_id_from_arn) add_test_case(sigv4_skip_xray_header_test) add_test_case(sigv4_skip_user_agent_header_test) diff --git a/tests/credentials_provider_ecs_tests.c b/tests/credentials_provider_ecs_tests.c index 4cefd777..ddb49688 100644 --- a/tests/credentials_provider_ecs_tests.c +++ b/tests/credentials_provider_ecs_tests.c @@ -556,9 +556,14 @@ AWS_STATIC_STRING_FROM_LITERAL( s_good_response, "{\"AccessKeyId\":\"SuccessfulAccessKey\", \n \"SecretAccessKey\":\"SuccessfulSecret\", \n " "\"Token\":\"TokenSuccess\", \n \"Expiration\":\"2020-02-25T06:03:31Z\"}"); +AWS_STATIC_STRING_FROM_LITERAL( + s_good_response_with_account_id, + "{\"AccessKeyId\":\"SuccessfulAccessKey\", \n \"SecretAccessKey\":\"SuccessfulSecret\", \n " + "\"Token\":\"TokenSuccess\", \n \"Expiration\":\"2020-02-25T06:03:31Z\", \"AccountId\":\"AccountId123\"}"); AWS_STATIC_STRING_FROM_LITERAL(s_good_access_key_id, "SuccessfulAccessKey"); AWS_STATIC_STRING_FROM_LITERAL(s_good_secret_access_key, "SuccessfulSecret"); AWS_STATIC_STRING_FROM_LITERAL(s_good_session_token, "TokenSuccess"); +AWS_STATIC_STRING_FROM_LITERAL(s_good_account_id, "AccountId123"); AWS_STATIC_STRING_FROM_LITERAL(s_good_response_expiration, "2020-02-25T06:03:31Z"); /* Check that expected URI and Authorization token were used to make request. @@ -590,7 +595,8 @@ static int s_do_ecs_success_test( struct aws_allocator *allocator, struct aws_credentials_provider_ecs_options *options, const char *expected_uri, - const char *expected_token) { + const char *expected_token, + const struct aws_string *expected_account_id) { struct aws_credentials_provider *provider = aws_credentials_provider_new_ecs(allocator, options); aws_credentials_provider_get_credentials(provider, s_get_credentials_callback, NULL); @@ -605,6 +611,11 @@ static int s_do_ecs_success_test( ASSERT_CURSOR_VALUE_STRING_EQUALS( aws_credentials_get_secret_access_key(s_tester.credentials), s_good_secret_access_key); ASSERT_CURSOR_VALUE_STRING_EQUALS(aws_credentials_get_session_token(s_tester.credentials), s_good_session_token); + if (expected_account_id) { + ASSERT_CURSOR_VALUE_STRING_EQUALS(aws_credentials_get_account_id(s_tester.credentials), expected_account_id); + } else { + ASSERT_TRUE(aws_credentials_get_account_id(s_tester.credentials).len == 0); + } struct aws_date_time expiration; struct aws_byte_cursor date_cursor = aws_byte_cursor_from_string(s_good_response_expiration); @@ -726,7 +737,8 @@ static int s_credentials_provider_ecs_basic_success(struct aws_allocator *alloca allocator, &options, "https://www.xxx123321testmocknonexsitingawsservice.com:443/path/to/resource/?a=b&c=d" /*expected_uri*/, - "test-token-1234-abcd" /*expected_token*/)); + "test-token-1234-abcd" /*expected_token*/, + NULL /*expected_account_id*/)); s_aws_ecs_tester_cleanup(); @@ -735,6 +747,44 @@ static int s_credentials_provider_ecs_basic_success(struct aws_allocator *alloca AWS_TEST_CASE(credentials_provider_ecs_basic_success, s_credentials_provider_ecs_basic_success); +static int s_credentials_provider_ecs_basic_success_with_account_id(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + + s_aws_ecs_tester_init(allocator); + + struct aws_byte_cursor good_response_cursor = aws_byte_cursor_from_string(s_good_response_with_account_id); + aws_array_list_push_back(&s_tester.response_data_callbacks, &good_response_cursor); + + struct aws_credentials_provider_ecs_options options = { + .bootstrap = s_tester.bootstrap, + .function_table = &s_mock_function_table, + .shutdown_options = + { + .shutdown_callback = s_on_shutdown_complete, + .shutdown_user_data = NULL, + }, + .host = aws_byte_cursor_from_c_str("www.xxx123321testmocknonexsitingawsservice.com"), + .path_and_query = aws_byte_cursor_from_c_str("/path/to/resource/?a=b&c=d"), + .auth_token = aws_byte_cursor_from_c_str("test-token-1234-abcd"), + .tls_ctx = s_tester.tls_ctx, + }; + + ASSERT_SUCCESS(s_do_ecs_success_test( + allocator, + &options, + "https://www.xxx123321testmocknonexsitingawsservice.com:443/path/to/resource/?a=b&c=d" /*expected_uri*/, + "test-token-1234-abcd" /*expected_token*/, + s_good_account_id /*expected_account_id*/)); + + s_aws_ecs_tester_cleanup(); + + return 0; +} + +AWS_TEST_CASE( + credentials_provider_ecs_basic_success_with_account_id, + s_credentials_provider_ecs_basic_success_with_account_id); + static int s_credentials_provider_ecs_basic_success_token_file(struct aws_allocator *allocator, void *ctx) { (void)ctx; @@ -982,7 +1032,8 @@ static int s_credentials_provider_ecs_no_auth_token_success(struct aws_allocator allocator, &options, "https://www.xxx123321testmocknonexsitingawsservice.com:443/path/to/resource/?a=b&c=d" /*expected_uri*/, - NULL /*expected_token*/)); + NULL /*expected_token*/, + NULL /*expected_account_id=*/)); s_aws_ecs_tester_cleanup(); diff --git a/tests/credentials_provider_process_tests.c b/tests/credentials_provider_process_tests.c index 57b00634..92731d0a 100644 --- a/tests/credentials_provider_process_tests.c +++ b/tests/credentials_provider_process_tests.c @@ -144,6 +144,20 @@ AWS_STATIC_STRING_FROM_LITERAL( "\"Expiration\":\"2020-02-25T06:03:31Z\"}'"); #endif +#ifdef _WIN32 +AWS_STATIC_STRING_FROM_LITERAL( + s_test_command_with_account_id, + "echo {\"Version\": 1, \"AccessKeyId\": \"AccessKey123\", " + "\"SecretAccessKey\": \"SecretAccessKey321\", \"SessionToken\":\"TokenSuccess\", " + "\"Expiration\":\"2020-02-25T06:03:31Z\", \"AccountId\":\"AccountId123\"}"); +#else +AWS_STATIC_STRING_FROM_LITERAL( + s_test_command_with_account_id, + "echo '{\"Version\": 1, \"AccessKeyId\": \"AccessKey123\", " + "\"SecretAccessKey\": \"SecretAccessKey321\", \"SessionToken\":\"TokenSuccess\", " + "\"Expiration\":\"2020-02-25T06:03:31Z\", \"AccountId\":\"AccountId123\"}'"); +#endif + #ifdef _WIN32 AWS_STATIC_STRING_FROM_LITERAL( s_test_command_with_logging_on_stderr, @@ -172,7 +186,9 @@ AWS_STATIC_STRING_FROM_LITERAL(s_bad_command_output, "echo \"Hello, World!\""); AWS_STATIC_STRING_FROM_LITERAL(s_good_access_key_id, "AccessKey123"); AWS_STATIC_STRING_FROM_LITERAL(s_good_secret_access_key, "SecretAccessKey321"); AWS_STATIC_STRING_FROM_LITERAL(s_good_session_token, "TokenSuccess"); -AWS_STATIC_STRING_FROM_LITERAL(s_good_expiration, "2020-02-25T06:03:31Z"); +AWS_STATIC_STRING_FROM_LITERAL(s_good_account_id, "AccountId123"); + +static uint64_t s_good_expiration = 1582610611; AWS_STATIC_STRING_FROM_LITERAL( s_process_config_file_contents, @@ -340,22 +356,45 @@ AWS_TEST_CASE( credentials_provider_process_incorrect_command_output, s_credentials_provider_process_incorrect_command_output); -static int s_verify_credentials(struct aws_credentials *credentials) { +static int s_verify_credentials(struct aws_credentials *credentials, struct aws_credentials *expected_credentials) { ASSERT_NOT_NULL(credentials); - ASSERT_CURSOR_VALUE_STRING_EQUALS(aws_credentials_get_access_key_id(credentials), s_good_access_key_id); - ASSERT_CURSOR_VALUE_STRING_EQUALS(aws_credentials_get_secret_access_key(credentials), s_good_secret_access_key); - ASSERT_CURSOR_VALUE_STRING_EQUALS(aws_credentials_get_session_token(credentials), s_good_session_token); - - struct aws_date_time expiration; - struct aws_byte_cursor date_cursor = aws_byte_cursor_from_string(s_good_expiration); - aws_date_time_init_from_str_cursor(&expiration, &date_cursor, AWS_DATE_FORMAT_ISO_8601); - ASSERT_TRUE( - aws_credentials_get_expiration_timepoint_seconds(s_tester.credentials) == (uint64_t)expiration.timestamp); + ASSERT_NOT_NULL(expected_credentials); + + ASSERT_BIN_ARRAYS_EQUALS( + aws_credentials_get_access_key_id(credentials).ptr, + aws_credentials_get_access_key_id(credentials).len, + aws_credentials_get_access_key_id(expected_credentials).ptr, + aws_credentials_get_access_key_id(expected_credentials).len); + + ASSERT_BIN_ARRAYS_EQUALS( + aws_credentials_get_secret_access_key(credentials).ptr, + aws_credentials_get_secret_access_key(credentials).len, + aws_credentials_get_secret_access_key(expected_credentials).ptr, + aws_credentials_get_secret_access_key(expected_credentials).len); + + ASSERT_BIN_ARRAYS_EQUALS( + aws_credentials_get_session_token(credentials).ptr, + aws_credentials_get_session_token(credentials).len, + aws_credentials_get_session_token(expected_credentials).ptr, + aws_credentials_get_session_token(expected_credentials).len); + + ASSERT_BIN_ARRAYS_EQUALS( + aws_credentials_get_account_id(credentials).ptr, + aws_credentials_get_account_id(credentials).len, + aws_credentials_get_account_id(expected_credentials).ptr, + aws_credentials_get_account_id(expected_credentials).len); + + ASSERT_UINT_EQUALS( + aws_credentials_get_expiration_timepoint_seconds(credentials), + aws_credentials_get_expiration_timepoint_seconds(expected_credentials)); return AWS_OP_SUCCESS; } -static int s_test_command_expect_success(struct aws_allocator *allocator, const struct aws_string *command) { +static int s_test_command_expect_success( + struct aws_allocator *allocator, + const struct aws_string *command, + struct aws_credentials *expected_credentials) { s_aws_process_tester_init(allocator); struct aws_byte_buf content_buf; @@ -388,7 +427,7 @@ static int s_test_command_expect_success(struct aws_allocator *allocator, const s_aws_wait_for_credentials_result(); ASSERT_TRUE(s_tester.has_received_credentials_callback == true); - ASSERT_SUCCESS(s_verify_credentials(s_tester.credentials)); + ASSERT_SUCCESS(s_verify_credentials(s_tester.credentials, expected_credentials)); aws_credentials_provider_release(provider); s_aws_wait_for_provider_shutdown_callback(); @@ -398,15 +437,56 @@ static int s_test_command_expect_success(struct aws_allocator *allocator, const static int s_credentials_provider_process_basic_success(struct aws_allocator *allocator, void *ctx) { (void)ctx; - return s_test_command_expect_success(allocator, s_test_command); + struct aws_credentials *expected_credentials = aws_credentials_new_from_string( + allocator, s_good_access_key_id, s_good_secret_access_key, s_good_session_token, s_good_expiration); + ASSERT_SUCCESS(s_test_command_expect_success(allocator, s_test_command, expected_credentials)); + aws_credentials_release(expected_credentials); + return AWS_OP_SUCCESS; } AWS_TEST_CASE(credentials_provider_process_basic_success, s_credentials_provider_process_basic_success); +static int s_credentials_provider_process_basic_success_without_session_token( + struct aws_allocator *allocator, + void *ctx) { + (void)ctx; + struct aws_credentials *expected_credentials = aws_credentials_new_from_string( + allocator, s_good_access_key_id, s_good_secret_access_key, NULL, s_good_expiration); + ASSERT_SUCCESS(s_test_command_expect_success(allocator, s_test_command_without_token, expected_credentials)); + aws_credentials_release(expected_credentials); + return AWS_OP_SUCCESS; +} +AWS_TEST_CASE( + credentials_provider_process_basic_success_without_session_token, + s_credentials_provider_process_basic_success_without_session_token); + +static int s_credentials_provider_process_basic_success_with_account_id(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + struct aws_credentials_options creds_option = { + .access_key_id_cursor = aws_byte_cursor_from_string(s_good_access_key_id), + .secret_access_key_cursor = aws_byte_cursor_from_string(s_good_secret_access_key), + .session_token_cursor = aws_byte_cursor_from_string(s_good_session_token), + .account_id_cursor = aws_byte_cursor_from_string(s_good_account_id), + .expiration_timepoint_seconds = s_good_expiration, + }; + struct aws_credentials *expected_credentials = aws_credentials_new_with_options(allocator, &creds_option); + ASSERT_SUCCESS(s_test_command_expect_success(allocator, s_test_command_with_account_id, expected_credentials)); + aws_credentials_release(expected_credentials); + return AWS_OP_SUCCESS; +} +AWS_TEST_CASE( + credentials_provider_process_basic_success_with_account_id, + s_credentials_provider_process_basic_success_with_account_id); + /* Test that stderr is ignored, if the process otherwise succeeds with exit code 0 and valid JSON to stdout. * Once upon a time stderr and stdout were merged, and mundane logging to stderr would break things. */ static int s_credentials_provider_process_success_ignores_stderr(struct aws_allocator *allocator, void *ctx) { (void)ctx; - return s_test_command_expect_success(allocator, s_test_command_with_logging_on_stderr); + struct aws_credentials *expected_credentials = aws_credentials_new_from_string( + allocator, s_good_access_key_id, s_good_secret_access_key, s_good_session_token, s_good_expiration); + ASSERT_SUCCESS( + s_test_command_expect_success(allocator, s_test_command_with_logging_on_stderr, expected_credentials)); + aws_credentials_release(expected_credentials); + return AWS_OP_SUCCESS; } AWS_TEST_CASE( credentials_provider_process_success_ignores_stderr, @@ -449,7 +529,10 @@ static int s_credentials_provider_process_basic_success_from_profile_provider( s_aws_wait_for_credentials_result(); ASSERT_TRUE(s_tester.has_received_credentials_callback == true); - ASSERT_SUCCESS(s_verify_credentials(s_tester.credentials)); + struct aws_credentials *expected_credentials = aws_credentials_new_from_string( + allocator, s_good_access_key_id, s_good_secret_access_key, s_good_session_token, s_good_expiration); + ASSERT_SUCCESS(s_verify_credentials(s_tester.credentials, expected_credentials)); + aws_credentials_release(expected_credentials); aws_credentials_provider_release(provider); s_aws_wait_for_provider_shutdown_callback(); @@ -519,7 +602,10 @@ static int s_credentials_provider_process_basic_success_cached(struct aws_alloca s_aws_wait_for_credentials_result(); ASSERT_TRUE(s_tester.has_received_credentials_callback == true); - ASSERT_SUCCESS(s_verify_credentials(s_tester.credentials)); + struct aws_credentials *expected_credentials = aws_credentials_new_from_string( + allocator, s_good_access_key_id, s_good_secret_access_key, s_good_session_token, s_good_expiration); + ASSERT_SUCCESS(s_verify_credentials(s_tester.credentials, expected_credentials)); + aws_credentials_release(expected_credentials); aws_string_destroy(config_file_path); aws_profile_collection_release(profile_collection); diff --git a/tests/credentials_provider_sso_tests.c b/tests/credentials_provider_sso_tests.c index d4483f1d..ca02e02c 100644 --- a/tests/credentials_provider_sso_tests.c +++ b/tests/credentials_provider_sso_tests.c @@ -258,6 +258,7 @@ AWS_STATIC_STRING_FROM_LITERAL( AWS_STATIC_STRING_FROM_LITERAL(s_good_access_key_id, "SuccessfulAccessKey"); AWS_STATIC_STRING_FROM_LITERAL(s_good_secret_access_key, "SuccessfulSecret"); AWS_STATIC_STRING_FROM_LITERAL(s_good_session_token, "SuccessfulToken"); +AWS_STATIC_STRING_FROM_LITERAL(s_good_account_id, "123"); static int s_good_response_expiration = 1678574216; static int s_verify_credentials(bool request_made, bool got_credentials, int expected_attempts) { ASSERT_TRUE(credentials_provider_http_mock_tester.has_received_credentials_callback); @@ -271,6 +272,8 @@ static int s_verify_credentials(bool request_made, bool got_credentials, int exp s_good_secret_access_key); ASSERT_CURSOR_VALUE_STRING_EQUALS( aws_credentials_get_session_token(credentials_provider_http_mock_tester.credentials), s_good_session_token); + ASSERT_CURSOR_VALUE_STRING_EQUALS( + aws_credentials_get_account_id(credentials_provider_http_mock_tester.credentials), s_good_account_id); ASSERT_INT_EQUALS( aws_credentials_get_expiration_timepoint_seconds(credentials_provider_http_mock_tester.credentials), s_good_response_expiration); diff --git a/tests/credentials_provider_sts_tests.c b/tests/credentials_provider_sts_tests.c index 3ab73258..4cb618d8 100644 --- a/tests/credentials_provider_sts_tests.c +++ b/tests/credentials_provider_sts_tests.c @@ -426,9 +426,10 @@ static struct aws_byte_cursor s_success_creds_doc = " secretKeyResp\n" " sessionTokenResp\n" " \n" - " \n" - " ... a bunch of other stuff we don't care about\n" - " \n" + " \n" + " assumeRoleIdResp\n" + " arn:aws:sts::123456789012:assumed-role\n" + " \n" " ... more stuff we don't care about\n" " \n" ""); @@ -448,12 +449,14 @@ static struct aws_byte_cursor s_expected_payload_with_external_id = AWS_STATIC_STRING_FROM_LITERAL(s_access_key_id_response, "accessKeyIdResp"); AWS_STATIC_STRING_FROM_LITERAL(s_secret_access_key_response, "secretKeyResp"); AWS_STATIC_STRING_FROM_LITERAL(s_session_token_response, "sessionTokenResp"); +AWS_STATIC_STRING_FROM_LITERAL(s_account_id_response, "123456789012"); static int s_verify_credentials(struct aws_credentials *credentials) { ASSERT_NOT_NULL(credentials); ASSERT_CURSOR_VALUE_STRING_EQUALS(aws_credentials_get_access_key_id(credentials), s_access_key_id_response); ASSERT_CURSOR_VALUE_STRING_EQUALS(aws_credentials_get_secret_access_key(credentials), s_secret_access_key_response); ASSERT_CURSOR_VALUE_STRING_EQUALS(aws_credentials_get_session_token(credentials), s_session_token_response); + ASSERT_CURSOR_VALUE_STRING_EQUALS(aws_credentials_get_account_id(credentials), s_account_id_response); return AWS_OP_SUCCESS; } diff --git a/tests/credentials_provider_sts_web_identity_tests.c b/tests/credentials_provider_sts_web_identity_tests.c index 80b18580..066d2615 100644 --- a/tests/credentials_provider_sts_web_identity_tests.c +++ b/tests/credentials_provider_sts_web_identity_tests.c @@ -682,7 +682,7 @@ AWS_STATIC_STRING_FROM_LITERAL( "" " " " " - " arn:aws:sts::123456789012:assumed-role/FederatedWebIdentityRole/app1" + " arn:aws:sts::123456789012:assumed-role/FederatedWebIdentityRole/app1" " AROACLKWSDQRAOEXAMPLE:app1" " " " " @@ -701,6 +701,7 @@ AWS_STATIC_STRING_FROM_LITERAL(s_good_access_key_id, "SuccessfulAccessKey"); AWS_STATIC_STRING_FROM_LITERAL(s_good_secret_access_key, "SuccessfulSecret"); AWS_STATIC_STRING_FROM_LITERAL(s_good_session_token, "TokenSuccess"); AWS_STATIC_STRING_FROM_LITERAL(s_good_response_expiration, "2020-02-25T06:03:31Z"); +AWS_STATIC_STRING_FROM_LITERAL(s_good_account_id_response, "123456789012"); static int s_verify_credentials(bool request_made, bool from_config, bool got_credentials, int expected_attempts) { @@ -724,6 +725,8 @@ static int s_verify_credentials(bool request_made, bool from_config, bool got_cr aws_credentials_get_secret_access_key(s_tester.credentials), s_good_secret_access_key); ASSERT_CURSOR_VALUE_STRING_EQUALS( aws_credentials_get_session_token(s_tester.credentials), s_good_session_token); + ASSERT_CURSOR_VALUE_STRING_EQUALS( + aws_credentials_get_account_id(s_tester.credentials), s_good_account_id_response); } else { ASSERT_TRUE(s_tester.credentials == NULL); } diff --git a/tests/credentials_tests.c b/tests/credentials_tests.c index fe2a6548..635c8bd4 100644 --- a/tests/credentials_tests.c +++ b/tests/credentials_tests.c @@ -30,6 +30,8 @@ AWS_STATIC_STRING_FROM_LITERAL(s_secret_access_key_test_value, "SekritKey"); AWS_STATIC_STRING_FROM_LITERAL(s_session_token_test_value, "Some Session Token"); AWS_STATIC_STRING_FROM_LITERAL(s_account_id_test_value, "Some Account Value"); +AWS_STATIC_STRING_FROM_LITERAL(s_account_id_env_var, "AWS_ACCOUNT_ID"); + static int s_credentials_create_destroy_test(struct aws_allocator *allocator, void *ctx) { (void)ctx; @@ -257,6 +259,17 @@ static int s_environment_credentials_provider_basic_test(struct aws_allocator *a s_session_token_test_value, NULL) == AWS_OP_SUCCESS); + aws_set_environment_value(s_account_id_env_var, s_account_id_test_value); + + ASSERT_TRUE( + s_do_basic_provider_test( + provider, + 1, + s_access_key_id_test_value, + s_secret_access_key_test_value, + s_session_token_test_value, + s_account_id_test_value) == AWS_OP_SUCCESS); + aws_credentials_provider_release(provider); s_aws_wait_for_provider_shutdown_callback(); @@ -901,6 +914,11 @@ AWS_STATIC_STRING_FROM_LITERAL( AWS_STATIC_STRING_FROM_LITERAL( s_config_contents2, "[profile default]\naws_access_key_id=fake_access_key2\naws_secret_access_key=fake_secret_key2\n"); +AWS_STATIC_STRING_FROM_LITERAL( + s_account_id_config_contents, + "[profile " + "default]\naws_access_key_id=fake_access_key\naws_secret_access_key=fake_secret_key\naws_account_id=fake_account_" + "id"); AWS_STATIC_STRING_FROM_LITERAL( s_credentials_contents, @@ -911,6 +929,7 @@ AWS_STATIC_STRING_FROM_LITERAL( AWS_STATIC_STRING_FROM_LITERAL(s_fake_access, "fake_access_key"); AWS_STATIC_STRING_FROM_LITERAL(s_fake_secret, "fake_secret_key"); +AWS_STATIC_STRING_FROM_LITERAL(s_fake_account_id, "fake_account_id"); int s_verify_default_credentials_callback(struct aws_get_credentials_test_callback_result *callback_results) { ASSERT_TRUE(callback_results->count == 1); @@ -957,6 +976,53 @@ static int s_profile_credentials_provider_default_test(struct aws_allocator *all AWS_TEST_CASE(profile_credentials_provider_default_test, s_profile_credentials_provider_default_test); +int s_verify_account_id_credentials_callback(struct aws_get_credentials_test_callback_result *callback_results) { + ASSERT_TRUE(callback_results->count == 1); + ASSERT_TRUE(callback_results->credentials != NULL); + ASSERT_CURSOR_VALUE_STRING_EQUALS(aws_credentials_get_access_key_id(callback_results->credentials), s_fake_access); + ASSERT_CURSOR_VALUE_STRING_EQUALS( + aws_credentials_get_secret_access_key(callback_results->credentials), s_fake_secret); + ASSERT_CURSOR_VALUE_STRING_EQUALS(aws_credentials_get_account_id(callback_results->credentials), s_fake_account_id); + ASSERT_TRUE(aws_credentials_get_session_token(callback_results->credentials).len == 0); + + return AWS_OP_SUCCESS; +} + +static int s_profile_credentials_provider_account_id_test(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + (void)s_account_id_config_contents; + + struct aws_string *config_file_str = aws_create_process_unique_file_name(allocator); + struct aws_string *creds_file_str = aws_create_process_unique_file_name(allocator); + + struct aws_credentials_provider_profile_options options = { + .config_file_name_override = aws_byte_cursor_from_string(config_file_str), + .credentials_file_name_override = aws_byte_cursor_from_string(creds_file_str), + .shutdown_options = + { + .shutdown_callback = s_on_shutdown_complete, + .shutdown_user_data = NULL, + }, + }; + + ASSERT_SUCCESS(s_do_credentials_provider_profile_test( + allocator, + config_file_str, + s_account_id_config_contents, + creds_file_str, + s_credentials_contents, + &options, + s_verify_account_id_credentials_callback, + true)); + + aws_string_destroy(config_file_str); + aws_string_destroy(creds_file_str); + + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(profile_credentials_provider_account_id_test, s_profile_credentials_provider_account_id_test); + static int s_profile_credentials_provider_cached_test(struct aws_allocator *allocator, void *ctx) { (void)ctx; diff --git a/tests/credentials_utils_tests.c b/tests/credentials_utils_tests.c index 2ef5c79e..663abde7 100644 --- a/tests/credentials_utils_tests.c +++ b/tests/credentials_utils_tests.c @@ -52,7 +52,22 @@ static int s_credentials_utils_construct_endpoint_test(struct aws_allocator *all aws_string_destroy(service_name); - return 0; + return AWS_OP_SUCCESS; } AWS_TEST_CASE(credentials_utils_construct_endpoint_test, s_credentials_utils_construct_endpoint_test); + +static int s_credentials_utils_parse_account_id_from_arn(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + (void)allocator; + + ASSERT_CURSOR_VALUE_CSTRING_EQUALS( + aws_parse_account_id_from_arn(aws_byte_cursor_from_c_str("::::123456789012::")), "123456789012"); + ASSERT_CURSOR_VALUE_CSTRING_EQUALS( + aws_parse_account_id_from_arn(aws_byte_cursor_from_c_str("arn:a:b:c:123456789012::")), "123456789012"); + ASSERT_CURSOR_VALUE_CSTRING_EQUALS(aws_parse_account_id_from_arn(aws_byte_cursor_from_c_str("::::::")), ""); + ASSERT_CURSOR_VALUE_CSTRING_EQUALS(aws_parse_account_id_from_arn(aws_byte_cursor_from_c_str("invalid-arn")), ""); + return AWS_OP_SUCCESS; +} + +AWS_TEST_CASE(credentials_utils_parse_account_id_from_arn, s_credentials_utils_parse_account_id_from_arn);