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);