esp_http_client: Add API for adding authorization info

There was existing support for adding authorization info in esp_http_client
but it was functional only while using `esp_http_client_perform` API. This commit just moves
existing authorization addition logic into publicly exposed API.
This commit is contained in:
Jitin George 2019-04-03 19:43:13 +05:30
parent 6890326504
commit 86e1fc564e
3 changed files with 78 additions and 51 deletions

View file

@ -7,4 +7,11 @@ menu "ESP HTTP client"
help help
This option will enable https protocol by linking mbedtls library and initializing SSL transport 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 endmenu

View file

@ -152,20 +152,6 @@ static const char *HTTP_METHOD_MAPPING[] = {
"OPTIONS" "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_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_connect(esp_http_client_handle_t client);
static esp_err_t esp_http_client_send_post_data(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) { if (client->location == NULL) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
ESP_LOGD(TAG, "Redirect to %s", client->location);
return esp_http_client_set_url(client, 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) 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) { 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); ESP_LOGE(TAG, "Error, reach max_redirection_count count=%d", client->redirect_counter);
return ESP_ERR_HTTP_MAX_REDIRECT; 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) { switch (client->response->status_code) {
case HttpStatus_MovedPermanently: case HttpStatus_MovedPermanently:
case HttpStatus_Found: case HttpStatus_Found:
ESP_LOGI(TAG, "Redirect to %s", client->location); esp_http_client_set_redirection(client);
esp_http_client_set_url(client, client->location);
client->redirect_counter ++; client->redirect_counter ++;
client->process_again = 1; client->process_again = 1;
break; break;
case HttpStatus_Unauthorized: case HttpStatus_Unauthorized:
auth_header = client->auth_header; esp_http_client_add_auth(client);
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");
}
} }
return ESP_OK; 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; 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");
}
}

View file

@ -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. */ 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; } 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_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 */ #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 * @param[in] client The esp_http_client handle
* *
* @return * @return
* - ESP_OK * - ESP_OK
* - ESP_FAIL * - ESP_FAIL
*/ */
esp_err_t esp_http_client_set_redirection(esp_http_client_handle_t client); 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 #ifdef __cplusplus
} }
#endif #endif