Details
-
Bug
-
Resolution: Incomplete
-
P2: Important
-
None
-
6.1.1
-
None
Description
This issue is almost identical to QTBUG-44096 and I was told to create a new ticket. I apologize in advance if I'm not able to provide enough information for the analysis, I'm new to networking and was not able to decrypt the Wireshark traffic despite pointing it to a keylog.
I'm accessing a local server using GET-request and NTLM authetication from a Windows 10 machine that is logged in to the network using credentials that the server API accepts. This means that I can for example enter the GET-request in Edge without the need to provide credentials. I have also tested with Postman agent with NTLM authentication selected and credentials provided and that works as well. But when using QNetworkAccessManager the server denies access and I get an authenticationRequired error and the authenticationRequired signal is not emitted. I have not been able to find any method to force this signal to be emitted.
I have found that in some cases servers do not request authentication despite the need for it, but that is not the case here given by this header debug:
Reply: QList(std::pair("content-type","text/html"), std::pair("server","Microsoft-IIS/10.0"), std::pair("www-authenticate","Negotiate, NTLM"), std::pair("x-powered-by","ASP.NET"), std::pair("date","Thu, 15 Feb 2024 07:26:39 GMT"), std::pair("Content-Length","76266"))
This is one of the examples I've used to test:
#include "NTLMexample.h" NTLMexample::NTLMexample(QObject *parent) : QObject{parent} { manager = new QNetworkAccessManager(this); connect(manager, &QNetworkAccessManager::authenticationRequired, this, &NTLMexample::authenticationRequired); connect(manager, &QNetworkAccessManager::preSharedKeyAuthenticationRequired,this, &NTLMexample::preSharedKeyAuthenticationRequired); connect(manager, &QNetworkAccessManager::proxyAuthenticationRequired,this, &NTLMexample::proxyAuthenticationRequired); connect(manager, &QNetworkAccessManager::finished, this, &NTLMexample::requestFinished); connect(manager, &QNetworkAccessManager::encrypted, this, &NTLMexample::encrypted); connect(manager, &QNetworkAccessManager::sslErrors, this, &NTLMexample::sslErrors); }void NTLMexample::requestFinished(QNetworkReply *reply) { qInfo() << "Finished. "; if (reply->error() == QNetworkReply::NoError) { qInfo() << "Request successful!"; qInfo() << "Response:" << reply->readAll(); } else { qInfo() << "readAll: " << reply->readAll(); qInfo() << "Error:" << reply->errorString(); qInfo() << "Reply:" << reply->rawHeaderPairs(); } } void NTLMexample::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors) { Q_UNUSED(reply); Q_UNUSED(errors); qInfo() << "sslErrors"; }void NTLMexample::encrypted(QNetworkReply *reply) { //Q_UNUSED(reply); qInfo() << "encrypted"; //if(reply) qInfo() << "Reply: " << reply->readBufferSize(); }void NTLMexample::preSharedKeyAuthenticationRequired(QNetworkReply *reply, QSslPreSharedKeyAuthenticator *authenticator) { qInfo() << "preSharedKeyAuthenticationRequired"; }void NTLMexample::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator) { qInfo() << "proxyAuthenticationRequired"; } void NTLMexample::authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator) { // NTLM authentication credentials qInfo() << "authenticationRequired signal emitted!"; }void NTLMexample::readyRead() { qInfo() << "ReadyRead"; QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender()); if(reply) qInfo() << reply->readAll(); } void NTLMexample::makeRequest(QString URL) { // Set up the request QNetworkRequest request = QNetworkRequest(QUrl(URL)); QNetworkReply *reply = manager->get(request); connect(reply, &QNetworkReply::readyRead, this, &NTLMexample::readyRead); }
Using WinINet with this code works fine:
QString networkTest::getRequest(QString url){ HINTERNET hInternet = InternetOpen(L"MMSC-EOL", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); if (hInternet) { HINTERNET hConnect = InternetOpenUrl(hInternet, reinterpret_cast<LPCWSTR>(url.utf16()), NULL, 0, INTERNET_FLAG_RELOAD, 0); if (hConnect) { char buffer[32000]; DWORD bytesRead; while (InternetReadFile(hConnect, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) { // Process the received data QString responseData = QString::fromUtf8(buffer, bytesRead); documentBuffer = responseData; //qDebug() << responseData; return responseData; } InternetCloseHandle(hConnect); } else { return "!hConnect"; } InternetCloseHandle(hInternet); } else { return "!hInternet"; } }
One of our server API's responds with a HTML page including the text "You do not have permission to view this directory or page using the credentials that you supplied" indicating to me that QNetworkAuthenticator thinks that it has found and provided credentials. But what's puzzling to me is that according to the documentation I've found if the credentials are rejected, the authenticationRequired signal should be emitted, which it is not. I've tried with the clearAccessCache() but that does not help. I have now moved to using WinINet for now since I have been unable to find a workaround using QNetworkAccessManager.