diff --git a/components/esp_http_client/Kconfig b/components/esp_http_client/Kconfig index c362d1e89..9cc8a6805 100644 --- a/components/esp_http_client/Kconfig +++ b/components/esp_http_client/Kconfig @@ -7,4 +7,11 @@ menu "ESP HTTP client" help This option will enable https protocol by linking mbedtls library and initializing SSL transport + config ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH + bool "Enable HTTP Basic Authentication" + default n + help + This option will enable HTTP Basic Authentication. It is disabled by default as Basic + auth uses unencrypted encoding, so it introduces a vulnerability when not using TLS + endmenu diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index b2a58f725..b96bcd87c 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -152,20 +152,6 @@ static const char *HTTP_METHOD_MAPPING[] = { "OPTIONS" }; -/** - * Enum for the HTTP status codes. - */ -enum HttpStatus_Code -{ - /* 3xx - Redirection */ - HttpStatus_MovedPermanently = 301, - HttpStatus_Found = 302, - - /* 4xx - Client Error */ - HttpStatus_Unauthorized = 401 -}; - - static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, int write_len); static esp_err_t esp_http_client_connect(esp_http_client_handle_t client); static esp_err_t esp_http_client_send_post_data(esp_http_client_handle_t client); @@ -617,13 +603,12 @@ esp_err_t esp_http_client_set_redirection(esp_http_client_handle_t client) if (client->location == NULL) { return ESP_ERR_INVALID_ARG; } + ESP_LOGD(TAG, "Redirect to %s", client->location); return esp_http_client_set_url(client, client->location); } static esp_err_t esp_http_check_response(esp_http_client_handle_t client) { - char *auth_header = NULL; - if (client->redirect_counter >= client->max_redirection_count || client->disable_auto_redirect) { ESP_LOGE(TAG, "Error, reach max_redirection_count count=%d", client->redirect_counter); return ESP_ERR_HTTP_MAX_REDIRECT; @@ -631,44 +616,12 @@ static esp_err_t esp_http_check_response(esp_http_client_handle_t client) switch (client->response->status_code) { case HttpStatus_MovedPermanently: case HttpStatus_Found: - ESP_LOGI(TAG, "Redirect to %s", client->location); - esp_http_client_set_url(client, client->location); + esp_http_client_set_redirection(client); client->redirect_counter ++; client->process_again = 1; break; case HttpStatus_Unauthorized: - auth_header = client->auth_header; - if (auth_header) { - http_utils_trim_whitespace(&auth_header); - ESP_LOGD(TAG, "UNAUTHORIZED: %s", auth_header); - client->redirect_counter ++; - if (http_utils_str_starts_with(auth_header, "Digest") == 0) { - ESP_LOGD(TAG, "type = Digest"); - client->connection_info.auth_type = HTTP_AUTH_TYPE_DIGEST; - } else if (http_utils_str_starts_with(auth_header, "Basic") == 0) { - ESP_LOGD(TAG, "type = Basic"); - client->connection_info.auth_type = HTTP_AUTH_TYPE_BASIC; - } else { - client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE; - ESP_LOGE(TAG, "This authentication method is not supported: %s", auth_header); - break; - } - - _clear_auth_data(client); - - client->auth_data->method = strdup(HTTP_METHOD_MAPPING[client->connection_info.method]); - - client->auth_data->nc = 1; - client->auth_data->realm = http_utils_get_string_between(auth_header, "realm=\"", "\""); - client->auth_data->algorithm = http_utils_get_string_between(auth_header, "algorithm=", ","); - client->auth_data->qop = http_utils_get_string_between(auth_header, "qop=\"", "\""); - client->auth_data->nonce = http_utils_get_string_between(auth_header, "nonce=\"", "\""); - client->auth_data->opaque = http_utils_get_string_between(auth_header, "opaque=\"", "\""); - client->process_again = 1; - } else { - client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE; - ESP_LOGW(TAG, "This request requires authentication, but does not provide header information for that"); - } + esp_http_client_add_auth(client); } return ESP_OK; } @@ -1250,3 +1203,48 @@ esp_http_client_transport_t esp_http_client_get_transport_type(esp_http_client_h return HTTP_TRANSPORT_UNKNOWN; } } + +void esp_http_client_add_auth(esp_http_client_handle_t client) +{ + if (client == NULL) { + return; + } + if (client->state != HTTP_STATE_RES_COMPLETE_HEADER) { + return; + } + + char *auth_header = client->auth_header; + if (auth_header) { + http_utils_trim_whitespace(&auth_header); + ESP_LOGD(TAG, "UNAUTHORIZED: %s", auth_header); + client->redirect_counter++; + if (http_utils_str_starts_with(auth_header, "Digest") == 0) { + ESP_LOGD(TAG, "type = Digest"); + client->connection_info.auth_type = HTTP_AUTH_TYPE_DIGEST; +#ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH + } else if (http_utils_str_starts_with(auth_header, "Basic") == 0) { + ESP_LOGD(TAG, "type = Basic"); + client->connection_info.auth_type = HTTP_AUTH_TYPE_BASIC; +#endif + } else { + client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE; + ESP_LOGE(TAG, "This authentication method is not supported: %s", auth_header); + return; + } + + _clear_auth_data(client); + + client->auth_data->method = strdup(HTTP_METHOD_MAPPING[client->connection_info.method]); + + client->auth_data->nc = 1; + client->auth_data->realm = http_utils_get_string_between(auth_header, "realm=\"", "\""); + client->auth_data->algorithm = http_utils_get_string_between(auth_header, "algorithm=", ","); + client->auth_data->qop = http_utils_get_string_between(auth_header, "qop=\"", "\""); + client->auth_data->nonce = http_utils_get_string_between(auth_header, "nonce=\"", "\""); + client->auth_data->opaque = http_utils_get_string_between(auth_header, "opaque=\"", "\""); + client->process_again = 1; + } else { + client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE; + ESP_LOGW(TAG, "This request requires authentication, but does not provide header information for that"); + } +} \ No newline at end of file diff --git a/components/esp_http_client/include/esp_http_client.h b/components/esp_http_client/include/esp_http_client.h index 102bf9e3e..8ece63607 100644 --- a/components/esp_http_client/include/esp_http_client.h +++ b/components/esp_http_client/include/esp_http_client.h @@ -120,6 +120,17 @@ typedef struct { bool use_global_ca_store; /*!< Use a global ca_store for all the connections in which this bool is set. */ } esp_http_client_config_t; +/** + * Enum for the HTTP status codes. + */ +typedef enum { + /* 3xx - Redirection */ + HttpStatus_MovedPermanently = 301, + HttpStatus_Found = 302, + + /* 4xx - Client Error */ + HttpStatus_Unauthorized = 401 +} HttpStatus_Code; #define ESP_ERR_HTTP_BASE (0x7000) /*!< Starting number of HTTP error codes */ #define ESP_ERR_HTTP_MAX_REDIRECT (ESP_ERR_HTTP_BASE + 1) /*!< The error exceeds the number of HTTP redirects */ @@ -413,12 +424,23 @@ esp_http_client_transport_t esp_http_client_get_transport_type(esp_http_client_h * * @param[in] client The esp_http_client handle * - * @return + * @return * - ESP_OK * - ESP_FAIL */ esp_err_t esp_http_client_set_redirection(esp_http_client_handle_t client); +/** + * @brief On receiving HTTP Status code 401, this API can be invoked to add authorization + * information. + * + * @note There is a possibility of receiving body message with redirection status codes, thus make sure + * to flush off body data after calling this API. + * + * @param[in] client The esp_http_client handle + */ +void esp_http_client_add_auth(esp_http_client_handle_t client); + #ifdef __cplusplus } #endif