Page 1 of 1

Azure Blob Storage data fetch fails due to HTTPS Authentification MBed TLS

Posted: Wed Sep 13, 2023 9:55 am
by adrian-fratila
Hi everybody,

I try to fetch a binary file from an Azure Blob Storage, using esp_http_client, IDF v5.0.1. The fetch works in Postman or in a browser, which means the url path and the SAS token are correct.

The connection to the Azure server is established, but I get the error message: "Server failed to authenticate the request":
  1. I(15113) APP : Opened successfully the HTTP connection
  2. I(15273) HTTP_CLIENT : Body received in fetch header state, 0x3ffbb6da, 166
  3. I(15293) APP : Read data : ���< ? xml version = "1.0" encoding = "utf-8" ? >
  4. <Error><Code>AuthenticationFailed< / Code><Message>Server failed to authenticate the request.Make sure the value of Authorization header is formed correctly including the signature.
  5. RequestId : 01100f54 - 901e-0045 - 18cc - e3e32c000000

I have tried various combinations for the connection setting: the url with and without the SAS at the end, and setting the SAS in the http header "Authorization" field.

I suspect the problem comes from the way the connection data is set / arranged in the esp http client. This is the code that I have tested:

  1. esp_http_client_config_t config = {
  2.   //.url = "https://name.blob.core.windows.net/test/v0.0.2-fw.bin&sp=r&...0MtMgNI%3D",
  3.   .url = "https://name.blob.core.windows.net/test/v0.0.2-fw.bin",
  4.   .transport_type = HTTP_TRANSPORT_OVER_SSL,
  5.   .event_handler = http_event_handler,
  6.   .cert_pem = rootCaPem,
  7.   .cert_len = rootCaPemLen,
  8.   .timeout_ms = RECEIVE_TIMEOUT,
  9.   .keep_alive_enable = true,
  10.   .skip_cert_common_name_check = true,
  11.   //.use_global_ca_store = true
  12. };
  13.  
  14. esp_http_client_handle_t client = esp_http_client_init(&config);
  15.  
  16. if (client == NULL) {
  17.   ESP_LOGE(TAG, "Failed to initialise HTTP connection");
  18.   return;
  19. }
  20.  
  21. esp_http_client_set_header(client, "Authorization", "SharedAccessSignature sp=r&...0MtMgNI%3D");
  22. //esp_http_client_set_header(client, "ContentType", "application/octet-stream");
  23. esp_http_client_set_header(client, "Accept", "*/*"); // copied from Postman
  24. esp_http_client_set_header(client, "Accept-Encoding", "gzip, deflate, br"); // copied from Postman
  25. esp_http_client_set_header(client, "Host", "name.blob.core.windows.net");
  26. esp_http_client_set_method(client, HTTP_METHOD_GET);
  27.  
  28. err = esp_http_client_open(client, 0);
  29.  
  30. if (err != ESP_OK) {
  31.   ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
  32.   esp_http_client_cleanup(client);
  33.   return;
  34. }
  35. else {
  36.   ESP_LOGI(TAG, "Opened successfully the HTTP connection");
  37. }
  38.  
  39. esp_http_client_fetch_headers(client);

Any idea on why the Azure authorization fails?

Does anybody have an ESP http client example, for fetching data from an Azure Blob Storage?

I would really appreciate any help!

Thank you!

Re: Azure Blob Storage data fetch fails due to HTTPS Authentification MBed TLS

Posted: Wed Sep 13, 2023 10:32 am
by ESP_harshal
Hello @adrian-fratila,

I think the http_request needs authentication data which is not included in the config. If you are trying to access the domain "https://name.blob.core.windows.net/test/v0.0.2-fw.bin" without any auth data then this should have been accessible using a browser publicly by me too. But when I try to access this domain, I get the same error message in the browser as the reported error "Server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature."
I feel all you need is to add the authentication configs. You can refer to the basic auth example of esp_http_client: https://github.com/espressif/esp-idf/bl ... #L329-L355

Re: Azure Blob Storage data fetch fails due to HTTPS Authentification MBed TLS

Posted: Wed Sep 13, 2023 8:43 pm
by MicroController
AFAICT, the SAS token goes into the URI of the request. And apparently, a "date" or "x-ms-date" header is mandatory for all authenticated accesses; see e.g. examples here.

Edit:

Code: Select all

//.url = "https://name.blob.core.windows.net/test/v0.0.2-fw.bin&sp=r&...0MtMgNI%3D"
looks almost right. Just the resource-path 'test/v0.0.2-fw.bin' needs to be separated from the query parameters by a ? instead of an &!
Try

Code: Select all

.url = "https://name.blob.core.windows.net/test/v0.0.2-fw.bin?sp=r&...0MtMgNI%3D"

Re: Azure Blob Storage data fetch fails due to HTTPS Authentification MBed TLS

Posted: Thu Sep 14, 2023 8:27 am
by adrian-fratila
Hi guys,

Thank you for your input. I should have stated in my previous post that the URL and SAS were dummy. For completeness I have created a new Azure blob and uploaded two .txt files (3kB & 12KB).

The strange thing is that the small one (test.txt) is somehow loaded, even there is an error from the HTTP_CLIENT. In this error the beginning of the text file appears in the Error log:

I (12172) OTA: Opened successfully the HTTP connection
I (12252) HTTP_CLIENT: Body received in fetch header state, 0x3ffbad7a, 486
E (12252) HTTP_CLIENT: This is a test file.
This example demonstrates common operations the OTA tool:
- reading, writing and erasing OTA partitions,
- switching boot partitions, and
- switching to factory partition.

