Skip to content

Commit 042d616

Browse files
author
Bret Ambrose
committed
Initial implementation of dynamic login flow for cognito
1 parent 01dd06a commit 042d616

File tree

2 files changed

+129
-28
lines changed

2 files changed

+129
-28
lines changed

include/aws/auth/credentials.h

+24-2
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,17 @@ struct aws_cognito_identity_provider_token_pair {
668668
struct aws_byte_cursor identity_provider_token;
669669
};
670670

671+
typedef void(aws_credentials_provider_cognito_get_token_pairs_completion_fn)(
672+
struct aws_cognito_identity_provider_token_pair *logins,
673+
size_t login_count,
674+
int error_code,
675+
void *completion_user_data);
676+
677+
typedef int(aws_credentials_provider_cognito_get_token_pairs_async_fn)(
678+
void *get_token_pairs_user_data,
679+
aws_credentials_provider_cognito_get_token_pairs_completion_fn *completion_callback,
680+
void *completion_user_data);
681+
671682
/**
672683
* Configuration options needed to create a Cognito-based Credentials Provider
673684
*/
@@ -695,12 +706,12 @@ struct aws_credentials_provider_cognito_options {
695706
*/
696707
struct aws_byte_cursor *custom_role_arn;
697708

698-
/*
709+
/**
699710
* Connection bootstrap to use for network connections made while sourcing credentials
700711
*/
701712
struct aws_client_bootstrap *bootstrap;
702713

703-
/*
714+
/**
704715
* Client TLS context to use when querying cognito credentials.
705716
* Required.
706717
*/
@@ -713,6 +724,17 @@ struct aws_credentials_provider_cognito_options {
713724

714725
/* For mocking the http layer in tests, leave NULL otherwise */
715726
struct aws_auth_http_system_vtable *function_table;
727+
728+
/**
729+
* Optional async function to allow for dynamic augmentation of the token pair set on a per-request basis.
730+
*/
731+
aws_credentials_provider_cognito_get_token_pairs_async_fn *get_token_pairs;
732+
733+
/**
734+
* User data that should be passed in to the get_token_pairs function as the first parameter. In practice, this
735+
* will be a reference to a CRT binding object.
736+
*/
737+
void *get_token_pairs_user_data;
716738
};
717739

718740
/**

source/credentials_provider_cognito.c

+105-26
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,12 @@ struct aws_credentials_provider_cognito_impl {
6464

6565
struct aws_string *identity;
6666

67-
struct aws_array_list logins;
67+
struct aws_array_list static_logins;
6868

6969
struct aws_string *custom_role_arn;
70+
71+
aws_credentials_provider_cognito_get_token_pairs_async_fn *get_token_pairs;
72+
void *get_token_pairs_user_data;
7073
};
7174

7275
struct cognito_user_data {
@@ -77,6 +80,8 @@ struct cognito_user_data {
7780
aws_on_get_credentials_callback_fn *original_callback;
7881
void *original_user_data;
7982

83+
struct aws_array_list dynamic_logins;
84+
8085
struct aws_http_connection *connection;
8186
struct aws_http_message *get_credentials_request;
8287
struct aws_byte_buf request_body_buffer;
@@ -115,6 +120,15 @@ static void s_user_data_destroy(struct cognito_user_data *user_data) {
115120
aws_credentials_provider_release(user_data->provider);
116121
aws_credentials_release(user_data->credentials);
117122

123+
size_t dynamic_logins_count = aws_array_list_length(&user_data->dynamic_logins);
124+
for (size_t i = 0; i < dynamic_logins_count; ++i) {
125+
struct aws_cognito_login *login = NULL;
126+
aws_array_list_get_at(&user_data->dynamic_logins, &login, i);
127+
128+
s_aws_cognito_login_clean_up(login);
129+
}
130+
aws_array_list_clean_up(&user_data->dynamic_logins);
131+
118132
aws_mem_release(user_data->allocator, user_data);
119133
}
120134

@@ -133,6 +147,8 @@ static struct cognito_user_data *s_user_data_new(
133147
cognito_user_data->original_callback = callback;
134148
cognito_user_data->original_user_data = user_data;
135149

150+
aws_array_list_init_dynamic(&cognito_user_data->dynamic_logins, allocator, 0, sizeof(struct aws_cognito_login));
151+
136152
return cognito_user_data;
137153
}
138154

@@ -291,6 +307,31 @@ static int s_on_incoming_body_fn(struct aws_http_stream *stream, const struct aw
291307
return aws_byte_buf_append_dynamic(&provider_user_data->response_body, data);
292308
}
293309

310+
static int s_add_login_tokens_to_json(
311+
struct aws_json_value *json_value,
312+
struct aws_array_list *logins,
313+
struct aws_allocator *allocator) {
314+
size_t login_count = aws_array_list_length(logins);
315+
for (size_t i = 0; i < login_count; ++i) {
316+
struct aws_cognito_login login;
317+
if (aws_array_list_get_at(logins, &login, i)) {
318+
return AWS_OP_ERR;
319+
}
320+
321+
struct aws_json_value *login_value_string = aws_json_value_new_string(allocator, login.identity_provider_token);
322+
if (login_value_string == NULL) {
323+
return AWS_OP_ERR;
324+
}
325+
326+
if (aws_json_value_add_to_object(json_value, login.identity_provider_name, login_value_string)) {
327+
aws_json_value_destroy(login_value_string);
328+
return AWS_OP_ERR;
329+
}
330+
}
331+
332+
return AWS_OP_SUCCESS;
333+
}
334+
294335
AWS_STATIC_STRING_FROM_LITERAL(s_identity_id_key, "IdentityId");
295336
AWS_STATIC_STRING_FROM_LITERAL(s_custom_role_arn_key, "CustomRoleArn");
296337
AWS_STATIC_STRING_FROM_LITERAL(s_logins_key, "Logins");
@@ -333,8 +374,9 @@ int s_create_get_credentials_for_identity_body_buffer(
333374
}
334375
}
335376

336-
size_t login_count = aws_array_list_length(&impl->logins);
337-
if (login_count > 0) {
377+
size_t static_login_count = aws_array_list_length(&impl->static_logins);
378+
size_t dynamic_login_count = aws_array_list_length(&provider_user_data->dynamic_logins);
379+
if (static_login_count + dynamic_login_count > 0) {
338380
struct aws_json_value *logins = aws_json_value_new_object(allocator);
339381
if (logins == NULL) {
340382
goto done;
@@ -345,22 +387,12 @@ int s_create_get_credentials_for_identity_body_buffer(
345387
goto done;
346388
}
347389

348-
for (size_t i = 0; i < login_count; ++i) {
349-
struct aws_cognito_login login;
350-
if (aws_array_list_get_at(&impl->logins, &login, i)) {
351-
goto done;
352-
}
353-
354-
struct aws_json_value *login_value_string =
355-
aws_json_value_new_string(allocator, login.identity_provider_token);
356-
if (login_value_string == NULL) {
357-
goto done;
358-
}
359-
360-
if (aws_json_value_add_to_object(logins, login.identity_provider_name, login_value_string)) {
361-
aws_json_value_destroy(login_value_string);
362-
goto done;
363-
}
390+
if (s_add_login_tokens_to_json(logins, &impl->static_logins, allocator)) {
391+
goto done;
392+
}
393+
394+
if (s_add_login_tokens_to_json(logins, &provider_user_data->dynamic_logins, allocator)) {
395+
goto done;
364396
}
365397
}
366398

@@ -534,6 +566,46 @@ static void s_on_connection_setup_fn(struct aws_http_connection *connection, int
534566
s_finalize_credentials_query(wrapped_user_data, error_code);
535567
}
536568

569+
static void s_on_get_token_pairs_completion(
570+
struct aws_cognito_identity_provider_token_pair *logins,
571+
size_t login_count,
572+
int error_code,
573+
void *completion_user_data) {
574+
575+
(void)logins;
576+
(void)login_count;
577+
578+
struct cognito_user_data *wrapped_user_data = completion_user_data;
579+
struct aws_credentials_provider_cognito_impl *impl = wrapped_user_data->provider->impl;
580+
581+
if (error_code == AWS_ERROR_SUCCESS) {
582+
for (size_t i = 0; i < login_count; i++) {
583+
struct aws_cognito_identity_provider_token_pair *login_pair = &logins[i];
584+
585+
struct aws_cognito_login login;
586+
AWS_ZERO_STRUCT(login);
587+
588+
s_aws_cognito_login_init(
589+
&login,
590+
wrapped_user_data->allocator,
591+
login_pair->identity_provider_name,
592+
login_pair->identity_provider_token);
593+
aws_array_list_push_back(&wrapped_user_data->dynamic_logins, &login);
594+
}
595+
596+
impl->function_table->aws_http_connection_manager_acquire_connection(
597+
impl->connection_manager, s_on_connection_setup_fn, wrapped_user_data);
598+
} else {
599+
AWS_LOGF_ERROR(
600+
AWS_LS_AUTH_CREDENTIALS_PROVIDER,
601+
"(id=%p): Cognito credentials provider failed to dynamically append token pairs on get credentials "
602+
"invocation: %s",
603+
(void *)wrapped_user_data->provider,
604+
aws_error_debug_str(error_code));
605+
s_finalize_credentials_query(wrapped_user_data, error_code);
606+
}
607+
}
608+
537609
static void s_on_retry_token_acquired(
538610
struct aws_retry_strategy *strategy,
539611
int error_code,
@@ -556,8 +628,11 @@ static void s_on_retry_token_acquired(
556628

557629
struct aws_credentials_provider_cognito_impl *impl = wrapped_user_data->provider->impl;
558630

559-
impl->function_table->aws_http_connection_manager_acquire_connection(
560-
impl->connection_manager, s_on_connection_setup_fn, wrapped_user_data);
631+
if (impl->get_token_pairs != NULL) {
632+
(*impl->get_token_pairs)(impl->get_token_pairs_user_data, s_on_get_token_pairs_completion, wrapped_user_data);
633+
} else {
634+
s_on_get_token_pairs_completion(NULL, 0, AWS_ERROR_SUCCESS, wrapped_user_data);
635+
}
561636
}
562637

563638
static int s_credentials_provider_cognito_get_credentials_async(
@@ -629,16 +704,16 @@ static void s_on_connection_manager_shutdown(void *user_data) {
629704
aws_string_destroy(impl->identity);
630705
aws_string_destroy(impl->custom_role_arn);
631706

632-
for (size_t i = 0; i < aws_array_list_length(&impl->logins); ++i) {
707+
for (size_t i = 0; i < aws_array_list_length(&impl->static_logins); ++i) {
633708
struct aws_cognito_login login;
634-
if (aws_array_list_get_at(&impl->logins, &login, i)) {
709+
if (aws_array_list_get_at(&impl->static_logins, &login, i)) {
635710
continue;
636711
}
637712

638713
s_aws_cognito_login_clean_up(&login);
639714
}
640715

641-
aws_array_list_clean_up(&impl->logins);
716+
aws_array_list_clean_up(&impl->static_logins);
642717

643718
aws_mem_release(provider->allocator, provider);
644719
}
@@ -763,7 +838,8 @@ struct aws_credentials_provider *aws_credentials_provider_new_cognito(
763838
impl->custom_role_arn = aws_string_new_from_cursor(allocator, options->custom_role_arn);
764839
}
765840

766-
aws_array_list_init_dynamic(&impl->logins, allocator, options->login_count, sizeof(struct aws_cognito_login));
841+
aws_array_list_init_dynamic(
842+
&impl->static_logins, allocator, options->login_count, sizeof(struct aws_cognito_login));
767843

768844
for (size_t i = 0; i < options->login_count; ++i) {
769845
struct aws_cognito_identity_provider_token_pair *login_token_pair = &options->logins[i];
@@ -782,7 +858,7 @@ struct aws_credentials_provider *aws_credentials_provider_new_cognito(
782858
goto on_error;
783859
}
784860

785-
aws_array_list_push_back(&impl->logins, &login);
861+
aws_array_list_push_back(&impl->static_logins, &login);
786862
}
787863

788864
struct aws_standard_retry_options retry_options = {
@@ -807,6 +883,9 @@ struct aws_credentials_provider *aws_credentials_provider_new_cognito(
807883

808884
aws_tls_connection_options_clean_up(&tls_connection_options);
809885

886+
impl->get_token_pairs = options->get_token_pairs;
887+
impl->get_token_pairs_user_data = options->get_token_pairs_user_data;
888+
810889
return provider;
811890

812891
on_error:

0 commit comments

Comments
 (0)