Azure / azure-storage-cpp

Microsoft Azure Storage Client Library for C++
http://azure.github.io/azure-storage-cpp
Apache License 2.0
131 stars 147 forks source link

Unable to connect through HTTPS proxy #330

Open neilkenny opened 4 years ago

neilkenny commented 4 years ago

We are having issues connecting to azure blob storage through a HTTPS proxy.

We have verified that the proxy details are correct, and have written a similar test app to the below one using the AWS S3 SDK that connects through the proxy without any issues.

If I remove the operationContext.set_proxy(proxy); line from the below code it connects.

The error we get is: WinHttpReceiveResponse: 12030: The connection with the server was terminated abnormally

It seems to us that there is a problem with the SDK, here is code from the test app we have written:

    std::wstring wAzureAccountName = L"<storageaccount>";
    std::wstring wAzureAccountKey = L"<accountkey>";
    std::wstring wProxyType = utility::conversions::to_string_t("https");
    std::wstring wProxyHost = utility::conversions::to_string_t("10.225.70.163");
    std::wstring wProxyPort = utility::conversions::to_string_t("8443");
    std::wstring wProxyUsername = utility::conversions::to_string_t("<username>");
    std::wstring wProxyPassword = utility::conversions::to_string_t("<password>");
    std::string strErrMsg;
    bool connectionSucceed;

    azure::storage::cloud_storage_account storageAccount;
    azure::storage::cloud_blob_client blobClient;
    azure::storage::operation_context operationContext;
    azure::storage::blob_request_options options;

    azure::storage::storage_credentials storageCredentials
        = azure::storage::storage_credentials(wAzureAccountName, wAzureAccountKey);

    storageAccount = azure::storage::cloud_storage_account(storageCredentials, true);

    if (storageAccount.is_initialized()) {
        blobClient = storageAccount.create_cloud_blob_client();
        operationContext = azure::storage::operation_context();
        options = azure::storage::blob_request_options();
    }

    std::wstring address;
    address.append(wProxyType).append(L"://").append(wProxyHost).append(L":").append(wProxyPort);

    web::web_proxy proxy(address);

    web::credentials credentials(wProxyUsername, wProxyPassword);

    proxy.set_credentials(credentials);

    operationContext.set_proxy(proxy);

    try {
        auto containerIt = blobClient.list_containers(
            std::wstring(), azure::storage::container_listing_details::none, 0, options, operationContext);

        if (containerIt->is_valid()) {
            connectionSucceed = true;
        }
    }
    catch (azure::storage::storage_exception & storageException) {
        std::string code = std::to_string(storageException.result().http_status_code());
        std::string message(storageException.what());

        if (code.empty()) {
            message.clear();
            message.append("Invalid credentials or network issue");
        }

        strErrMsg.append("Failed to retrieve container for test: ").append(code).append(" : ").append(message);
    }
    catch (web::http::http_exception & httpException) {
        strErrMsg.append("Failed to retrieve container for test: ").append(httpException.error_code().message());
    }
    catch (web::uri_exception & uriException) {
        strErrMsg.append("Failed to create Azure Blob host error: ").append(uriException.what());
    }
    catch (std::exception & e) {
        strErrMsg.append("Failed to retrieve container for test: ").append(e.what());
    }

Following more in-depth investigation we noted the following:

Jinming-Hu commented 4 years ago

Hi @neilkenny

  • If using an HTTPS Only proxy it will fail

Does it mean if you're using HTTP proxy, it can connect? If so, looks like it's a cert issue.

Can you share which proxy server you're using? So that I can try to reproduce this issue.

neilkenny commented 4 years ago

@JinmingHu-MSFT the proxy we used is behind a firewall, we don't have time right now but will try to set one up in Azure in the coming days.

We don't think it's a cert issue since it never seems to even attempt the SSL negotiation and we have a test app working with the S3 SDK on the same machine using the same cert

Here is the wireshark trace for Azure: image

And the same for the S3 SDK we tested: image

Jinming-Hu commented 4 years ago

@neilkenny I can reproduce your result now.

I looked through source code of cpprestsdk, which we use as HTTP client. On Windows, the proxy settings are directly passed to underlying WinHTTP, which seems does not support HTTPS proxy. But I didn't find any documents stating this. On Linux, cpprestsdk uses boost::asio to handle connections, and evidently cpprestsdk doesn't initiate SSL handshake after connection is established, so it only supports HTTP proxy.

So in conclusion, we don't support HTTPS proxy yet because cpprestsdk doesn't support it.

Can you tell us why HTTP proxy is not acceptable for your scenario so that we can properly prioritize this HTTPS proxy feature?

neilkenny commented 4 years ago

@JinmingHu-MSFT The product I work on (MOVEit Automation) allows users to configure and automate file transfers between many different host types. We have recently added Azure Blob as a host type, and as part of the host settings we allow the user to configure a proxy. Because of this issue the connection options for our users connecting to an Azure Blob host are more restricted compared to other hosts

Jinming-Hu commented 4 years ago

@neilkenny Hi, we have another C++ SDK cpplite which has the same functionality as this SDK but better performance and with less dependencies. It uses libcurl as backend HTTP client. I believe libcurl supports HTTPS proxy, and it's very easy for us to add an interface in cpplite sdk for users to change proxy settings.

If cpplite meets your needs, I can add this feature to cpplite very soon because it's very easy. But in this cpp sdk, this feature is not easy. I need to discuss with cpprest team and maybe WinHTTP team. This will take some time and I cannot guarantee results.

neilkenny commented 4 years ago

@JinmingHu-MSFT We will have to ship with this as a known issue as it is too late for us to replace the sdk framework at this stage, however we may look to replace the current sdk with cpplite in a later release if this issue is fixed in that framework.

Jinming-Hu commented 4 years ago

@neilkenny Okay, then you may want to create a feature request in cpplite repo, so that I can add it to backlog.

Jinming-Hu commented 4 years ago

@neilkenny btw, your product is Windows only right? Since I noticed the code you posted only runs on Windows.

neilkenny commented 4 years ago

@JinmingHu-MSFT Correct, MOVEit Automation needs to be installed on Windows Server. I will create a feature request