From d3f4879fa84b8b0bd1430df72164936e819fcbce Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Tue, 5 Jan 2021 16:22:19 -0600 Subject: [PATCH 01/13] add code for kerberos strategy with user token as input(straight) & modify CMakeList.txt to compile with 4221 warning --- CMakeLists.txt | 1 + include/aws/http/proxy_strategy.h | 30 +++ source/proxy_strategy.c | 303 ++++++++++++++++++++++++++++-- 3 files changed, 317 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 532647575..1417c1d94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,7 @@ aws_add_sanitizers(${PROJECT_NAME} BLACKLIST "sanitizer-blacklist.txt") # We are not ABI stable yet set_target_properties(${PROJECT_NAME} PROPERTIES VERSION 1.0.0) +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "/wd4221") target_include_directories(${PROJECT_NAME} PUBLIC $ diff --git a/include/aws/http/proxy_strategy.h b/include/aws/http/proxy_strategy.h index fc9f161ce..fd119f90b 100644 --- a/include/aws/http/proxy_strategy.h +++ b/include/aws/http/proxy_strategy.h @@ -150,6 +150,17 @@ struct aws_http_proxy_strategy_factory { enum aws_http_proxy_connection_type proxy_connection_type; }; + +struct aws_http_proxy_strategy_factory_kerberos_auth_config { + + /* type of proxy connection being established, must be forwarding or tunnel */ + enum aws_http_proxy_connection_type proxy_connection_type; + + /* user token to use in kerberos authentication */ + struct aws_byte_cursor user_token; + +}; + struct aws_http_proxy_strategy_factory_basic_auth_config { /* type of proxy connection being established, must be forwarding or tunnel */ @@ -189,6 +200,8 @@ struct aws_http_proxy_strategy_factory_tunneling_kerberos_options { struct aws_http_proxy_strategy_factory_tunneling_adaptive_kerberos_options { struct aws_http_proxy_strategy_factory_tunneling_kerberos_options kerberos_options; + + }; AWS_EXTERN_C_BEGIN @@ -234,6 +247,23 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_acquire( AWS_HTTP_API void aws_http_proxy_strategy_factory_release(struct aws_http_proxy_strategy_factory *proxy_strategy_factory); + + +/** + * A constructor for a proxy strategy factory that performs kerberos authentication by adding the appropriate + * header and header value to requests or CONNECT requests. + * + * @param allocator memory allocator to use + * @param config kerberos authentication configuration info + * @return a new proxy strategy factory if successfully constructed, otherwise NULL + */ +AWS_HTTP_API +struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_kerberos_auth( + struct aws_allocator *allocator, + struct aws_http_proxy_strategy_factory_kerberos_auth_config *config); + + + /** * A constructor for a proxy strategy factory that performs basic authentication by adding the appropriate * header and header value to requests or CONNECT requests. diff --git a/source/proxy_strategy.c b/source/proxy_strategy.c index 7e0a16a05..6736cd3b7 100644 --- a/source/proxy_strategy.c +++ b/source/proxy_strategy.c @@ -8,11 +8,6 @@ #include #include -#if defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable : 4221) -#endif /* _MSC_VER */ - struct aws_http_proxy_strategy *aws_http_proxy_strategy_acquire(struct aws_http_proxy_strategy *proxy_strategy) { if (proxy_strategy != NULL) { aws_ref_count_acquire(&proxy_strategy->ref_count); @@ -53,7 +48,7 @@ void aws_http_proxy_strategy_factory_release(struct aws_http_proxy_strategy_fact } } -/******************************************************************************************************************/ +/*****************************************************************************************************************/ enum proxy_strategy_connect_state { AWS_PSCS_READY, @@ -62,12 +57,12 @@ enum proxy_strategy_connect_state { AWS_PSCS_FAILURE, }; +/* Functions for factory basic auth strategy with Basic Header */ + struct aws_http_proxy_strategy_factory_basic_auth { struct aws_allocator *allocator; - struct aws_string *user_name; struct aws_string *password; - struct aws_http_proxy_strategy_factory factory_base; }; @@ -323,6 +318,282 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_basi /******************************************************************************************************************/ +/* Functions for factory kerberos strategy with Negotiate Header */ + +struct aws_http_proxy_strategy_factory_kerberos_auth { + struct aws_allocator *allocator; + struct aws_string *user_token; + struct aws_http_proxy_strategy_factory factory_base; +}; + +static void s_destroy_kerberos_auth_factory(struct aws_http_proxy_strategy_factory *proxy_strategy_factory) { + struct aws_http_proxy_strategy_factory_kerberos_auth *kerberos_auth_factory = proxy_strategy_factory->impl; + + aws_string_destroy(kerberos_auth_factory->user_token); + + aws_mem_release(kerberos_auth_factory->allocator, kerberos_auth_factory); +} + +struct aws_http_proxy_strategy_kerberos_auth { + struct aws_allocator *allocator; + + struct aws_http_proxy_strategy_factory *factory; + + enum proxy_strategy_connect_state connect_state; + + struct aws_http_proxy_strategy strategy_base; +}; + +static void s_destroy_kerberos_auth_strategy(struct aws_http_proxy_strategy *proxy_strategy) { + struct aws_http_proxy_strategy_kerberos_auth *kerberos_auth_strategy = proxy_strategy->impl; + + aws_http_proxy_strategy_factory_release(kerberos_auth_strategy->factory); + + aws_mem_release(kerberos_auth_strategy->allocator, kerberos_auth_strategy); +} + +AWS_STATIC_STRING_FROM_LITERAL(s_proxy_authorization_header_kerberos_prefix, "Negotiate "); + +/* + * Adds a proxy authentication header based on the kerberos authentication mode + */ +static int s_add_kerberos_proxy_authentication_header( + struct aws_allocator *allocator, + struct aws_http_message *request, + struct aws_http_proxy_strategy_kerberos_auth *kerberos_auth_strategy) { + + struct aws_byte_buf base64_input_value; + AWS_ZERO_STRUCT(base64_input_value); + + struct aws_byte_buf header_value; + AWS_ZERO_STRUCT(header_value); + + int result = AWS_OP_ERR; + + struct aws_http_proxy_strategy_factory_kerberos_auth *factory = kerberos_auth_strategy->factory->impl; + + if (aws_byte_buf_init(&base64_input_value, allocator, factory->user_token->len + 1)) { + goto done; + } + + /* First build a buffer with "username:password" in it */ + struct aws_byte_cursor usertoken_cursor = aws_byte_cursor_from_string(factory->user_token); + if (aws_byte_buf_append(&base64_input_value, &usertoken_cursor)) { + goto done; + } + + struct aws_byte_cursor base64_source_cursor = + aws_byte_cursor_from_array(base64_input_value.buffer, base64_input_value.len); + + /* Figure out how much room we need in our final header value buffer */ + size_t required_size = 0; + if (aws_base64_compute_encoded_len(base64_source_cursor.len, &required_size)) { + goto done; + } + + required_size += s_proxy_authorization_header_kerberos_prefix->len + 1; + if (aws_byte_buf_init(&header_value, allocator, required_size)) { + goto done; + } + + /* Build the final header value by appending the authorization type and the base64 encoding string together */ + struct aws_byte_cursor kerberos_prefix = aws_byte_cursor_from_string(s_proxy_authorization_header_kerberos_prefix); + if (aws_byte_buf_append_dynamic(&header_value, &kerberos_prefix)) { + goto done; + } + + uint8_t length = (uint8_t) s_proxy_authorization_header_kerberos_prefix->len; + + /* copy the length of token into header value buffer starting with an offset*/ + for (uint16_t i = 0; i impl; + + return s_add_kerberos_proxy_authentication_header(kerberos_auth_strategy->allocator, message, kerberos_auth_strategy); +} + +void s_kerberos_auth_tunnel_add_header( + struct aws_http_proxy_strategy *proxy_strategy, + struct aws_http_message *message, + aws_http_proxy_strategy_terminate_fn *strategy_termination_callback, + aws_http_proxy_strategy_http_request_forward_fn *strategy_http_request_forward_callback, + void *internal_proxy_user_data) { + + struct aws_http_proxy_strategy_kerberos_auth *kerberos_auth_strategy = proxy_strategy->impl; + if (kerberos_auth_strategy->connect_state != AWS_PSCS_READY) { + strategy_termination_callback(message, AWS_ERROR_INVALID_STATE, internal_proxy_user_data); + return; + } + + kerberos_auth_strategy->connect_state = AWS_PSCS_IN_PROGRESS; + + if (s_add_kerberos_proxy_authentication_header(kerberos_auth_strategy->allocator, message, kerberos_auth_strategy)) { + strategy_termination_callback(message, aws_last_error(), internal_proxy_user_data); + return; + } + + strategy_http_request_forward_callback(message, internal_proxy_user_data); +} + +static int s_kerberos_on_incoming_header( + struct aws_http_proxy_strategy *proxy_strategy, + enum aws_http_header_block header_block, + const struct aws_http_header *header_array, + size_t num_headers) { + + struct aws_http_proxy_strategy_tunneling_chain *kerberos_strategy = proxy_strategy->impl; + (void)kerberos_strategy; + (void)header_block; + (void)header_array; + (void)num_headers; + + /* SA-TBI: process CONNECT response headers here if needed */ + + return AWS_OP_SUCCESS; +} + +static int s_kerberos_auth_on_connect_status( + struct aws_http_proxy_strategy *proxy_strategy, + enum aws_http_status_code status_code) { + struct aws_http_proxy_strategy_kerberos_auth *kerberos_auth_strategy = proxy_strategy->impl; + + if (kerberos_auth_strategy->connect_state == AWS_PSCS_IN_PROGRESS) { + if (AWS_HTTP_STATUS_CODE_200_OK != status_code) { + kerberos_auth_strategy->connect_state = AWS_PSCS_FAILURE; + } else { + kerberos_auth_strategy->connect_state = AWS_PSCS_SUCCESS; + } + } + + return AWS_OP_SUCCESS; +} + +static struct aws_http_proxy_strategy_forwarding_vtable s_kerberos_auth_proxy_forwarding_vtable = { + .forward_request_transform = s_kerberos_auth_forward_add_header, +}; + +static struct aws_http_proxy_strategy_tunnelling_vtable s_kerberos_auth_proxy_tunneling_vtable = { + .on_status_callback = s_kerberos_auth_on_connect_status, + .connect_request_transform = s_kerberos_auth_tunnel_add_header, + .on_incoming_headers_callback = s_kerberos_on_incoming_header, +}; + + +static struct aws_http_proxy_strategy *s_create_kerberos_auth_strategy( + struct aws_http_proxy_strategy_factory *proxy_strategy_factory, + struct aws_allocator *allocator) { + if (proxy_strategy_factory == NULL || allocator == NULL) { + aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); + return NULL; + } + + struct aws_http_proxy_strategy_kerberos_auth *kerberos_auth_strategy = + aws_mem_calloc(allocator, 1, sizeof(struct aws_http_proxy_strategy_kerberos_auth)); + if (kerberos_auth_strategy == NULL) { + return NULL; + } + + kerberos_auth_strategy->allocator = allocator; + kerberos_auth_strategy->connect_state = AWS_PSCS_READY; + kerberos_auth_strategy->strategy_base.impl = kerberos_auth_strategy; + aws_ref_count_init( + &kerberos_auth_strategy->strategy_base.ref_count, + &kerberos_auth_strategy->strategy_base, + (aws_simple_completion_callback *)s_destroy_kerberos_auth_strategy); + + if (proxy_strategy_factory->proxy_connection_type == AWS_HPCT_HTTP_FORWARD) { + kerberos_auth_strategy->strategy_base.strategy_vtable.forwarding_vtable = &s_kerberos_auth_proxy_forwarding_vtable; + } else { + kerberos_auth_strategy->strategy_base.strategy_vtable.tunnelling_vtable = &s_kerberos_auth_proxy_tunneling_vtable; + } + + kerberos_auth_strategy->factory = aws_ref_count_acquire(&proxy_strategy_factory->ref_count); + + return &kerberos_auth_strategy->strategy_base; +} + +static struct aws_http_proxy_strategy_factory_vtable s_kerberos_auth_factory_vtable = { + .create_strategy = s_create_kerberos_auth_strategy, +}; + +struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_kerberos_auth( + struct aws_allocator *allocator, + struct aws_http_proxy_strategy_factory_kerberos_auth_config *config) { + if (config == NULL || allocator == NULL) { + aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); + return NULL; + } + + if (config->proxy_connection_type != AWS_HPCT_HTTP_FORWARD && + config->proxy_connection_type != AWS_HPCT_HTTP_TUNNEL) { + aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); + return NULL; + } + + struct aws_http_proxy_strategy_factory_kerberos_auth *kerberos_auth_factory = + aws_mem_calloc(allocator, 1, sizeof(struct aws_http_proxy_strategy_factory_kerberos_auth)); + if (kerberos_auth_factory == NULL) { + return NULL; + } + + kerberos_auth_factory->factory_base.impl = kerberos_auth_factory; + kerberos_auth_factory->factory_base.vtable = &s_kerberos_auth_factory_vtable; + kerberos_auth_factory->allocator = allocator; + kerberos_auth_factory->factory_base.proxy_connection_type = config->proxy_connection_type; + aws_ref_count_init( + &kerberos_auth_factory->factory_base.ref_count, + &kerberos_auth_factory->factory_base, + (aws_simple_completion_callback *)s_destroy_kerberos_auth_factory); + + kerberos_auth_factory->user_token = aws_string_new_from_cursor(allocator, &config->user_token); + if (kerberos_auth_factory->user_token == NULL) { + goto on_error; + } + + return &kerberos_auth_factory->factory_base; + +on_error: + + aws_http_proxy_strategy_factory_release(&kerberos_auth_factory->factory_base); + + return NULL; +} + + +/*****************************************************************************************************************/ + struct aws_http_proxy_strategy_factory_one_time_identity { struct aws_allocator *allocator; @@ -901,13 +1172,13 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn goto on_error; } - struct aws_http_proxy_strategy_factory *factory_array[2] = { + struct aws_http_proxy_strategy_factory *factories[2] = { bad_basic_factory, good_basic_factory, }; struct aws_http_proxy_strategy_factory_tunneling_chain_options chain_config = { - .factories = factory_array, + .factories = factories, .factory_count = 2, }; @@ -966,13 +1237,15 @@ static void s_kerberos_tunnel_transform_connect( (void)strategy_http_request_forward_callback; (void)internal_proxy_user_data; - /* + + /* * SA-TBI: modify message with kerberos auth data and call the request_forward callback or if * encountering an error, invoke the strategy_termination callback. * * As written, a connection attempt using this strategy will hang because neither of these are currently * invoked. */ + } static int s_kerberos_on_incoming_headers( @@ -1129,13 +1402,13 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn goto on_error; } - struct aws_http_proxy_strategy_factory *factory_array[2] = { + struct aws_http_proxy_strategy_factory *factories[2] = { identity_factory, kerberos_factory, }; struct aws_http_proxy_strategy_factory_tunneling_chain_options chain_config = { - .factories = factory_array, + .factories = factories, .factory_count = 2, }; @@ -1154,7 +1427,3 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn return NULL; } - -#if defined(_MSC_VER) -# pragma warning(pop) -#endif /* _MSC_VER */ From c402e52ff6091c5c3f806a16b6bd37854b29c125 Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Tue, 5 Jan 2021 21:08:24 -0600 Subject: [PATCH 02/13] add function to get kerberos user token --- include/aws/http/proxy_strategy.h | 18 +++++ source/proxy_strategy.c | 121 ++++++++++++++++++++++++++++-- 2 files changed, 131 insertions(+), 8 deletions(-) diff --git a/include/aws/http/proxy_strategy.h b/include/aws/http/proxy_strategy.h index fd119f90b..2ae9c032f 100644 --- a/include/aws/http/proxy_strategy.h +++ b/include/aws/http/proxy_strategy.h @@ -18,6 +18,24 @@ struct aws_http_header; struct aws_http_proxy_strategy; struct aws_http_proxy_strategy_factory; +/* function defined in crt to get kerberos usertoken*/ +#ifdef __cplusplus +extern "C" char* get_kerberos_usertoken(); +#endif + +#ifdef __cplusplus +extern "C" void send_kerberos_header( + size_t length, + uint8_t *httpHeader, + size_t length1, + uint8_t *httpHeader1, + size_t num_headers); +#endif + +#ifdef __cplusplus +extern "C" void send_kerberos_https_status(int httpStatusCode); +#endif + /** * Proxy strategy logic must call this function to indicate an unsuccessful outcome */ diff --git a/source/proxy_strategy.c b/source/proxy_strategy.c index 6736cd3b7..6b842f325 100644 --- a/source/proxy_strategy.c +++ b/source/proxy_strategy.c @@ -8,6 +8,10 @@ #include #include +char* get_kerberos_usertoken(); +void send_kerberos_header(size_t length, uint8_t *httpHeader, size_t length1, uint8_t *httpHeader1, size_t num_headers); +void send_kerberos_https_status(int httpStatusCode); + struct aws_http_proxy_strategy *aws_http_proxy_strategy_acquire(struct aws_http_proxy_strategy *proxy_strategy) { if (proxy_strategy != NULL) { aws_ref_count_acquire(&proxy_strategy->ref_count); @@ -376,7 +380,7 @@ static int s_add_kerberos_proxy_authentication_header( goto done; } - /* First build a buffer with "username:password" in it */ + /* First build a buffer with "usertoken" in it */ struct aws_byte_cursor usertoken_cursor = aws_byte_cursor_from_string(factory->user_token); if (aws_byte_buf_append(&base64_input_value, &usertoken_cursor)) { goto done; @@ -415,10 +419,8 @@ static int s_add_kerberos_proxy_authentication_header( /* * We do not need base64 encoding as the usertoken is already base64 encoded - if (aws_base64_encode(&base64_source_cursor, &header_value)) { - goto done; - } */ + struct aws_http_header header = { .name = aws_byte_cursor_from_string(s_proxy_authorization_header_name), .value = aws_byte_cursor_from_array(header_value.buffer, header_value.len), @@ -1200,6 +1202,85 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn /******************************************************************************************************************/ +/* + * Adds a proxy authentication header based on the user kerberos authentication token + */ +static int s_add_kerberos_proxy_usertoken_authentication_header( + struct aws_allocator *allocator, + struct aws_http_message *request, + struct aws_string *user_token) { + + struct aws_byte_buf base64_input_value; + AWS_ZERO_STRUCT(base64_input_value); + + struct aws_byte_buf header_value; + AWS_ZERO_STRUCT(header_value); + + int result = AWS_OP_ERR; + + if (aws_byte_buf_init(&base64_input_value, allocator, user_token->len + 1)) { + goto done; + } + + /* First build a buffer with "usertoken" in it */ + struct aws_byte_cursor usertoken_cursor = aws_byte_cursor_from_string(user_token); + if (aws_byte_buf_append(&base64_input_value, &usertoken_cursor)) { + goto done; + } + + struct aws_byte_cursor base64_source_cursor = + aws_byte_cursor_from_array(base64_input_value.buffer, base64_input_value.len); + + /* Figure out how much room we need in our final header value buffer */ + size_t required_size = 0; + if (aws_base64_compute_encoded_len(base64_source_cursor.len, &required_size)) { + goto done; + } + + required_size += s_proxy_authorization_header_kerberos_prefix->len + 1; + if (aws_byte_buf_init(&header_value, allocator, required_size)) { + goto done; + } + + /* Build the final header value by appending the authorization type and the base64 encoding string together */ + struct aws_byte_cursor kerberos_prefix = aws_byte_cursor_from_string(s_proxy_authorization_header_kerberos_prefix); + if (aws_byte_buf_append_dynamic(&header_value, &kerberos_prefix)) { + goto done; + } + + uint8_t length = (uint8_t)s_proxy_authorization_header_kerberos_prefix->len; + + /* copy the length of token into header value buffer starting with an offset*/ + for (uint16_t i = 0; i < base64_input_value.len; i++) { + + header_value.buffer[i + length] = base64_input_value.buffer[i]; + } + + header_value.len += base64_input_value.len; + + /* + * We do not need base64 encoding as the usertoken is already base64 encoded + */ + + struct aws_http_header header = { + .name = aws_byte_cursor_from_string(s_proxy_authorization_header_name), + .value = aws_byte_cursor_from_array(header_value.buffer, header_value.len), + }; + + if (aws_http_message_add_header(request, header)) { + goto done; + } + + result = AWS_OP_SUCCESS; + +done: + + aws_byte_buf_clean_up(&header_value); + aws_byte_buf_clean_up(&base64_input_value); + + return result; +} + struct aws_http_proxy_strategy_factory_tunneling_kerberos { struct aws_allocator *allocator; @@ -1236,8 +1317,7 @@ static void s_kerberos_tunnel_transform_connect( (void)strategy_termination_callback; (void)strategy_http_request_forward_callback; (void)internal_proxy_user_data; - - + /* * SA-TBI: modify message with kerberos auth data and call the request_forward callback or if * encountering an error, invoke the strategy_termination callback. @@ -1246,9 +1326,22 @@ static void s_kerberos_tunnel_transform_connect( * invoked. */ + /* we first need to get the kerberos usertoken from user*/ + char *kerberos_usertoken = get_kerberos_usertoken(); + struct aws_byte_cursor kerberos_usertoken_tmp = aws_byte_cursor_from_c_str(kerberos_usertoken); + struct aws_string *kerberos_token = aws_string_new_from_cursor(kerberos_strategy->allocator, &kerberos_usertoken_tmp); + + /*transform the header with proxy authenticate:Negotiate and kerberos token*/ + if (s_add_kerberos_proxy_usertoken_authentication_header(kerberos_strategy->allocator, message, kerberos_token)) { + strategy_termination_callback(message, aws_last_error(), internal_proxy_user_data); + return; + } + + strategy_http_request_forward_callback(message, internal_proxy_user_data); + } -static int s_kerberos_on_incoming_headers( +static int s_kerberos_on_incoming_header_adaptive( struct aws_http_proxy_strategy *proxy_strategy, enum aws_http_header_block header_block, const struct aws_http_header *header_array, @@ -1261,6 +1354,16 @@ static int s_kerberos_on_incoming_headers( (void)num_headers; /* SA-TBI: process CONNECT response headers here if needed */ + /*transfer the header to user area for information purpose*/ + if (header_block == AWS_HTTP_HEADER_BLOCK_MAIN) { + /*TODO - Try function overloading*/ + send_kerberos_header( + header_array->name.len, + header_array->name.ptr, + header_array->value.len, + header_array->value.ptr, + num_headers); + } return AWS_OP_SUCCESS; } @@ -1275,6 +1378,8 @@ static int s_kerberos_on_connect_status( /* SA-TBI: process status code of CONNECT request here if needed */ + /*send http status code for informational purpose*/ + send_kerberos_https_status(status_code); return AWS_OP_SUCCESS; } @@ -1293,7 +1398,7 @@ static int s_kerberos_on_incoming_body( static struct aws_http_proxy_strategy_tunnelling_vtable s_tunneling_kerberos_proxy_tunneling_vtable = { .on_incoming_body_callback = s_kerberos_on_incoming_body, - .on_incoming_headers_callback = s_kerberos_on_incoming_headers, + .on_incoming_headers_callback = s_kerberos_on_incoming_header_adaptive, .on_status_callback = s_kerberos_on_connect_status, .connect_request_transform = s_kerberos_tunnel_transform_connect, }; From 303ec0f7979b087292ac0c6d602d1abab1b89838 Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Sun, 10 Jan 2021 22:59:43 -0600 Subject: [PATCH 03/13] add proxy connection type --- include/aws/http/private/proxy_impl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/aws/http/private/proxy_impl.h b/include/aws/http/private/proxy_impl.h index 058f80d32..f25f64e95 100644 --- a/include/aws/http/private/proxy_impl.h +++ b/include/aws/http/private/proxy_impl.h @@ -37,6 +37,8 @@ struct aws_http_proxy_config { struct aws_allocator *allocator; + enum aws_http_proxy_connection_type connection_type; + struct aws_byte_buf host; uint16_t port; From f9776c6a7d506d2b3e1db49898c65e7789ea30de Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Sun, 10 Jan 2021 23:00:51 -0600 Subject: [PATCH 04/13] add ntlm proxy strategy type --- include/aws/http/proxy_strategy.h | 40 ++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/include/aws/http/proxy_strategy.h b/include/aws/http/proxy_strategy.h index 2ae9c032f..562925172 100644 --- a/include/aws/http/proxy_strategy.h +++ b/include/aws/http/proxy_strategy.h @@ -23,8 +23,18 @@ struct aws_http_proxy_strategy_factory; extern "C" char* get_kerberos_usertoken(); #endif +/* function defined in crt to get ntlm credential*/ #ifdef __cplusplus -extern "C" void send_kerberos_header( +extern "C" char *get_ntlm_credential(); +#endif + +/* function defined in crt to get ntlm credential*/ +#ifdef __cplusplus +extern "C" char *get_ntlm_response(); +#endif + +#ifdef __cplusplus +extern "C" void send_ntlm_challenge_header( size_t length, uint8_t *httpHeader, size_t length1, @@ -222,6 +232,19 @@ struct aws_http_proxy_strategy_factory_tunneling_adaptive_kerberos_options { }; +/* + * SA-TBI: add any configuration needed for ntlm auth negotiation here + */ +struct aws_http_proxy_strategy_factory_tunneling_ntlm_options { + bool placeholder; + /* user credential for ntlm */ + struct aws_byte_cursor user_credential; +}; + +struct aws_http_proxy_strategy_factory_tunneling_adaptive_ntlm_options { + struct aws_http_proxy_strategy_factory_tunneling_ntlm_options ntlm_options; +}; + AWS_EXTERN_C_BEGIN /** @@ -361,6 +384,21 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn struct aws_allocator *allocator, struct aws_http_proxy_strategy_factory_tunneling_adaptive_kerberos_options *config); +/** + * This is an experimental API. + * + * Constructor for a WIP adaptive tunneling proxy strategy. This strategy attempts a vanilla CONNECT and if that + * fails it attempts a ntlm-oriented CONNECT (if applicable). + * + * @param allocator memory allocator to use + * @param config configuration options for the strategy factory + * @return a new proxy strategy factory if successfully constructed, otherwise NULL + */ +AWS_HTTP_API +struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunneling_adaptive_ntlm( + struct aws_allocator *allocator, + struct aws_http_proxy_strategy_factory_tunneling_adaptive_ntlm_options *config); + AWS_EXTERN_C_END #endif /* AWS_PROXY_STRATEGY_H */ From 70c357823abf014014d03a648939a508cf72e6b6 Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Sun, 10 Jan 2021 23:01:49 -0600 Subject: [PATCH 05/13] add proxy connection type --- source/proxy_connection.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/proxy_connection.c b/source/proxy_connection.c index 985fce649..136e91a5c 100644 --- a/source/proxy_connection.c +++ b/source/proxy_connection.c @@ -800,6 +800,8 @@ struct aws_http_proxy_config *aws_http_proxy_config_new( return NULL; } + config->connection_type = options->connection_type; + if (aws_byte_buf_init_copy_from_cursor(&config->host, allocator, options->host)) { goto on_error; } @@ -867,6 +869,7 @@ void aws_http_proxy_options_init_from_config( const struct aws_http_proxy_config *config) { AWS_FATAL_ASSERT(options && config); + options->connection_type = config->connection_type; options->host = aws_byte_cursor_from_buf(&config->host); options->port = config->port; options->tls_options = config->tls_options; From 9481f801f5a932b7e27d46b0072a97bfbfb9981f Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Sun, 10 Jan 2021 23:04:30 -0600 Subject: [PATCH 06/13] add ntlm strategy --- source/proxy_strategy.c | 549 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 501 insertions(+), 48 deletions(-) diff --git a/source/proxy_strategy.c b/source/proxy_strategy.c index 6b842f325..de8a9320b 100644 --- a/source/proxy_strategy.c +++ b/source/proxy_strategy.c @@ -8,8 +8,16 @@ #include #include +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4221) +#endif /* _MSC_VER */ + + char* get_kerberos_usertoken(); -void send_kerberos_header(size_t length, uint8_t *httpHeader, size_t length1, uint8_t *httpHeader1, size_t num_headers); +char *get_ntlm_credential(); +char *get_ntlm_response(); +void send_ntlm_challenge_header(size_t length, uint8_t *httpHeader, size_t length1, uint8_t *httpHeader1, size_t num_headers); void send_kerberos_https_status(int httpStatusCode); struct aws_http_proxy_strategy *aws_http_proxy_strategy_acquire(struct aws_http_proxy_strategy *proxy_strategy) { @@ -61,6 +69,13 @@ enum proxy_strategy_connect_state { AWS_PSCS_FAILURE, }; +enum proxy_strategy_connect_sub_state { + AWS_PSCS_SUB_STATE_READY, + AWS_PSCS_SUB_STATE_IN_PROGRESS, + AWS_PSCS_SUB_STATE_SUCCESS, + AWS_PSCS_SUB_STATE_FAILURE, +}; + /* Functions for factory basic auth strategy with Basic Header */ struct aws_http_proxy_strategy_factory_basic_auth { @@ -321,8 +336,8 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_basi } /******************************************************************************************************************/ - -/* Functions for factory kerberos strategy with Negotiate Header */ +/**/ +/*straight kerberos*/ struct aws_http_proxy_strategy_factory_kerberos_auth { struct aws_allocator *allocator; @@ -616,6 +631,34 @@ static void s_destroy_one_time_identity_strategy(struct aws_http_proxy_strategy aws_mem_release(identity_strategy->allocator, identity_strategy); } +static int s_one_time_identity_on_incoming_header_adaptive( + struct aws_http_proxy_strategy *proxy_strategy, + enum aws_http_header_block header_block, + const struct aws_http_header *header_array, + size_t num_headers) { + + struct aws_http_proxy_strategy_one_time_identity *one_time_identity_strategy = proxy_strategy->impl; + (void)one_time_identity_strategy; + (void)header_block; + (void)header_array; + (void)num_headers; + + /* SA-TBI: process CONNECT response headers here if needed */ + + return AWS_OP_SUCCESS; +} + +static int s_one_time_identity_on_incoming_body(struct aws_http_proxy_strategy *proxy_strategy, const struct aws_byte_cursor *data) { + + struct aws_http_proxy_strategy_one_time_identity *one_time_identity_strategy = proxy_strategy->impl; + (void)one_time_identity_strategy; + (void)data; + + /* SA-TBI: process body of CONNECT request here if needed */ + + return AWS_OP_SUCCESS; +} + void s_one_time_identity_connect_transform( struct aws_http_proxy_strategy *proxy_strategy, struct aws_http_message *message, @@ -650,6 +693,8 @@ static int s_one_time_identity_on_connect_status( } static struct aws_http_proxy_strategy_tunnelling_vtable s_one_time_identity_proxy_tunneling_vtable = { + .on_incoming_body_callback = s_one_time_identity_on_incoming_body, + .on_incoming_headers_callback = s_one_time_identity_on_incoming_header_adaptive, .on_status_callback = s_one_time_identity_on_connect_status, .connect_request_transform = s_one_time_identity_connect_transform, }; @@ -834,6 +879,8 @@ struct aws_http_proxy_strategy_tunneling_chain { void *original_internal_proxy_user_data; aws_http_proxy_strategy_terminate_fn *original_strategy_termination_callback; aws_http_proxy_strategy_http_request_forward_fn *original_strategy_http_request_forward_callback; + enum proxy_strategy_connect_state connect_state; + enum proxy_strategy_connect_sub_state connect_sub_state; struct aws_http_proxy_strategy strategy_base; }; @@ -1027,6 +1074,8 @@ static struct aws_http_proxy_strategy *s_create_tunneling_chain_strategy( (aws_simple_completion_callback *)s_destroy_tunneling_chain_strategy); chain_strategy->strategy_base.strategy_vtable.tunnelling_vtable = &s_tunneling_chain_proxy_tunneling_vtable; + chain_strategy->connect_state = AWS_PSCS_READY; + chain_strategy->connect_sub_state = AWS_PSCS_SUB_STATE_READY; struct aws_http_proxy_strategy_factory_tunneling_chain *chain_factory = proxy_strategy_factory->impl; size_t strategy_count = aws_array_list_length(&chain_factory->strategy_factories); @@ -1174,13 +1223,13 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn goto on_error; } - struct aws_http_proxy_strategy_factory *factories[2] = { + struct aws_http_proxy_strategy_factory *factory_array[2] = { bad_basic_factory, good_basic_factory, }; struct aws_http_proxy_strategy_factory_tunneling_chain_options chain_config = { - .factories = factories, + .factories = factory_array, .factory_count = 2, }; @@ -1201,6 +1250,29 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn } /******************************************************************************************************************/ +/*adaptive kerberos*/ +struct aws_http_proxy_strategy_factory_tunneling_kerberos { + struct aws_allocator *allocator; + + struct aws_http_proxy_strategy_factory factory_base; + + /* SA-TBI: add any factory state needed here */ +}; + +struct aws_http_proxy_strategy_tunneling_kerberos { + struct aws_allocator *allocator; + + struct aws_http_proxy_strategy strategy_base; + + enum proxy_strategy_connect_state state; + + /* + * SA-TBI: add any factory state needed here + * + * Likely things include response code (from the vanilla CONNECT) and the appropriate headers in + * the response + */ +}; /* * Adds a proxy authentication header based on the user kerberos authentication token @@ -1248,6 +1320,11 @@ static int s_add_kerberos_proxy_usertoken_authentication_header( goto done; } + + /* + * We do not need base64 encoding as the usertoken is already base64 encoded + */ + uint8_t length = (uint8_t)s_proxy_authorization_header_kerberos_prefix->len; /* copy the length of token into header value buffer starting with an offset*/ @@ -1257,10 +1334,6 @@ static int s_add_kerberos_proxy_usertoken_authentication_header( } header_value.len += base64_input_value.len; - - /* - * We do not need base64 encoding as the usertoken is already base64 encoded - */ struct aws_http_header header = { .name = aws_byte_cursor_from_string(s_proxy_authorization_header_name), @@ -1281,29 +1354,6 @@ static int s_add_kerberos_proxy_usertoken_authentication_header( return result; } -struct aws_http_proxy_strategy_factory_tunneling_kerberos { - struct aws_allocator *allocator; - - struct aws_http_proxy_strategy_factory factory_base; - - /* SA-TBI: add any factory state needed here */ -}; - -struct aws_http_proxy_strategy_tunneling_kerberos { - struct aws_allocator *allocator; - - struct aws_http_proxy_strategy strategy_base; - - enum proxy_strategy_connect_state state; - - /* - * SA-TBI: add any factory state needed here - * - * Likely things include response code (from the vanilla CONNECT) and the appropriate headers in - * the response - */ -}; - static void s_kerberos_tunnel_transform_connect( struct aws_http_proxy_strategy *proxy_strategy, struct aws_http_message *message, @@ -1326,7 +1376,12 @@ static void s_kerberos_tunnel_transform_connect( * invoked. */ - /* we first need to get the kerberos usertoken from user*/ + if (kerberos_strategy->connect_state != AWS_PSCS_READY) { + strategy_termination_callback(message, AWS_ERROR_INVALID_STATE, internal_proxy_user_data); + return; + } + + /* we first need to get the kerberos usertoken from user*/ char *kerberos_usertoken = get_kerberos_usertoken(); struct aws_byte_cursor kerberos_usertoken_tmp = aws_byte_cursor_from_c_str(kerberos_usertoken); struct aws_string *kerberos_token = aws_string_new_from_cursor(kerberos_strategy->allocator, &kerberos_usertoken_tmp); @@ -1337,6 +1392,7 @@ static void s_kerberos_tunnel_transform_connect( return; } + kerberos_strategy->connect_state = AWS_PSCS_IN_PROGRESS; strategy_http_request_forward_callback(message, internal_proxy_user_data); } @@ -1354,17 +1410,13 @@ static int s_kerberos_on_incoming_header_adaptive( (void)num_headers; /* SA-TBI: process CONNECT response headers here if needed */ - /*transfer the header to user area for information purpose*/ - if (header_block == AWS_HTTP_HEADER_BLOCK_MAIN) { - /*TODO - Try function overloading*/ - send_kerberos_header( - header_array->name.len, - header_array->name.ptr, - header_array->value.len, - header_array->value.ptr, - num_headers); - } + if (kerberos_strategy->connect_state == AWS_PSCS_IN_PROGRESS) { + + /*transfer the header to user area for information purpose*/ + + } + return AWS_OP_SUCCESS; } @@ -1378,8 +1430,17 @@ static int s_kerberos_on_connect_status( /* SA-TBI: process status code of CONNECT request here if needed */ - /*send http status code for informational purpose*/ - send_kerberos_https_status(status_code); + if (kerberos_strategy->connect_state == AWS_PSCS_IN_PROGRESS) { + if (AWS_HTTP_STATUS_CODE_200_OK != status_code) { + kerberos_strategy->connect_state = AWS_PSCS_FAILURE; + } else { + kerberos_strategy->connect_state = AWS_PSCS_SUCCESS; + } + + /*send http status code for informational purpose*/ + send_kerberos_https_status(status_code); + } + return AWS_OP_SUCCESS; } @@ -1391,8 +1452,12 @@ static int s_kerberos_on_incoming_body( (void)kerberos_strategy; (void)data; - /* SA-TBI: process body of CONNECT request here if needed */ + if (kerberos_strategy->connect_state == AWS_PSCS_IN_PROGRESS) { + /* SA-TBI: process body of CONNECT request here if needed */ + + } + return AWS_OP_SUCCESS; } @@ -1483,6 +1548,336 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn /******************************************************************************************************************/ +/*adaptive ntlm*/ + +struct aws_http_proxy_strategy_factory_tunneling_ntlm { + struct aws_allocator *allocator; + + struct aws_http_proxy_strategy_factory factory_base; + + /* SA-TBI: add any factory state needed here */ +}; + +struct aws_http_proxy_strategy_tunneling_ntlm { + struct aws_allocator *allocator; + + struct aws_http_proxy_strategy strategy_base; + + enum proxy_strategy_connect_state state; + + /* + * SA-TBI: add any factory state needed here + * + * Likely things include response code (from the vanilla CONNECT) and the appropriate headers in + * the response + */ +}; + +AWS_STATIC_STRING_FROM_LITERAL(s_proxy_authorization_header_ntlm_prefix, "NTLM "); + +/* + * Adds a proxy authentication header based on ntlm credential or response provided by user + */ +static int s_add_ntlm_proxy_usertoken_authentication_header( + struct aws_allocator *allocator, + struct aws_http_message *request, + struct aws_string *credential_response) { + + struct aws_byte_buf base64_input_value; + AWS_ZERO_STRUCT(base64_input_value); + + struct aws_byte_buf header_value; + AWS_ZERO_STRUCT(header_value); + + int result = AWS_OP_ERR; + + if (aws_byte_buf_init(&base64_input_value, allocator, credential_response->len + 1)) { + goto done; + } + + /* First build a buffer with "ntlm credential/response" in it */ + struct aws_byte_cursor credential_response_cursor = aws_byte_cursor_from_string(credential_response); + if (aws_byte_buf_append(&base64_input_value, &credential_response_cursor)) { + goto done; + } + + struct aws_byte_cursor base64_source_cursor = + aws_byte_cursor_from_array(base64_input_value.buffer, base64_input_value.len); + + /* Figure out how much room we need in our final header value buffer */ + size_t required_size = 0; + if (aws_base64_compute_encoded_len(base64_source_cursor.len, &required_size)) { + goto done; + } + + required_size += s_proxy_authorization_header_ntlm_prefix->len + 1; + if (aws_byte_buf_init(&header_value, allocator, required_size)) { + goto done; + } + + /* Build the final header value by appending the authorization type and the base64 encoding string together */ + struct aws_byte_cursor ntlm_prefix = aws_byte_cursor_from_string(s_proxy_authorization_header_ntlm_prefix); + if (aws_byte_buf_append_dynamic(&header_value, &ntlm_prefix)) { + goto done; + } + + /* + * We do not need base64 encoding as the credential or response are already base64 encoded + */ + + uint8_t length = (uint8_t)s_proxy_authorization_header_ntlm_prefix->len; + + /* copy the length of credential into header value buffer starting with an offset*/ + for (uint16_t i = 0; i < base64_input_value.len; i++) { + + header_value.buffer[i + length] = base64_input_value.buffer[i]; + } + + header_value.len += base64_input_value.len; + + struct aws_http_header header = { + .name = aws_byte_cursor_from_string(s_proxy_authorization_header_name), + .value = aws_byte_cursor_from_array(header_value.buffer, header_value.len), + }; + + if (aws_http_message_add_header(request, header)) { + goto done; + } + + result = AWS_OP_SUCCESS; + +done: + + aws_byte_buf_clean_up(&header_value); + aws_byte_buf_clean_up(&base64_input_value); + + return result; +} + +static void s_ntlm_tunnel_transform_connect( + struct aws_http_proxy_strategy *proxy_strategy, + struct aws_http_message *message, + aws_http_proxy_strategy_terminate_fn *strategy_termination_callback, + aws_http_proxy_strategy_http_request_forward_fn *strategy_http_request_forward_callback, + void *internal_proxy_user_data) { + + struct aws_http_proxy_strategy_tunneling_chain *ntlm_strategy = proxy_strategy->impl; + (void)ntlm_strategy; + (void)message; + (void)strategy_termination_callback; + (void)strategy_http_request_forward_callback; + (void)internal_proxy_user_data; + + /* + * SA-TBI: modify message with ntlm auth data and call the request_forward callback or if + * encountering an error, invoke the strategy_termination callback. + * + * As written, a connection attempt using this strategy will hang because neither of these are currently + * invoked. + */ + + /*Terminate when both states are not AWS_PSCS_READY*/ + if ((ntlm_strategy->connect_state != AWS_PSCS_READY) + &&(ntlm_strategy->connect_sub_state != AWS_PSCS_SUB_STATE_READY)) { + strategy_termination_callback(message, AWS_ERROR_INVALID_STATE, internal_proxy_user_data); + return; + } + + if (ntlm_strategy->connect_state == AWS_PSCS_READY) { + + /* we first need to get the ntlm credential from user*/ + char *ntlm_credential_user = get_ntlm_credential(); + struct aws_byte_cursor ntlm_credential_tmp = aws_byte_cursor_from_c_str(ntlm_credential_user); + struct aws_string *ntlm_credential = aws_string_new_from_cursor(ntlm_strategy->allocator, &ntlm_credential_tmp); + + /*transform the header with proxy authenticate:NTLM and NTLM credentials*/ + if (s_add_ntlm_proxy_usertoken_authentication_header(ntlm_strategy->allocator, message, ntlm_credential)) { + strategy_termination_callback(message, aws_last_error(), internal_proxy_user_data); + return; + } + } + + else if (ntlm_strategy->connect_sub_state == AWS_PSCS_SUB_STATE_READY) { + + char *ntlm_response_user = get_ntlm_response(); + struct aws_byte_cursor ntlm_response_tmp = aws_byte_cursor_from_c_str(ntlm_response_user); + struct aws_string *ntlm_response = + aws_string_new_from_cursor(ntlm_strategy->allocator, &ntlm_response_tmp); + + /*transform the header with proxy authenticate:NTLM and the response for challenge received from user*/ + if (s_add_ntlm_proxy_usertoken_authentication_header(ntlm_strategy->allocator, message, ntlm_response)) { + strategy_termination_callback(message, aws_last_error(), internal_proxy_user_data); + return; + } + + ntlm_strategy->connect_sub_state = AWS_PSCS_SUB_STATE_IN_PROGRESS; + } + + ntlm_strategy->connect_state = AWS_PSCS_IN_PROGRESS; + strategy_http_request_forward_callback(message, internal_proxy_user_data); +} + +static int s_ntlm_on_incoming_header_adaptive( + struct aws_http_proxy_strategy *proxy_strategy, + enum aws_http_header_block header_block, + const struct aws_http_header *header_array, + size_t num_headers) { + + struct aws_http_proxy_strategy_tunneling_chain *ntlm_strategy = proxy_strategy->impl; + (void)ntlm_strategy; + (void)header_block; + (void)header_array; + (void)num_headers; + + /* SA-TBI: process CONNECT response headers here if needed */ + //transfer the challenge to user area only when connect state in progress & sub state is not in progress + if ((ntlm_strategy->connect_state == AWS_PSCS_IN_PROGRESS) + &&(ntlm_strategy->connect_sub_state != AWS_PSCS_SUB_STATE_IN_PROGRESS)) + { + + if (header_block == AWS_HTTP_HEADER_BLOCK_MAIN) { + send_ntlm_challenge_header( + header_array->name.len, + header_array->name.ptr, + header_array->value.len, + header_array->value.ptr, + num_headers); + } + } + return AWS_OP_SUCCESS; +} + +static int s_ntlm_on_connect_status( + struct aws_http_proxy_strategy *proxy_strategy, + enum aws_http_status_code status_code) { + + struct aws_http_proxy_strategy_tunneling_chain *ntlm_strategy = proxy_strategy->impl; + (void)ntlm_strategy; + (void)status_code; + + if ((ntlm_strategy->connect_state == AWS_PSCS_IN_PROGRESS)&&(ntlm_strategy->connect_sub_state != AWS_PSCS_SUB_STATE_IN_PROGRESS)) { + if (AWS_HTTP_STATUS_CODE_200_OK != status_code) { + ntlm_strategy->connect_state = AWS_PSCS_FAILURE; + } else { + ntlm_strategy->connect_state = AWS_PSCS_SUCCESS; + } + } + + if ((ntlm_strategy->connect_state == AWS_PSCS_IN_PROGRESS)&&(ntlm_strategy->connect_sub_state == AWS_PSCS_SUB_STATE_IN_PROGRESS)) { + if (AWS_HTTP_STATUS_CODE_200_OK != status_code) { + ntlm_strategy->connect_state = AWS_PSCS_FAILURE; + ntlm_strategy->connect_sub_state = AWS_PSCS_SUB_STATE_FAILURE; + } else { + ntlm_strategy->connect_state = AWS_PSCS_FAILURE; + ntlm_strategy->connect_sub_state = AWS_PSCS_SUB_STATE_FAILURE; + } + } + return AWS_OP_SUCCESS; +} + +static int s_ntlm_on_incoming_body( + struct aws_http_proxy_strategy *proxy_strategy, + const struct aws_byte_cursor *data) { + + struct aws_http_proxy_strategy_tunneling_chain *ntlm_strategy = proxy_strategy->impl; + (void)ntlm_strategy; + (void)data; + + if (ntlm_strategy->connect_state == AWS_PSCS_IN_PROGRESS) { + + /* SA-TBI: process body of CONNECT request here if needed */ + } + + return AWS_OP_SUCCESS; +} + +static struct aws_http_proxy_strategy_tunnelling_vtable s_tunneling_ntlm_proxy_tunneling_vtable = { + .on_incoming_body_callback = s_ntlm_on_incoming_body, + .on_incoming_headers_callback = s_ntlm_on_incoming_header_adaptive, + .on_status_callback = s_ntlm_on_connect_status, + .connect_request_transform = s_ntlm_tunnel_transform_connect, +}; + +static void s_destroy_tunneling_ntlm_strategy(struct aws_http_proxy_strategy *proxy_strategy) { + struct aws_http_proxy_strategy_tunneling_ntlm *ntlm_strategy = proxy_strategy->impl; + + /* SA-TBI: any special ntlm strategy clean up here */ + + aws_mem_release(ntlm_strategy->allocator, ntlm_strategy); +} + +static struct aws_http_proxy_strategy *s_create_tunneling_ntlm_strategy( + struct aws_http_proxy_strategy_factory *proxy_strategy_factory, + struct aws_allocator *allocator) { + if (proxy_strategy_factory == NULL || allocator == NULL) { + aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); + return NULL; + } + + struct aws_http_proxy_strategy_tunneling_ntlm *ntlm_strategy = + aws_mem_calloc(allocator, 1, sizeof(struct aws_http_proxy_strategy_tunneling_ntlm)); + if (ntlm_strategy == NULL) { + return NULL; + } + + ntlm_strategy->allocator = allocator; + ntlm_strategy->strategy_base.impl = ntlm_strategy; + aws_ref_count_init( + &ntlm_strategy->strategy_base.ref_count, + &ntlm_strategy->strategy_base, + (aws_simple_completion_callback *)s_destroy_tunneling_ntlm_strategy); + + ntlm_strategy->strategy_base.strategy_vtable.tunnelling_vtable = &s_tunneling_ntlm_proxy_tunneling_vtable; + + /* SA-TBI: special ntlm strategy init here */ + + return &ntlm_strategy->strategy_base; +} + +static struct aws_http_proxy_strategy_factory_vtable s_tunneling_ntlm_factory_vtable = { + .create_strategy = s_create_tunneling_ntlm_strategy, +}; + +static void s_destroy_tunneling_ntlm_factory(struct aws_http_proxy_strategy_factory *proxy_strategy_factory) { + struct aws_http_proxy_strategy_factory_tunneling_ntlm *ntlm_factory = proxy_strategy_factory->impl; + + /* SA-TBI: any special factory clean up here */ + + aws_mem_release(ntlm_factory->allocator, ntlm_factory); +} + +struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunneling_ntlm( + struct aws_allocator *allocator, + struct aws_http_proxy_strategy_factory_tunneling_ntlm_options *config) { + + if (allocator == NULL || config == NULL) { + aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); + return NULL; + } + + struct aws_http_proxy_strategy_factory_tunneling_ntlm *ntlm_factory = + aws_mem_calloc(allocator, 1, sizeof(struct aws_http_proxy_strategy_factory_tunneling_ntlm)); + if (ntlm_factory == NULL) { + return NULL; + } + + ntlm_factory->factory_base.impl = ntlm_factory; + ntlm_factory->factory_base.vtable = &s_tunneling_ntlm_factory_vtable; + ntlm_factory->factory_base.proxy_connection_type = AWS_HPCT_HTTP_TUNNEL; + ntlm_factory->allocator = allocator; + + aws_ref_count_init( + &ntlm_factory->factory_base.ref_count, + &ntlm_factory->factory_base, + (aws_simple_completion_callback *)s_destroy_tunneling_ntlm_factory); + + /* SA-TBI: any other factory init here */ + + return &ntlm_factory->factory_base; +} + +/******************************************************************************************************************/ + AWS_HTTP_API struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunneling_adaptive_kerberos( struct aws_allocator *allocator, @@ -1507,13 +1902,14 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn goto on_error; } - struct aws_http_proxy_strategy_factory *factories[2] = { + struct aws_http_proxy_strategy_factory *factory_array[2] = { identity_factory, kerberos_factory, + }; struct aws_http_proxy_strategy_factory_tunneling_chain_options chain_config = { - .factories = factories, + .factories = factory_array, .factory_count = 2, }; @@ -1532,3 +1928,60 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn return NULL; } + +/******************************************************************************************************************/ + +AWS_HTTP_API +struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunneling_adaptive_ntlm( + struct aws_allocator *allocator, + struct aws_http_proxy_strategy_factory_tunneling_adaptive_ntlm_options *config) { + + if (allocator == NULL || config == NULL) { + aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); + return NULL; + } + + struct aws_http_proxy_strategy_factory *identity_factory = NULL; + struct aws_http_proxy_strategy_factory *ntlm_factory = NULL; + struct aws_http_proxy_strategy_factory *adaptive_factory = NULL; + + identity_factory = aws_http_proxy_strategy_factory_new_tunneling_one_time_identity(allocator); + if (identity_factory == NULL) { + goto on_error; + } + + ntlm_factory = aws_http_proxy_strategy_factory_new_tunneling_ntlm(allocator, &config->ntlm_options); + if (ntlm_factory == NULL) { + goto on_error; + } + + struct aws_http_proxy_strategy_factory *factory_array[2] = { + identity_factory, + ntlm_factory, + }; + + struct aws_http_proxy_strategy_factory_tunneling_chain_options chain_config = { + .factories = factory_array, + .factory_count = 2, + }; + + adaptive_factory = aws_http_proxy_strategy_factory_new_tunneling_chain(allocator, &chain_config); + if (adaptive_factory == NULL) { + goto on_error; + } + + return adaptive_factory; + +on_error: + + aws_http_proxy_strategy_factory_release(identity_factory); + aws_http_proxy_strategy_factory_release(ntlm_factory); + aws_http_proxy_strategy_factory_release(adaptive_factory); + + return NULL; +} + + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif /* _MSC_VER */ From 02c6f57b46545b0b607c190927afafdc42286738 Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Thu, 14 Jan 2021 00:30:44 -0600 Subject: [PATCH 07/13] remove the exception for wd4221 warning from CMakeList.txt file --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1417c1d94..532647575 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,6 @@ aws_add_sanitizers(${PROJECT_NAME} BLACKLIST "sanitizer-blacklist.txt") # We are not ABI stable yet set_target_properties(${PROJECT_NAME} PROPERTIES VERSION 1.0.0) -set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "/wd4221") target_include_directories(${PROJECT_NAME} PUBLIC $ From 01c647a065e0ddbea9fe35a8275c75570ee92377 Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Thu, 14 Jan 2021 00:43:16 -0600 Subject: [PATCH 08/13] add callback functions --- include/aws/http/proxy_strategy.h | 128 +++++++++++++++--------------- 1 file changed, 66 insertions(+), 62 deletions(-) diff --git a/include/aws/http/proxy_strategy.h b/include/aws/http/proxy_strategy.h index 562925172..768971056 100644 --- a/include/aws/http/proxy_strategy.h +++ b/include/aws/http/proxy_strategy.h @@ -18,33 +18,28 @@ struct aws_http_header; struct aws_http_proxy_strategy; struct aws_http_proxy_strategy_factory; -/* function defined in crt to get kerberos usertoken*/ -#ifdef __cplusplus -extern "C" char* get_kerberos_usertoken(); -#endif - -/* function defined in crt to get ntlm credential*/ -#ifdef __cplusplus -extern "C" char *get_ntlm_credential(); -#endif - -/* function defined in crt to get ntlm credential*/ -#ifdef __cplusplus -extern "C" char *get_ntlm_response(); -#endif - -#ifdef __cplusplus -extern "C" void send_ntlm_challenge_header( - size_t length, - uint8_t *httpHeader, - size_t length1, - uint8_t *httpHeader1, - size_t num_headers); -#endif +/*SA-Added Start*/ + +/*enum defination for callback state*/ +enum proxy_strategy_callback_state { + AWS_KERB_TOKEN, + AWS_NTLM_CRED, + AWS_NTLM_RESP, +}; + +/** + * User-supplied transform callback function that sends user data to user + *(example NTLM challenge) + */ +typedef void (*aws_http_proxy_send_user_data_callback_fn)(size_t data_length, uint8_t *data, void *userdata); + +/** + * User-supplied transform callback function that gets user data depending on callback state + *(example NTLM credentials/response) + */ +typedef char* (*aws_http_proxy_get_user_data_callback_fn)(int callback_state, void *userdata); -#ifdef __cplusplus -extern "C" void send_kerberos_https_status(int httpStatusCode); -#endif +/*SA-Added End*/ /** * Proxy strategy logic must call this function to indicate an unsuccessful outcome @@ -178,17 +173,6 @@ struct aws_http_proxy_strategy_factory { enum aws_http_proxy_connection_type proxy_connection_type; }; - -struct aws_http_proxy_strategy_factory_kerberos_auth_config { - - /* type of proxy connection being established, must be forwarding or tunnel */ - enum aws_http_proxy_connection_type proxy_connection_type; - - /* user token to use in kerberos authentication */ - struct aws_byte_cursor user_token; - -}; - struct aws_http_proxy_strategy_factory_basic_auth_config { /* type of proxy connection being established, must be forwarding or tunnel */ @@ -228,23 +212,27 @@ struct aws_http_proxy_strategy_factory_tunneling_kerberos_options { struct aws_http_proxy_strategy_factory_tunneling_adaptive_kerberos_options { struct aws_http_proxy_strategy_factory_tunneling_kerberos_options kerberos_options; - + }; -}; +/*SA-Added Start*/ + struct aws_http_proxy_strategy_factory_kerberos_auth_config { + + /* type of proxy connection being established, must be forwarding or tunnel */ + enum aws_http_proxy_connection_type proxy_connection_type; + + /* user token to use in kerberos authentication which is base64 encoded and provided by user*/ + struct aws_byte_cursor user_token; + }; -/* - * SA-TBI: add any configuration needed for ntlm auth negotiation here - */ struct aws_http_proxy_strategy_factory_tunneling_ntlm_options { bool placeholder; - /* user credential for ntlm */ - struct aws_byte_cursor user_credential; }; struct aws_http_proxy_strategy_factory_tunneling_adaptive_ntlm_options { struct aws_http_proxy_strategy_factory_tunneling_ntlm_options ntlm_options; }; +/*SA-Added End*/ AWS_EXTERN_C_BEGIN /** @@ -288,23 +276,6 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_acquire( AWS_HTTP_API void aws_http_proxy_strategy_factory_release(struct aws_http_proxy_strategy_factory *proxy_strategy_factory); - - -/** - * A constructor for a proxy strategy factory that performs kerberos authentication by adding the appropriate - * header and header value to requests or CONNECT requests. - * - * @param allocator memory allocator to use - * @param config kerberos authentication configuration info - * @return a new proxy strategy factory if successfully constructed, otherwise NULL - */ -AWS_HTTP_API -struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_kerberos_auth( - struct aws_allocator *allocator, - struct aws_http_proxy_strategy_factory_kerberos_auth_config *config); - - - /** * A constructor for a proxy strategy factory that performs basic authentication by adding the appropriate * header and header value to requests or CONNECT requests. @@ -384,10 +355,25 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn struct aws_allocator *allocator, struct aws_http_proxy_strategy_factory_tunneling_adaptive_kerberos_options *config); +/*SA-Added Start*/ + +/** + * A constructor for a proxy strategy factory that performs kerberos authentication by adding the appropriate + * header and header value to requests or CONNECT requests. + * + * @param allocator memory allocator to use + * @param config kerberos authentication configuration info + * @return a new proxy strategy factory if successfully constructed, otherwise NULL + */ +AWS_HTTP_API +struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_kerberos_auth( + struct aws_allocator *allocator, + struct aws_http_proxy_strategy_factory_kerberos_auth_config *config); + /** * This is an experimental API. * - * Constructor for a WIP adaptive tunneling proxy strategy. This strategy attempts a vanilla CONNECT and if that + * Constructor for a WIP adaptive tunneling NTLM proxy strategy. This strategy attempts a vanilla CONNECT and if that * fails it attempts a ntlm-oriented CONNECT (if applicable). * * @param allocator memory allocator to use @@ -399,6 +385,24 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn struct aws_allocator *allocator, struct aws_http_proxy_strategy_factory_tunneling_adaptive_ntlm_options *config); +/** + * This is an experimental API. + * + * Constructor for callback functions + * + * @param callback function for sending user data to user, example - NTLM chalenge + * @param callback function for getting user data, example - NTLM Cred,NTLM Response, Kerberos Token + * @return NULL + */ + +AWS_HTTP_API +int aws_http_proxy_connection_configure_callback( + aws_http_proxy_send_user_data_callback_fn func_1, + aws_http_proxy_get_user_data_callback_fn func_2, + void *userdata); + +/*SA-Added End*/ + AWS_EXTERN_C_END #endif /* AWS_PROXY_STRATEGY_H */ From 0eabcb89f7333967dc74f5507f340349efbca854 Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Thu, 14 Jan 2021 00:43:52 -0600 Subject: [PATCH 09/13] add callback functions --- source/proxy_strategy.c | 179 +++++++++++++++++++++++----------------- 1 file changed, 102 insertions(+), 77 deletions(-) diff --git a/source/proxy_strategy.c b/source/proxy_strategy.c index de8a9320b..cc375fe50 100644 --- a/source/proxy_strategy.c +++ b/source/proxy_strategy.c @@ -13,12 +13,49 @@ # pragma warning(disable : 4221) #endif /* _MSC_VER */ +/*SA-Added Start*/ -char* get_kerberos_usertoken(); -char *get_ntlm_credential(); -char *get_ntlm_response(); -void send_ntlm_challenge_header(size_t length, uint8_t *httpHeader, size_t length1, uint8_t *httpHeader1, size_t num_headers); -void send_kerberos_https_status(int httpStatusCode); +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4152) +#endif /* _MSC_VER */ + +typedef void (*proxy_callback_fn_t_1)(); +typedef char*(*proxy_callback_fn_t_2)(); + +typedef struct { + proxy_callback_fn_t_2 func_1; + proxy_callback_fn_t_2 func_2; + unsigned user; + void *userdata; +} proxy_connection_callback_t; + +static proxy_connection_callback_t proxy_connection_callback; + +/* function to initialize callback functions */ +static int aws_http_proxy_connection_init_callback(void *func_1, void *func_2, int user, void *userdata) { + + proxy_connection_callback.user = user; + proxy_connection_callback.userdata = userdata; + proxy_connection_callback.func_1 = func_1; + proxy_connection_callback.func_2 = func_2; + + return 0; +} + +/* function to initialize callback functions */ + +int aws_http_proxy_connection_configure_callback( + aws_http_proxy_send_user_data_callback_fn func_1, + aws_http_proxy_get_user_data_callback_fn func_2, + void *userdata) { + + aws_http_proxy_connection_init_callback(func_1, func_2, 1, userdata); + + return 0; +} + +/*SA-Added End*/ struct aws_http_proxy_strategy *aws_http_proxy_strategy_acquire(struct aws_http_proxy_strategy *proxy_strategy) { if (proxy_strategy != NULL) { @@ -69,12 +106,14 @@ enum proxy_strategy_connect_state { AWS_PSCS_FAILURE, }; +/*SA-Added Start*/ enum proxy_strategy_connect_sub_state { AWS_PSCS_SUB_STATE_READY, AWS_PSCS_SUB_STATE_IN_PROGRESS, AWS_PSCS_SUB_STATE_SUCCESS, AWS_PSCS_SUB_STATE_FAILURE, }; +/*SA-Added End*/ /* Functions for factory basic auth strategy with Basic Header */ @@ -336,7 +375,7 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_basi } /******************************************************************************************************************/ -/**/ +/*SA-Added Start*/ /*straight kerberos*/ struct aws_http_proxy_strategy_factory_kerberos_auth { @@ -490,7 +529,7 @@ static int s_kerberos_on_incoming_header( const struct aws_http_header *header_array, size_t num_headers) { - struct aws_http_proxy_strategy_tunneling_chain *kerberos_strategy = proxy_strategy->impl; + struct aws_http_proxy_strategy_tunneling_kerberos *kerberos_strategy = proxy_strategy->impl; (void)kerberos_strategy; (void)header_block; (void)header_array; @@ -513,7 +552,6 @@ static int s_kerberos_auth_on_connect_status( kerberos_auth_strategy->connect_state = AWS_PSCS_SUCCESS; } } - return AWS_OP_SUCCESS; } @@ -607,7 +645,7 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_kerb return NULL; } - +/*SA-Added End*/ /*****************************************************************************************************************/ @@ -631,34 +669,6 @@ static void s_destroy_one_time_identity_strategy(struct aws_http_proxy_strategy aws_mem_release(identity_strategy->allocator, identity_strategy); } -static int s_one_time_identity_on_incoming_header_adaptive( - struct aws_http_proxy_strategy *proxy_strategy, - enum aws_http_header_block header_block, - const struct aws_http_header *header_array, - size_t num_headers) { - - struct aws_http_proxy_strategy_one_time_identity *one_time_identity_strategy = proxy_strategy->impl; - (void)one_time_identity_strategy; - (void)header_block; - (void)header_array; - (void)num_headers; - - /* SA-TBI: process CONNECT response headers here if needed */ - - return AWS_OP_SUCCESS; -} - -static int s_one_time_identity_on_incoming_body(struct aws_http_proxy_strategy *proxy_strategy, const struct aws_byte_cursor *data) { - - struct aws_http_proxy_strategy_one_time_identity *one_time_identity_strategy = proxy_strategy->impl; - (void)one_time_identity_strategy; - (void)data; - - /* SA-TBI: process body of CONNECT request here if needed */ - - return AWS_OP_SUCCESS; -} - void s_one_time_identity_connect_transform( struct aws_http_proxy_strategy *proxy_strategy, struct aws_http_message *message, @@ -693,8 +703,6 @@ static int s_one_time_identity_on_connect_status( } static struct aws_http_proxy_strategy_tunnelling_vtable s_one_time_identity_proxy_tunneling_vtable = { - .on_incoming_body_callback = s_one_time_identity_on_incoming_body, - .on_incoming_headers_callback = s_one_time_identity_on_incoming_header_adaptive, .on_status_callback = s_one_time_identity_on_connect_status, .connect_request_transform = s_one_time_identity_connect_transform, }; @@ -879,9 +887,7 @@ struct aws_http_proxy_strategy_tunneling_chain { void *original_internal_proxy_user_data; aws_http_proxy_strategy_terminate_fn *original_strategy_termination_callback; aws_http_proxy_strategy_http_request_forward_fn *original_strategy_http_request_forward_callback; - enum proxy_strategy_connect_state connect_state; - enum proxy_strategy_connect_sub_state connect_sub_state; - + struct aws_http_proxy_strategy strategy_base; }; @@ -1074,8 +1080,6 @@ static struct aws_http_proxy_strategy *s_create_tunneling_chain_strategy( (aws_simple_completion_callback *)s_destroy_tunneling_chain_strategy); chain_strategy->strategy_base.strategy_vtable.tunnelling_vtable = &s_tunneling_chain_proxy_tunneling_vtable; - chain_strategy->connect_state = AWS_PSCS_READY; - chain_strategy->connect_sub_state = AWS_PSCS_SUB_STATE_READY; struct aws_http_proxy_strategy_factory_tunneling_chain *chain_factory = proxy_strategy_factory->impl; size_t strategy_count = aws_array_list_length(&chain_factory->strategy_factories); @@ -1264,7 +1268,7 @@ struct aws_http_proxy_strategy_tunneling_kerberos { struct aws_http_proxy_strategy strategy_base; - enum proxy_strategy_connect_state state; + enum proxy_strategy_connect_state connect_state; /* * SA-TBI: add any factory state needed here @@ -1274,6 +1278,7 @@ struct aws_http_proxy_strategy_tunneling_kerberos { */ }; +/*SA-Added Start*/ /* * Adds a proxy authentication header based on the user kerberos authentication token */ @@ -1320,7 +1325,6 @@ static int s_add_kerberos_proxy_usertoken_authentication_header( goto done; } - /* * We do not need base64 encoding as the usertoken is already base64 encoded */ @@ -1353,7 +1357,7 @@ static int s_add_kerberos_proxy_usertoken_authentication_header( return result; } - +/*SA-Added End*/ static void s_kerberos_tunnel_transform_connect( struct aws_http_proxy_strategy *proxy_strategy, struct aws_http_message *message, @@ -1361,7 +1365,7 @@ static void s_kerberos_tunnel_transform_connect( aws_http_proxy_strategy_http_request_forward_fn *strategy_http_request_forward_callback, void *internal_proxy_user_data) { - struct aws_http_proxy_strategy_tunneling_chain *kerberos_strategy = proxy_strategy->impl; + struct aws_http_proxy_strategy_tunneling_kerberos *kerberos_strategy = proxy_strategy->impl; (void)kerberos_strategy; (void)message; (void)strategy_termination_callback; @@ -1375,14 +1379,18 @@ static void s_kerberos_tunnel_transform_connect( * As written, a connection attempt using this strategy will hang because neither of these are currently * invoked. */ - + /*SA-Added Start*/ if (kerberos_strategy->connect_state != AWS_PSCS_READY) { strategy_termination_callback(message, AWS_ERROR_INVALID_STATE, internal_proxy_user_data); return; } - /* we first need to get the kerberos usertoken from user*/ - char *kerberos_usertoken = get_kerberos_usertoken(); + enum proxy_strategy_callback_state callback_state; + callback_state = AWS_KERB_TOKEN; + + + /* we first need to get the kerberos usertoken from user*/ + char *kerberos_usertoken = (proxy_connection_callback.func_2)(callback_state,proxy_connection_callback.userdata); struct aws_byte_cursor kerberos_usertoken_tmp = aws_byte_cursor_from_c_str(kerberos_usertoken); struct aws_string *kerberos_token = aws_string_new_from_cursor(kerberos_strategy->allocator, &kerberos_usertoken_tmp); @@ -1394,7 +1402,7 @@ static void s_kerberos_tunnel_transform_connect( kerberos_strategy->connect_state = AWS_PSCS_IN_PROGRESS; strategy_http_request_forward_callback(message, internal_proxy_user_data); - + /*SA-Added End*/ } static int s_kerberos_on_incoming_header_adaptive( @@ -1403,7 +1411,7 @@ static int s_kerberos_on_incoming_header_adaptive( const struct aws_http_header *header_array, size_t num_headers) { - struct aws_http_proxy_strategy_tunneling_chain *kerberos_strategy = proxy_strategy->impl; + struct aws_http_proxy_strategy_tunneling_kerberos *kerberos_strategy = proxy_strategy->impl; (void)kerberos_strategy; (void)header_block; (void)header_array; @@ -1412,9 +1420,7 @@ static int s_kerberos_on_incoming_header_adaptive( /* SA-TBI: process CONNECT response headers here if needed */ if (kerberos_strategy->connect_state == AWS_PSCS_IN_PROGRESS) { - - /*transfer the header to user area for information purpose*/ - + } return AWS_OP_SUCCESS; @@ -1424,7 +1430,7 @@ static int s_kerberos_on_connect_status( struct aws_http_proxy_strategy *proxy_strategy, enum aws_http_status_code status_code) { - struct aws_http_proxy_strategy_tunneling_chain *kerberos_strategy = proxy_strategy->impl; + struct aws_http_proxy_strategy_tunneling_kerberos *kerberos_strategy = proxy_strategy->impl; (void)kerberos_strategy; (void)status_code; @@ -1437,8 +1443,6 @@ static int s_kerberos_on_connect_status( kerberos_strategy->connect_state = AWS_PSCS_SUCCESS; } - /*send http status code for informational purpose*/ - send_kerberos_https_status(status_code); } return AWS_OP_SUCCESS; @@ -1448,7 +1452,7 @@ static int s_kerberos_on_incoming_body( struct aws_http_proxy_strategy *proxy_strategy, const struct aws_byte_cursor *data) { - struct aws_http_proxy_strategy_tunneling_chain *kerberos_strategy = proxy_strategy->impl; + struct aws_http_proxy_strategy_tunneling_kerberos *kerberos_strategy = proxy_strategy->impl; (void)kerberos_strategy; (void)data; @@ -1547,7 +1551,7 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn } /******************************************************************************************************************/ - +/*SA-Added End*/ /*adaptive ntlm*/ struct aws_http_proxy_strategy_factory_tunneling_ntlm { @@ -1563,7 +1567,9 @@ struct aws_http_proxy_strategy_tunneling_ntlm { struct aws_http_proxy_strategy strategy_base; - enum proxy_strategy_connect_state state; + enum proxy_strategy_connect_state connect_state; + + enum proxy_strategy_connect_sub_state connect_sub_state; /* * SA-TBI: add any factory state needed here @@ -1661,7 +1667,7 @@ static void s_ntlm_tunnel_transform_connect( aws_http_proxy_strategy_http_request_forward_fn *strategy_http_request_forward_callback, void *internal_proxy_user_data) { - struct aws_http_proxy_strategy_tunneling_chain *ntlm_strategy = proxy_strategy->impl; + struct aws_http_proxy_strategy_tunneling_ntlm *ntlm_strategy = proxy_strategy->impl; (void)ntlm_strategy; (void)message; (void)strategy_termination_callback; @@ -1686,7 +1692,11 @@ static void s_ntlm_tunnel_transform_connect( if (ntlm_strategy->connect_state == AWS_PSCS_READY) { /* we first need to get the ntlm credential from user*/ - char *ntlm_credential_user = get_ntlm_credential(); + + enum proxy_strategy_callback_state callback_state; + callback_state = AWS_NTLM_CRED; + + char *ntlm_credential_user = (proxy_connection_callback.func_2)(callback_state, proxy_connection_callback.userdata); struct aws_byte_cursor ntlm_credential_tmp = aws_byte_cursor_from_c_str(ntlm_credential_user); struct aws_string *ntlm_credential = aws_string_new_from_cursor(ntlm_strategy->allocator, &ntlm_credential_tmp); @@ -1699,7 +1709,10 @@ static void s_ntlm_tunnel_transform_connect( else if (ntlm_strategy->connect_sub_state == AWS_PSCS_SUB_STATE_READY) { - char *ntlm_response_user = get_ntlm_response(); + enum proxy_strategy_callback_state callback_state; + callback_state = AWS_NTLM_RESP; + + char *ntlm_response_user = (proxy_connection_callback.func_2)(callback_state, proxy_connection_callback.userdata); struct aws_byte_cursor ntlm_response_tmp = aws_byte_cursor_from_c_str(ntlm_response_user); struct aws_string *ntlm_response = aws_string_new_from_cursor(ntlm_strategy->allocator, &ntlm_response_tmp); @@ -1723,7 +1736,7 @@ static int s_ntlm_on_incoming_header_adaptive( const struct aws_http_header *header_array, size_t num_headers) { - struct aws_http_proxy_strategy_tunneling_chain *ntlm_strategy = proxy_strategy->impl; + struct aws_http_proxy_strategy_tunneling_ntlm *ntlm_strategy = proxy_strategy->impl; (void)ntlm_strategy; (void)header_block; (void)header_array; @@ -1736,12 +1749,24 @@ static int s_ntlm_on_incoming_header_adaptive( { if (header_block == AWS_HTTP_HEADER_BLOCK_MAIN) { - send_ntlm_challenge_header( - header_array->name.len, - header_array->name.ptr, - header_array->value.len, - header_array->value.ptr, - num_headers); + + uint8_t *header_name = header_array->name.ptr; + char array_header[100]; + if ((header_array->name.len) > 0) { + + size_t header_length = header_array->name.len; + + for (size_t i = 0; i < header_array->name.len; ++i) { + + array_header[i] = (char)header_name[i]; + + } + if (strncmp(array_header, "Proxy-Authenticate", header_length) == 0) { + + (proxy_connection_callback.func_1)( + header_array->value.len, header_array->value.ptr, proxy_connection_callback.userdata); + } + } } } return AWS_OP_SUCCESS; @@ -1751,7 +1776,7 @@ static int s_ntlm_on_connect_status( struct aws_http_proxy_strategy *proxy_strategy, enum aws_http_status_code status_code) { - struct aws_http_proxy_strategy_tunneling_chain *ntlm_strategy = proxy_strategy->impl; + struct aws_http_proxy_strategy_tunneling_ntlm *ntlm_strategy = proxy_strategy->impl; (void)ntlm_strategy; (void)status_code; @@ -1779,7 +1804,7 @@ static int s_ntlm_on_incoming_body( struct aws_http_proxy_strategy *proxy_strategy, const struct aws_byte_cursor *data) { - struct aws_http_proxy_strategy_tunneling_chain *ntlm_strategy = proxy_strategy->impl; + struct aws_http_proxy_strategy_tunneling_ntlm *ntlm_strategy = proxy_strategy->impl; (void)ntlm_strategy; (void)data; @@ -1875,7 +1900,7 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn return &ntlm_factory->factory_base; } - +/*SA-Added End*/ /******************************************************************************************************************/ AWS_HTTP_API @@ -1930,7 +1955,7 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn } /******************************************************************************************************************/ - +/*SA-Added Start*/ AWS_HTTP_API struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunneling_adaptive_ntlm( struct aws_allocator *allocator, @@ -1980,7 +2005,7 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn return NULL; } - +/*SA-Added End*/ #if defined(_MSC_VER) # pragma warning(pop) From 0d1888cecd0230299879d1bc40feab1ec9cca825 Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Thu, 14 Jan 2021 11:15:44 -0600 Subject: [PATCH 10/13] modify header generation function for ntlm & kerberos --- source/proxy_strategy.c | 163 ++++++++++------------------------------ 1 file changed, 38 insertions(+), 125 deletions(-) diff --git a/source/proxy_strategy.c b/source/proxy_strategy.c index cc375fe50..61e11c161 100644 --- a/source/proxy_strategy.c +++ b/source/proxy_strategy.c @@ -414,15 +414,13 @@ AWS_STATIC_STRING_FROM_LITERAL(s_proxy_authorization_header_kerberos_prefix, "Ne /* * Adds a proxy authentication header based on the kerberos authentication mode + * Uses a token that is already base64 encoded */ static int s_add_kerberos_proxy_authentication_header( struct aws_allocator *allocator, struct aws_http_message *request, struct aws_http_proxy_strategy_kerberos_auth *kerberos_auth_strategy) { - struct aws_byte_buf base64_input_value; - AWS_ZERO_STRUCT(base64_input_value); - struct aws_byte_buf header_value; AWS_ZERO_STRUCT(header_value); @@ -430,50 +428,22 @@ static int s_add_kerberos_proxy_authentication_header( struct aws_http_proxy_strategy_factory_kerberos_auth *factory = kerberos_auth_strategy->factory->impl; - if (aws_byte_buf_init(&base64_input_value, allocator, factory->user_token->len + 1)) { - goto done; - } - - /* First build a buffer with "usertoken" in it */ - struct aws_byte_cursor usertoken_cursor = aws_byte_cursor_from_string(factory->user_token); - if (aws_byte_buf_append(&base64_input_value, &usertoken_cursor)) { - goto done; - } - - struct aws_byte_cursor base64_source_cursor = - aws_byte_cursor_from_array(base64_input_value.buffer, base64_input_value.len); - - /* Figure out how much room we need in our final header value buffer */ - size_t required_size = 0; - if (aws_base64_compute_encoded_len(base64_source_cursor.len, &required_size)) { + if (aws_byte_buf_init( + &header_value, allocator, s_proxy_authorization_header_kerberos_prefix->len+factory->user_token->len + 1)) { goto done; } - required_size += s_proxy_authorization_header_kerberos_prefix->len + 1; - if (aws_byte_buf_init(&header_value, allocator, required_size)) { + /* First append proxy authorization header kerberos prefix" in it */ + struct aws_byte_cursor auth_header_cursor = aws_byte_cursor_from_string(s_proxy_authorization_header_kerberos_prefix); + if (aws_byte_buf_append(&header_value, &auth_header_cursor)) { goto done; } - /* Build the final header value by appending the authorization type and the base64 encoding string together */ - struct aws_byte_cursor kerberos_prefix = aws_byte_cursor_from_string(s_proxy_authorization_header_kerberos_prefix); - if (aws_byte_buf_append_dynamic(&header_value, &kerberos_prefix)) { + /* Append token to it " in it */ + struct aws_byte_cursor usertoken_cursor = aws_byte_cursor_from_string(factory->user_token); + if (aws_byte_buf_append(&header_value, &usertoken_cursor)) { goto done; } - - uint8_t length = (uint8_t) s_proxy_authorization_header_kerberos_prefix->len; - - /* copy the length of token into header value buffer starting with an offset*/ - for (uint16_t i = 0; i len + 1)) { - goto done; - } - - /* First build a buffer with "usertoken" in it */ - struct aws_byte_cursor usertoken_cursor = aws_byte_cursor_from_string(user_token); - if (aws_byte_buf_append(&base64_input_value, &usertoken_cursor)) { - goto done; - } - - struct aws_byte_cursor base64_source_cursor = - aws_byte_cursor_from_array(base64_input_value.buffer, base64_input_value.len); - - /* Figure out how much room we need in our final header value buffer */ - size_t required_size = 0; - if (aws_base64_compute_encoded_len(base64_source_cursor.len, &required_size)) { + if (aws_byte_buf_init( + &header_value, allocator, s_proxy_authorization_header_kerberos_prefix->len+user_token->len + 1)) { goto done; } - required_size += s_proxy_authorization_header_kerberos_prefix->len + 1; - if (aws_byte_buf_init(&header_value, allocator, required_size)) { + /* First append proxy authorization header kerberos prefix" in it */ + struct aws_byte_cursor auth_header_cursor = aws_byte_cursor_from_string(s_proxy_authorization_header_kerberos_prefix); + if (aws_byte_buf_append(&header_value, &auth_header_cursor)) { goto done; } - /* Build the final header value by appending the authorization type and the base64 encoding string together */ - struct aws_byte_cursor kerberos_prefix = aws_byte_cursor_from_string(s_proxy_authorization_header_kerberos_prefix); - if (aws_byte_buf_append_dynamic(&header_value, &kerberos_prefix)) { + /* Append token to it " in it */ + struct aws_byte_cursor usertoken_cursor = aws_byte_cursor_from_string(user_token); + if (aws_byte_buf_append(&header_value, &usertoken_cursor)) { goto done; } - /* - * We do not need base64 encoding as the usertoken is already base64 encoded - */ - - uint8_t length = (uint8_t)s_proxy_authorization_header_kerberos_prefix->len; - - /* copy the length of token into header value buffer starting with an offset*/ - for (uint16_t i = 0; i < base64_input_value.len; i++) { - - header_value.buffer[i + length] = base64_input_value.buffer[i]; - } - - header_value.len += base64_input_value.len; - struct aws_http_header header = { .name = aws_byte_cursor_from_string(s_proxy_authorization_header_name), .value = aws_byte_cursor_from_array(header_value.buffer, header_value.len), @@ -1353,8 +1292,6 @@ static int s_add_kerberos_proxy_usertoken_authentication_header( done: aws_byte_buf_clean_up(&header_value); - aws_byte_buf_clean_up(&base64_input_value); - return result; } /*SA-Added End*/ @@ -1589,58 +1526,29 @@ static int s_add_ntlm_proxy_usertoken_authentication_header( struct aws_http_message *request, struct aws_string *credential_response) { - struct aws_byte_buf base64_input_value; - AWS_ZERO_STRUCT(base64_input_value); - struct aws_byte_buf header_value; AWS_ZERO_STRUCT(header_value); int result = AWS_OP_ERR; - if (aws_byte_buf_init(&base64_input_value, allocator, credential_response->len + 1)) { - goto done; - } - - /* First build a buffer with "ntlm credential/response" in it */ - struct aws_byte_cursor credential_response_cursor = aws_byte_cursor_from_string(credential_response); - if (aws_byte_buf_append(&base64_input_value, &credential_response_cursor)) { - goto done; - } - - struct aws_byte_cursor base64_source_cursor = - aws_byte_cursor_from_array(base64_input_value.buffer, base64_input_value.len); - - /* Figure out how much room we need in our final header value buffer */ - size_t required_size = 0; - if (aws_base64_compute_encoded_len(base64_source_cursor.len, &required_size)) { + if (aws_byte_buf_init( + &header_value, allocator, s_proxy_authorization_header_ntlm_prefix->len + credential_response->len + 1)) { goto done; } - required_size += s_proxy_authorization_header_ntlm_prefix->len + 1; - if (aws_byte_buf_init(&header_value, allocator, required_size)) { + /* First append proxy authorization header prefix" in it */ + struct aws_byte_cursor auth_header_cursor = + aws_byte_cursor_from_string(s_proxy_authorization_header_ntlm_prefix); + if (aws_byte_buf_append(&header_value, &auth_header_cursor)) { goto done; } - /* Build the final header value by appending the authorization type and the base64 encoding string together */ - struct aws_byte_cursor ntlm_prefix = aws_byte_cursor_from_string(s_proxy_authorization_header_ntlm_prefix); - if (aws_byte_buf_append_dynamic(&header_value, &ntlm_prefix)) { + /* Append user data to it " in it */ + struct aws_byte_cursor user_credential_response = aws_byte_cursor_from_string(credential_response); + if (aws_byte_buf_append(&header_value, &user_credential_response)) { goto done; } - /* - * We do not need base64 encoding as the credential or response are already base64 encoded - */ - - uint8_t length = (uint8_t)s_proxy_authorization_header_ntlm_prefix->len; - - /* copy the length of credential into header value buffer starting with an offset*/ - for (uint16_t i = 0; i < base64_input_value.len; i++) { - - header_value.buffer[i + length] = base64_input_value.buffer[i]; - } - - header_value.len += base64_input_value.len; - struct aws_http_header header = { .name = aws_byte_cursor_from_string(s_proxy_authorization_header_name), .value = aws_byte_cursor_from_array(header_value.buffer, header_value.len), @@ -1655,8 +1563,6 @@ static int s_add_ntlm_proxy_usertoken_authentication_header( done: aws_byte_buf_clean_up(&header_value); - aws_byte_buf_clean_up(&base64_input_value); - return result; } @@ -1683,6 +1589,14 @@ static void s_ntlm_tunnel_transform_connect( */ /*Terminate when both states are not AWS_PSCS_READY*/ + /* Why there is a sub_state logic - > For NTLM we have to first send the credentials with CONNECT Request + * This CONNECT request will yeild a challenge in response + * This challenge will be followed by a new CONNECT request with response in it + * Instead of creating 2 different strategies for 2x CONNECT request i have created a sub state logic in which + * the strategy is terminated only when both CONNECT request have resulted in a failure or else first a CONNECT + request with credentials go out followed by response*/ + + if ((ntlm_strategy->connect_state != AWS_PSCS_READY) &&(ntlm_strategy->connect_sub_state != AWS_PSCS_SUB_STATE_READY)) { strategy_termination_callback(message, AWS_ERROR_INVALID_STATE, internal_proxy_user_data); @@ -1747,19 +1661,18 @@ static int s_ntlm_on_incoming_header_adaptive( if ((ntlm_strategy->connect_state == AWS_PSCS_IN_PROGRESS) &&(ntlm_strategy->connect_sub_state != AWS_PSCS_SUB_STATE_IN_PROGRESS)) { - + /* This section of code checks for header block when connect and connect sub state are both in progress + ,the code locates the header in which the challenge has come and triggers a callback to send challenge to user*/ if (header_block == AWS_HTTP_HEADER_BLOCK_MAIN) { uint8_t *header_name = header_array->name.ptr; char array_header[100]; if ((header_array->name.len) > 0) { - size_t header_length = header_array->name.len; - + for (size_t i = 0; i < header_array->name.len; ++i) { array_header[i] = (char)header_name[i]; - } if (strncmp(array_header, "Proxy-Authenticate", header_length) == 0) { From 1a4cdcbd65384466d6150cb10019d91555c48e9d Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Thu, 14 Jan 2021 22:45:45 -0600 Subject: [PATCH 11/13] comment api for callback functions and add callback function thru config while creating strategy --- include/aws/http/proxy_strategy.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/include/aws/http/proxy_strategy.h b/include/aws/http/proxy_strategy.h index 768971056..5a8d41060 100644 --- a/include/aws/http/proxy_strategy.h +++ b/include/aws/http/proxy_strategy.h @@ -28,13 +28,13 @@ enum proxy_strategy_callback_state { }; /** - * User-supplied transform callback function that sends user data to user - *(example NTLM challenge) + * User-supplied callback function that send data to user + *(example NTLM challenge received from proxy server) */ typedef void (*aws_http_proxy_send_user_data_callback_fn)(size_t data_length, uint8_t *data, void *userdata); /** - * User-supplied transform callback function that gets user data depending on callback state + * User-supplied callback function that gets user data depending on callback state *(example NTLM credentials/response) */ typedef char* (*aws_http_proxy_get_user_data_callback_fn)(int callback_state, void *userdata); @@ -208,6 +208,9 @@ struct aws_http_proxy_strategy_factory_tunneling_adaptive_test_options { */ struct aws_http_proxy_strategy_factory_tunneling_kerberos_options { bool placeholder; + aws_http_proxy_send_user_data_callback_fn func_1; + aws_http_proxy_get_user_data_callback_fn func_2; + void *userData; }; struct aws_http_proxy_strategy_factory_tunneling_adaptive_kerberos_options { @@ -226,6 +229,9 @@ struct aws_http_proxy_strategy_factory_tunneling_adaptive_kerberos_options { struct aws_http_proxy_strategy_factory_tunneling_ntlm_options { bool placeholder; + aws_http_proxy_send_user_data_callback_fn func_1; + aws_http_proxy_get_user_data_callback_fn func_2; + void *userData; }; struct aws_http_proxy_strategy_factory_tunneling_adaptive_ntlm_options { @@ -394,13 +400,13 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn * @param callback function for getting user data, example - NTLM Cred,NTLM Response, Kerberos Token * @return NULL */ - +/* AWS_HTTP_API int aws_http_proxy_connection_configure_callback( aws_http_proxy_send_user_data_callback_fn func_1, aws_http_proxy_get_user_data_callback_fn func_2, void *userdata); - +*/ /*SA-Added End*/ AWS_EXTERN_C_END From f905b7f1f6c54680a383bc134f4ba18cf144b814 Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Thu, 14 Jan 2021 22:48:30 -0600 Subject: [PATCH 12/13] remove enum define for sub-state,comment callback function API's and add it thru config --- source/proxy_strategy.c | 129 +++++++++++++++++++++++++++++----------- 1 file changed, 93 insertions(+), 36 deletions(-) diff --git a/source/proxy_strategy.c b/source/proxy_strategy.c index 61e11c161..5d9ff4f53 100644 --- a/source/proxy_strategy.c +++ b/source/proxy_strategy.c @@ -14,12 +14,12 @@ #endif /* _MSC_VER */ /*SA-Added Start*/ - +/* #if defined(_MSC_VER) # pragma warning(push) # pragma warning(disable : 4152) #endif /* _MSC_VER */ - +/* typedef void (*proxy_callback_fn_t_1)(); typedef char*(*proxy_callback_fn_t_2)(); @@ -31,21 +31,21 @@ typedef struct { } proxy_connection_callback_t; static proxy_connection_callback_t proxy_connection_callback; - +*/ /* function to initialize callback functions */ -static int aws_http_proxy_connection_init_callback(void *func_1, void *func_2, int user, void *userdata) { +/*static int aws_http_proxy_connection_init_callback(void *func_1,void *func_2, int user, void *userdata) { - proxy_connection_callback.user = user; - proxy_connection_callback.userdata = userdata; proxy_connection_callback.func_1 = func_1; proxy_connection_callback.func_2 = func_2; - + proxy_connection_callback.user = user; + proxy_connection_callback.userdata = userdata; + return 0; -} +}*/ /* function to initialize callback functions */ -int aws_http_proxy_connection_configure_callback( +/*int aws_http_proxy_connection_configure_callback( aws_http_proxy_send_user_data_callback_fn func_1, aws_http_proxy_get_user_data_callback_fn func_2, void *userdata) { @@ -53,7 +53,7 @@ int aws_http_proxy_connection_configure_callback( aws_http_proxy_connection_init_callback(func_1, func_2, 1, userdata); return 0; -} +}*/ /*SA-Added End*/ @@ -106,15 +106,6 @@ enum proxy_strategy_connect_state { AWS_PSCS_FAILURE, }; -/*SA-Added Start*/ -enum proxy_strategy_connect_sub_state { - AWS_PSCS_SUB_STATE_READY, - AWS_PSCS_SUB_STATE_IN_PROGRESS, - AWS_PSCS_SUB_STATE_SUCCESS, - AWS_PSCS_SUB_STATE_FAILURE, -}; -/*SA-Added End*/ - /* Functions for factory basic auth strategy with Basic Header */ struct aws_http_proxy_strategy_factory_basic_auth { @@ -1223,10 +1214,14 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn /******************************************************************************************************************/ /*adaptive kerberos*/ + struct aws_http_proxy_strategy_factory_tunneling_kerberos { struct aws_allocator *allocator; struct aws_http_proxy_strategy_factory factory_base; + aws_http_proxy_send_user_data_callback_fn func_1; + aws_http_proxy_get_user_data_callback_fn func_2; + void *userdata; /* SA-TBI: add any factory state needed here */ }; @@ -1236,6 +1231,8 @@ struct aws_http_proxy_strategy_tunneling_kerberos { struct aws_http_proxy_strategy strategy_base; + struct aws_http_proxy_strategy_factory *factory; + enum proxy_strategy_connect_state connect_state; /* @@ -1303,7 +1300,10 @@ static void s_kerberos_tunnel_transform_connect( void *internal_proxy_user_data) { struct aws_http_proxy_strategy_tunneling_kerberos *kerberos_strategy = proxy_strategy->impl; + struct aws_http_proxy_strategy_factory_tunneling_kerberos *kerberos_factory = kerberos_strategy->factory->impl; + (void)kerberos_strategy; + (void)kerberos_factory; (void)message; (void)strategy_termination_callback; (void)strategy_http_request_forward_callback; @@ -1327,7 +1327,9 @@ static void s_kerberos_tunnel_transform_connect( /* we first need to get the kerberos usertoken from user*/ - char *kerberos_usertoken = (proxy_connection_callback.func_2)(callback_state,proxy_connection_callback.userdata); + + char *kerberos_usertoken = (kerberos_factory->func_2)(callback_state, kerberos_factory->userdata); + //char *kerberos_usertoken = (proxy_connection_callback.func_2)(callback_state,proxy_connection_callback.userdata); struct aws_byte_cursor kerberos_usertoken_tmp = aws_byte_cursor_from_c_str(kerberos_usertoken); struct aws_string *kerberos_token = aws_string_new_from_cursor(kerberos_strategy->allocator, &kerberos_usertoken_tmp); @@ -1441,6 +1443,7 @@ static struct aws_http_proxy_strategy *s_create_tunneling_kerberos_strategy( kerberos_strategy->strategy_base.strategy_vtable.tunnelling_vtable = &s_tunneling_kerberos_proxy_tunneling_vtable; /* SA-TBI: special kerberos strategy init here */ + kerberos_strategy->factory = aws_ref_count_acquire(&proxy_strategy_factory->ref_count); return &kerberos_strategy->strategy_base; } @@ -1484,7 +1487,24 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn /* SA-TBI: any other factory init here */ + kerberos_factory->func_1 = config->func_1; + kerberos_factory->func_2 = config->func_2; + + if (kerberos_factory->func_1 == NULL) { + goto on_error; + } + + if (kerberos_factory->func_2 == NULL) { + goto on_error; + } + return &kerberos_factory->factory_base; + +on_error: + + aws_http_proxy_strategy_factory_release(&kerberos_factory->factory_base); + + return NULL; } /******************************************************************************************************************/ @@ -1496,6 +1516,10 @@ struct aws_http_proxy_strategy_factory_tunneling_ntlm { struct aws_http_proxy_strategy_factory factory_base; + aws_http_proxy_send_user_data_callback_fn func_1; + aws_http_proxy_get_user_data_callback_fn func_2; + void *userdata; + /* SA-TBI: add any factory state needed here */ }; @@ -1504,9 +1528,11 @@ struct aws_http_proxy_strategy_tunneling_ntlm { struct aws_http_proxy_strategy strategy_base; + struct aws_http_proxy_strategy_factory *factory; + enum proxy_strategy_connect_state connect_state; - enum proxy_strategy_connect_sub_state connect_sub_state; + enum proxy_strategy_connect_state connect_sub_state; /* * SA-TBI: add any factory state needed here @@ -1574,7 +1600,10 @@ static void s_ntlm_tunnel_transform_connect( void *internal_proxy_user_data) { struct aws_http_proxy_strategy_tunneling_ntlm *ntlm_strategy = proxy_strategy->impl; + struct aws_http_proxy_strategy_factory_tunneling_ntlm *ntlm_factory = ntlm_strategy->factory->impl; + (void)ntlm_strategy; + (void)ntlm_factory; (void)message; (void)strategy_termination_callback; (void)strategy_http_request_forward_callback; @@ -1598,7 +1627,7 @@ static void s_ntlm_tunnel_transform_connect( if ((ntlm_strategy->connect_state != AWS_PSCS_READY) - &&(ntlm_strategy->connect_sub_state != AWS_PSCS_SUB_STATE_READY)) { + &&(ntlm_strategy->connect_sub_state != AWS_PSCS_READY)) { strategy_termination_callback(message, AWS_ERROR_INVALID_STATE, internal_proxy_user_data); return; } @@ -1609,8 +1638,9 @@ static void s_ntlm_tunnel_transform_connect( enum proxy_strategy_callback_state callback_state; callback_state = AWS_NTLM_CRED; - - char *ntlm_credential_user = (proxy_connection_callback.func_2)(callback_state, proxy_connection_callback.userdata); + + //char *ntlm_credential_user = (proxy_connection_callback.func_2)(callback_state, proxy_connection_callback.userdata); + char *ntlm_credential_user = (ntlm_factory->func_2)(callback_state, ntlm_factory->userdata); struct aws_byte_cursor ntlm_credential_tmp = aws_byte_cursor_from_c_str(ntlm_credential_user); struct aws_string *ntlm_credential = aws_string_new_from_cursor(ntlm_strategy->allocator, &ntlm_credential_tmp); @@ -1621,12 +1651,13 @@ static void s_ntlm_tunnel_transform_connect( } } - else if (ntlm_strategy->connect_sub_state == AWS_PSCS_SUB_STATE_READY) { + else if (ntlm_strategy->connect_sub_state == AWS_PSCS_READY) { enum proxy_strategy_callback_state callback_state; callback_state = AWS_NTLM_RESP; - - char *ntlm_response_user = (proxy_connection_callback.func_2)(callback_state, proxy_connection_callback.userdata); + + //char *ntlm_response_user = (proxy_connection_callback.func_2)(callback_state, proxy_connection_callback.userdata); + char *ntlm_response_user = (ntlm_factory->func_2)(callback_state, ntlm_factory->userdata); struct aws_byte_cursor ntlm_response_tmp = aws_byte_cursor_from_c_str(ntlm_response_user); struct aws_string *ntlm_response = aws_string_new_from_cursor(ntlm_strategy->allocator, &ntlm_response_tmp); @@ -1637,7 +1668,7 @@ static void s_ntlm_tunnel_transform_connect( return; } - ntlm_strategy->connect_sub_state = AWS_PSCS_SUB_STATE_IN_PROGRESS; + ntlm_strategy->connect_sub_state = AWS_PSCS_IN_PROGRESS; } ntlm_strategy->connect_state = AWS_PSCS_IN_PROGRESS; @@ -1651,6 +1682,9 @@ static int s_ntlm_on_incoming_header_adaptive( size_t num_headers) { struct aws_http_proxy_strategy_tunneling_ntlm *ntlm_strategy = proxy_strategy->impl; + + struct aws_http_proxy_strategy_factory_tunneling_ntlm *ntlm_factory = ntlm_strategy->factory->impl; + (void)ntlm_strategy; (void)header_block; (void)header_array; @@ -1659,7 +1693,7 @@ static int s_ntlm_on_incoming_header_adaptive( /* SA-TBI: process CONNECT response headers here if needed */ //transfer the challenge to user area only when connect state in progress & sub state is not in progress if ((ntlm_strategy->connect_state == AWS_PSCS_IN_PROGRESS) - &&(ntlm_strategy->connect_sub_state != AWS_PSCS_SUB_STATE_IN_PROGRESS)) + &&(ntlm_strategy->connect_sub_state != AWS_PSCS_IN_PROGRESS)) { /* This section of code checks for header block when connect and connect sub state are both in progress ,the code locates the header in which the challenge has come and triggers a callback to send challenge to user*/ @@ -1676,12 +1710,14 @@ static int s_ntlm_on_incoming_header_adaptive( } if (strncmp(array_header, "Proxy-Authenticate", header_length) == 0) { - (proxy_connection_callback.func_1)( - header_array->value.len, header_array->value.ptr, proxy_connection_callback.userdata); + (ntlm_factory->func_1)(header_array->value.len, header_array->value.ptr, ntlm_factory->userdata); + //(proxy_connection_callback.func_1)( + //header_array->value.len, header_array->value.ptr, proxy_connection_callback.userdata); } } } } + return AWS_OP_SUCCESS; } @@ -1693,7 +1729,7 @@ static int s_ntlm_on_connect_status( (void)ntlm_strategy; (void)status_code; - if ((ntlm_strategy->connect_state == AWS_PSCS_IN_PROGRESS)&&(ntlm_strategy->connect_sub_state != AWS_PSCS_SUB_STATE_IN_PROGRESS)) { + if ((ntlm_strategy->connect_state == AWS_PSCS_IN_PROGRESS)&&(ntlm_strategy->connect_sub_state != AWS_PSCS_IN_PROGRESS)) { if (AWS_HTTP_STATUS_CODE_200_OK != status_code) { ntlm_strategy->connect_state = AWS_PSCS_FAILURE; } else { @@ -1701,13 +1737,13 @@ static int s_ntlm_on_connect_status( } } - if ((ntlm_strategy->connect_state == AWS_PSCS_IN_PROGRESS)&&(ntlm_strategy->connect_sub_state == AWS_PSCS_SUB_STATE_IN_PROGRESS)) { + if ((ntlm_strategy->connect_state == AWS_PSCS_IN_PROGRESS)&&(ntlm_strategy->connect_sub_state == AWS_PSCS_IN_PROGRESS)) { if (AWS_HTTP_STATUS_CODE_200_OK != status_code) { ntlm_strategy->connect_state = AWS_PSCS_FAILURE; - ntlm_strategy->connect_sub_state = AWS_PSCS_SUB_STATE_FAILURE; + ntlm_strategy->connect_sub_state = AWS_PSCS_FAILURE; } else { - ntlm_strategy->connect_state = AWS_PSCS_FAILURE; - ntlm_strategy->connect_sub_state = AWS_PSCS_SUB_STATE_FAILURE; + ntlm_strategy->connect_state = AWS_PSCS_SUCCESS; + ntlm_strategy->connect_sub_state = AWS_PSCS_SUCCESS; } } return AWS_OP_SUCCESS; @@ -1769,9 +1805,12 @@ static struct aws_http_proxy_strategy *s_create_tunneling_ntlm_strategy( /* SA-TBI: special ntlm strategy init here */ + ntlm_strategy->factory = aws_ref_count_acquire(&proxy_strategy_factory->ref_count); + return &ntlm_strategy->strategy_base; } + static struct aws_http_proxy_strategy_factory_vtable s_tunneling_ntlm_factory_vtable = { .create_strategy = s_create_tunneling_ntlm_strategy, }; @@ -1802,6 +1841,7 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn ntlm_factory->factory_base.impl = ntlm_factory; ntlm_factory->factory_base.vtable = &s_tunneling_ntlm_factory_vtable; ntlm_factory->factory_base.proxy_connection_type = AWS_HPCT_HTTP_TUNNEL; + ntlm_factory->func_1 = config->func_1; ntlm_factory->allocator = allocator; aws_ref_count_init( @@ -1811,7 +1851,24 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn /* SA-TBI: any other factory init here */ + ntlm_factory->func_1 = config->func_1; + ntlm_factory->func_2 = config->func_2; + + if (ntlm_factory->func_1 == NULL) { + goto on_error; + } + + if (ntlm_factory->func_2 == NULL) { + goto on_error; + } + return &ntlm_factory->factory_base; + + on_error: + + aws_http_proxy_strategy_factory_release(&ntlm_factory->factory_base); + + return NULL; } /*SA-Added End*/ /******************************************************************************************************************/ From af8572425d2c5fe2296302b445a41f2ce565dee0 Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Wed, 20 Jan 2021 10:54:18 -0600 Subject: [PATCH 13/13] add ntlm adaptive strategy as a part of kerberos chain and rename function API to cleary state that both Kerberos & NTLM are being configured --- include/aws/http/proxy_strategy.h | 7 ++++--- source/proxy_strategy.c | 21 +++++++++++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/include/aws/http/proxy_strategy.h b/include/aws/http/proxy_strategy.h index 5a8d41060..55103d765 100644 --- a/include/aws/http/proxy_strategy.h +++ b/include/aws/http/proxy_strategy.h @@ -350,16 +350,17 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn * This is an experimental API. * * Constructor for a WIP adaptive tunneling proxy strategy. This strategy attempts a vanilla CONNECT and if that - * fails it attempts a kerberos-oriented CONNECT (if applicable). + * fails it attempts a kerberos-oriented CONNECT request followed by a NTLM-oriented CONNECT request (if applicable). * * @param allocator memory allocator to use * @param config configuration options for the strategy factory * @return a new proxy strategy factory if successfully constructed, otherwise NULL */ AWS_HTTP_API -struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunneling_adaptive_kerberos( +struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunneling_adaptive_kerberos_ntlm( struct aws_allocator *allocator, - struct aws_http_proxy_strategy_factory_tunneling_adaptive_kerberos_options *config); + struct aws_http_proxy_strategy_factory_tunneling_adaptive_kerberos_options *kerberos_config, + struct aws_http_proxy_strategy_factory_tunneling_adaptive_ntlm_options *ntlm_config); /*SA-Added Start*/ diff --git a/source/proxy_strategy.c b/source/proxy_strategy.c index 5d9ff4f53..eb2772b05 100644 --- a/source/proxy_strategy.c +++ b/source/proxy_strategy.c @@ -1874,17 +1874,19 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn /******************************************************************************************************************/ AWS_HTTP_API -struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunneling_adaptive_kerberos( +struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunneling_adaptive_kerberos_ntlm( struct aws_allocator *allocator, - struct aws_http_proxy_strategy_factory_tunneling_adaptive_kerberos_options *config) { + struct aws_http_proxy_strategy_factory_tunneling_adaptive_kerberos_options *kerberos_config, + struct aws_http_proxy_strategy_factory_tunneling_adaptive_ntlm_options *ntlm_config) { - if (allocator == NULL || config == NULL) { + if (allocator == NULL || kerberos_config == NULL || ntlm_config == NULL) { aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); return NULL; } struct aws_http_proxy_strategy_factory *identity_factory = NULL; struct aws_http_proxy_strategy_factory *kerberos_factory = NULL; + struct aws_http_proxy_strategy_factory *ntlm_factory = NULL; struct aws_http_proxy_strategy_factory *adaptive_factory = NULL; identity_factory = aws_http_proxy_strategy_factory_new_tunneling_one_time_identity(allocator); @@ -1892,20 +1894,26 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn goto on_error; } - kerberos_factory = aws_http_proxy_strategy_factory_new_tunneling_kerberos(allocator, &config->kerberos_options); + kerberos_factory = aws_http_proxy_strategy_factory_new_tunneling_kerberos(allocator, &kerberos_config->kerberos_options); if (kerberos_factory == NULL) { goto on_error; } - struct aws_http_proxy_strategy_factory *factory_array[2] = { + ntlm_factory = aws_http_proxy_strategy_factory_new_tunneling_ntlm(allocator, &ntlm_config->ntlm_options); + if (ntlm_factory == NULL) { + goto on_error; + } + + struct aws_http_proxy_strategy_factory *factory_array[3] = { identity_factory, kerberos_factory, + ntlm_factory, }; struct aws_http_proxy_strategy_factory_tunneling_chain_options chain_config = { .factories = factory_array, - .factory_count = 2, + .factory_count = 3, }; adaptive_factory = aws_http_proxy_strategy_factory_new_tunneling_chain(allocator, &chain_config); @@ -1919,6 +1927,7 @@ struct aws_http_proxy_strategy_factory *aws_http_proxy_strategy_factory_new_tunn aws_http_proxy_strategy_factory_release(identity_factory); aws_http_proxy_strategy_factory_release(kerberos_factory); + aws_http_proxy_strategy_factory_release(ntlm_factory); aws_http_proxy_strategy_factory_release(adaptive_factory); return NULL;