rs_string IAMWinHttpClient::SendHttpRequestWithWIA()

in src/odbc/rsodbc/iam/http/IAMWinHttpClient.cpp [459:694]


rs_string IAMWinHttpClient::SendHttpRequestWithWIA(
    const rs_wstring& in_host,
    short in_port,
    bool in_verifySSL,
    const rs_wstring& in_proxyUsername,
    const rs_wstring& in_proxyPassword,
    const rs_wstring& in_loginToRp,
	int in_stsConnectionTimeout
    )
{
    // Reference: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383880(v=vs.85).aspx
    HINTERNET sessionHandle = NULL,
        connectHandle = NULL,
        requestHandle = NULL;

    DWORD dwProxyAuthScheme = 0;

    size_t httpRequestAttempt = 0;
    rs_string httpContentBody;
    bool m_usingProxy = !IAMUtils::isEmpty(in_proxyUsername);

    if (m_usingProxy)
    {
        sessionHandle = WinHttpOpen(
            USER_AGENT,
            WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
            WINHTTP_NO_PROXY_NAME,
            WINHTTP_NO_PROXY_BYPASS,
            0);
    }
    else
    {
        sessionHandle = WinHttpOpen(
            USER_AGENT,
            WINHTTP_ACCESS_TYPE_NO_PROXY,
            WINHTTP_NO_PROXY_NAME,
            WINHTTP_NO_PROXY_BYPASS,
            0);
    }

    if (!sessionHandle)
    {
        return httpContentBody;
    }

    if (in_verifySSL)
    {
        //disable insecure tls protocols, otherwise you might as well turn ssl verification off.
        DWORD flags = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
            WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 |
            WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2;

        WinHttpSetOption(sessionHandle, WINHTTP_OPTION_SECURE_PROTOCOLS, &flags, sizeof(flags));
    }

    // Set timeouts
    WinHttpSetTimeouts(sessionHandle, 
		in_stsConnectionTimeout,
		in_stsConnectionTimeout,
		in_stsConnectionTimeout,
		in_stsConnectionTimeout);

    connectHandle = WinHttpConnect(
        sessionHandle,
        in_host.c_str(), // GetAsPlatformWString()
        in_port,
        0);

    if (connectHandle)
    {
        LPCWSTR accept[] = { L"*/*", NULL };

        rs_wstring adfs_url = ADFS_RESOURCE + in_loginToRp;
        std::wstring adfs_url_wstring = adfs_url; // .GetAsPlatformWString()
        requestHandle = WinHttpOpenRequest(
            connectHandle,
            L"GET",
            const_cast<wchar_t*>(adfs_url_wstring.c_str()),
            NULL,
            WINHTTP_NO_REFERER,
            accept,
            WINHTTP_FLAG_REFRESH | WINHTTP_FLAG_SECURE);
    }

    if (requestHandle)
    {
        if (!in_verifySSL)
        {
            DWORD flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
            WinHttpSetOption(requestHandle, WINHTTP_OPTION_SECURITY_FLAGS, &flags, sizeof(flags));
        }
    }

    bool isDone = false;
    bool isUnauthorized = false;
    BOOL success = FALSE;

    while (++httpRequestAttempt < MAX_HTTP_ATTEMPT && requestHandle && !isDone)
    {
        if (0 != dwProxyAuthScheme && m_usingProxy)
        {
            success = WinHttpSetCredentials(
                requestHandle,
                WINHTTP_AUTH_TARGET_PROXY,
                dwProxyAuthScheme,
                in_proxyUsername.c_str(), // GetAsPlatformWString().
                in_proxyPassword.c_str(), // GetAsPlatformWString().
                NULL);
        }


        success = WinHttpSendRequest(
            requestHandle,
            WINHTTP_NO_ADDITIONAL_HEADERS,
            0,
            WINHTTP_NO_REQUEST_DATA,
            0,
            0,
            0);

        if (success)
        {
            success = WinHttpReceiveResponse(requestHandle, 0);
        }

		if (!success)
		{
			if (ERROR_WINHTTP_RESEND_REQUEST == GetLastError())
			{
				continue;
			}
			else if (ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED == GetLastError())
			{
				// [PGODBC-1351] If the server requests the certificate, but does not require it,
				// try indicate that it does not have a certificate
				WinHttpSetOption(
					requestHandle,
					WINHTTP_OPTION_CLIENT_CERT_CONTEXT,
					WINHTTP_NO_CLIENT_CERT_CONTEXT,
					0);

				continue;
			}
		}


        DWORD statusCode = 0;
        DWORD size = sizeof(statusCode);
        if (success)
        {
            success = WinHttpQueryHeaders(
                requestHandle,
                WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
                NULL,
                &statusCode,
                &size,
                NULL);
        }

        if (success)
        {
            httpContentBody = GetContent(requestHandle);

            HttpResponseCode responseCode = static_cast<HttpResponseCode>(statusCode);
            if (HttpResponseCode::UNAUTHORIZED == responseCode)
            {
                isUnauthorized = true;

                DWORD supportedSchemes;
                DWORD firstScheme;
                DWORD target;

                success = WinHttpQueryAuthSchemes(requestHandle, &supportedSchemes, &firstScheme, &target);
                if (success)
                {
                    DWORD scheme = 0;
					// [PGODBC-1463] Check and use WINHTTP_AUTH_SCHEME_NEGOTIATE if supported by the server
					if (supportedSchemes & WINHTTP_AUTH_SCHEME_NEGOTIATE)
					{
						scheme = WINHTTP_AUTH_SCHEME_NEGOTIATE;
					}
					else
                    if (supportedSchemes & WINHTTP_AUTH_SCHEME_NTLM)
                    {
                        scheme = WINHTTP_AUTH_SCHEME_NTLM;
                    }
                    else
                    {
                        isDone = true;
						continue;
                    }

					DWORD flags = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW;

					success = WinHttpSetOption(requestHandle, WINHTTP_OPTION_AUTOLOGON_POLICY, &flags, sizeof(flags))
						&& WinHttpSetCredentials(requestHandle, target, scheme, NULL, NULL, NULL);
                }
            }
            else
            {
                isUnauthorized = false;
                isDone = true;
            }
        }

        if (!success)
        {
            isDone = true;
        }
    }

    if (!success)
    {
        IAMTHROWGEN2("IAMHttpRequestError", in_host, IAMUtils::GetLastErrorText());
    }

    if (isUnauthorized)
    {
        IAMTHROW1(DIAG_INVALID_AUTH_SPEC, "IAMHttpUnauthorizedError", in_host);
    }

    if (requestHandle)
    {
        WinHttpCloseHandle(requestHandle);
    }
    if (connectHandle)
    {
        WinHttpCloseHandle(connectHandle);
    }
    if (sessionHandle)
    {
        WinHttpCloseHandle(sessionHandle);
    }

    return httpContentBody;
}