Users taking a look at this example should focus on the contents of the Python script [otatool_example.py](otatool_example.py) or shell script [otatool_example.sh](otatool_example.sh). The scripts contain
programmatic invocation of the tool's functions via the Python API and command-l�?!

I (12302) OTA: Fetching the Image file of length 2840 bytes
I (12302) OTA: Incremented length 1024
I (12312) OTA: Incremented length 2048
I (12312) OTA: Incremented length 2840
I (12322) OTA: Connection closed
I (12322) OTA: Total received data length: 2840
I (12332) HTTP_CLIENT: HTTP_EVENT_DISCONNECTED


The second file: test_long.txt doesn't load at all, and throws this error:

I (14202) OTA: Opened successfully the HTTP connection
E (14282) esp-tls-mbedtls: read error :-0x7100:
E (14282) transport_base: esp_tls_conn_read error, errno=Connection already in progress
E (14292) OTA: HTTP client fetch headers failed

I (14292) HTTP_CLIENT: HTTP_EVENT_DISCONNECTED


The same error appears for any large size file. I have inlined the code below, which contains valid URLs and SAS tokens with the expiration at the end of October, so plenty of time left for testing.
  1.       esp_http_client_config_t config = {
  2.             .url = "https://dumstorage.blob.core.windows.net/test/test.txt?sp=r&st=2023-09-13T16:10:57Z&se=2023-10-31T01:10:57Z&spr=https&sv=2022-11-02&sr=b&sig=5WjKp2Mp7uJWVJNLr2sdYt17YWuhYpVoJSwhmmBBgAo%3D",
  3.             //.url = "https://dumstorage.blob.core.windows.net/test/test_long.txt?sp=r&st=2023-09-13T14:51:07Z&se=2023-10-30T23:51:07Z&spr=https&sv=2022-11-02&sr=b&sig=lK88A5l41ysl%2BxEgwhvOsYZaia3CdJzFchDHnLlGaNE%3D",
  4.                 .transport_type = HTTP_TRANSPORT_OVER_SSL,
  5.             .event_handler = http_event_handler,
  6.                 .cert_pem = rootCaPem,
  7.             .cert_len = rootCaPemLen,
  8.                 .timeout_ms = 5000,
  9.                 //.auth_type = HTTP_AUTH_TYPE_BASIC,
  10.                 .keep_alive_enable = true,
  11.                 .skip_cert_common_name_check = true,
  12.             //.use_global_ca_store = true
  13.         };
  14.  
  15.         esp_http_client_handle_t client = esp_http_client_init(&config);
  16.         if (client == NULL) {
  17.            ESP_LOGE(TAG, "Failed to initialise HTTP connection");
  18.            return;
  19.         }
  20.  
  21.         //esp_http_client_set_header(client, "Authorization", "");
  22.         //esp_http_client_set_header(client, "ContentType", "application/octet-stream");
  23.         //esp_http_client_set_header(client, "Accept", "*/*");
  24.         esp_http_client_set_method(client, HTTP_METHOD_GET);
  25.  
  26.  
  27.         err = esp_http_client_open(client, 0);
  28.         if (err != ESP_OK) {
  29.           ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
  30.           esp_http_client_cleanup(client);
  31.           return;
  32.         }else{
  33.             ESP_LOGI(TAG, "Opened successfully the HTTP connection");
  34.         }
  35.  
  36.         content_length = esp_http_client_fetch_headers(client);
  37.  
  38.         if (content_length <0){
  39.             ESP_LOGE(TAG, "HTTP client fetch headers failed");
  40.             esp_http_client_cleanup(client);
  41.             return;
  42.         }else{
  43.             ESP_LOGI(TAG, "Fetching the Image file of length %d bytes", content_length);
  44.         }
  45.  
  46.         int binary_file_length = 0;
  47.  
  48.         while (1) {
  49.             int data_read = esp_http_client_read_response(client, ota_write_data, BUFFSIZE);
  50.  
  51.             if (data_read < 0) {
  52.                 ESP_LOGE(TAG, "Error: SSL data read error");
  53.                 esp_http_client_cleanup(client);
  54.                 return;
  55.             } else if (data_read > 0) {
  56.                   //ESP_LOGI(TAG, "Read data: %s", ota_write_data);
  57.                 binary_file_length += data_read;
  58.                 ESP_LOGI(TAG, "Incremented length %d", binary_file_length);
  59.             } else if (data_read == 0) {
  60.                 if (errno == ECONNRESET || errno == ENOTCONN) {
  61.                     ESP_LOGE(TAG, "Connection closed, errno = %d", errno);
  62.                     break;
  63.                 }
  64.                 if (esp_http_client_is_complete_data_received(client) == true) {
  65.                     ESP_LOGI(TAG, "Connection closed");
  66.                     break;
  67.                 }
  68.             }
  69.         }
  70.         ESP_LOGI(TAG, "Total received data length: %d", binary_file_length);
  71.         if (esp_http_client_is_complete_data_received(client) != true) {
  72.             ESP_LOGE(TAG, "Error in receiving complete file");
  73.             http_cleanup(client);
  74.             return;
  75.         }
  76.  
  77.         esp_http_client_cleanup(client);
Following @ESP_harshal suggestion, I have also set .auth_type = HTTP_AUTH_TYPE_BASIC in config, but that doesn't change the outcome.

I believe there must be some ESP HTTP CLIENT config settings which are missing, in order to get the data from an Azure blob storage. The links in the code above work in a browser or Postman.

Any help will be highly appreciated!

Re: Azure Blob Storage data fetch fails due to HTTPS Authentification MBed TLS

Posted: Mon Jul 08, 2024 7:06 am
by crodriguez
Hello Adrian,

Did you manage to solve it? I am facing the same issue...

Thanks in advance