QNetworkRequest always returning 401 over https
-
I'm doing an https get call using a QNetworkRequest. The connection uses basic authentication. I had gotten this working with Qt 5.3.0, however, we were having other issues so I updated to 5.3.1, fixing the other issues but breaking my connection.
Now, when making a connection I always get a 401 reply and this message "Host requires authentication."
@bool IIntegratorConnection::doRequest(
QString const &username, QString const &password,
QString const &url, QString const &api) {QNetworkRequest request; QString address(url); if (!url.endsWith("/")) address.append("/"); request.setUrl(QUrl(address.append(api))); request.setRawHeader("Authorization", "Basic " + QByteArray(QString("%1:%2").arg( username).arg(password)).toUtf8().toBase64()); QNetworkReply *reply = _manager.get(request);//_manager is a member QNetworkAccessManager QObject::connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotProgress(qint64,qint64))); return true;
}
void IIntegratorConnection::receiveReply(QNetworkReply *reply) {
int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); //v is 401 here
if (reply->error() != QNetworkReply::NoError) {
qDebug() << "Error: " << reply->errorString() << " For URL : " << reply->url().toString(); @I've played around with setting the password to base64 or not. It worked as base64 in 5.3.0. Anything I'm doing obviously wrong here?
-
Hi,
Did you just switch Qt version ? Compile them yourself ?
-
yes I compiled them myself. I was able to figure out a workaround by catching the authenticationRequired signal on the manager.
@QObject::connect(&_manager, &QNetworkAccessManager::authenticationRequired, this, &MyClass::fixCredentials);@
However, to do this I have to store the username/password in the object which I'd rather not do.
I compiled on Windows with vs 2012.
-
Did you compile both 5.3.1 and 5.3.0 ?
If so, can you create a minimal compilable example that shows the behavior difference ?
-
I made a simple example to test this and of course now it's not working in 5.3.0 anymore either!
header (gets mocced)
@#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QAuthenticator>
#include <QObject>struct Connection : public QObject {
Q_OBJECT
public:
QNetworkAccessManager manager;
QString _username, _password;
Connection();
signals:
void finished();
private slots:
void receiveReply(QNetworkReply *);
void fixCredentials(QNetworkReply *reply, QAuthenticator *authenticator);};@
implementation
@#include "Connection.h"
#include "Connection.moc"
#include <QApplication>
#include <QJsonDocument>Connection::Connection() {
QObject::connect(&manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(receiveReply(QNetworkReply*)));
// QObject::connect(&manager, &QNetworkAccessManager::authenticationRequired, this, &Connection::fixCredentials);
_username = "username";
_password = "pass";
QString address = "url";
QString api = "v1/projects/";
QNetworkRequest request;
if (!address.endsWith("/"))
address.append("/");
request.setUrl(QUrl(address.append(api)));request.setRawHeader("Authorization", "Basic " + QByteArray(QString("%1:%2").arg( _username).arg(_password).toUtf8().toBase64())); QNetworkReply *reply = manager.get(request);
}
void Connection::receiveReply(QNetworkReply *reply) {
reply->deleteLater();
int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (reply->error() != QNetworkReply::NoError) {
qDebug() << "Error: " << reply->errorString() << " For URL : " << reply->url().toString();
} else {
if (v >= 400 || v < 200) {
qDebug() << "Error" << reply->error();
emit finished();
} else if (v >= 200 && v < 300) {
//handle data
QString text;
text = reply->readAll();
QJsonDocument jsonResponse = QJsonDocument::fromJson(text.toUtf8());
qDebug() << jsonResponse;
emit finished();
} else {
// Get the redirection url
QUrl newUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
// Because the redirection url can be relative,
// we have to use the previous one to resolve it
newUrl = reply->url().resolved(newUrl);QNetworkAccessManager *manager = reply->manager(); QNetworkRequest redirection(newUrl); QNetworkReply *newReply = manager->get(redirection); return; // to keep the manager for the next request } }
}
void Connection::fixCredentials(QNetworkReply *reply, QAuthenticator *authenticator) {
authenticator->setUser(_username);
authenticator->setPassword(_password);
}int main(int argc, char **argv) {
QApplication app(argc, argv);
Connection connect;
QObject::connect(&connect, &Connection::finished, &app, &QCoreApplication::quit);return app.exec();
}@
It runs ok if i make use of my fixCredentials method.
We're building Qt by following the instructions "here":https://github.com/MiraGeoscience/developmentCycle/wiki/Build-Qt (based on the instructions in the qt wiki for building from git).
-
Also, check whether the server changed it's authentication scheme
-
You can verify this with e.g. chrome's Postman application :-)