I'm trying to send a POST request to an HTTPS server (Jazz server) which expects a client certificate. In particular, this request concerns a login attempt to a Jazz server.
I'm using Qt 6.3.1 and my project is developed in C++.
I've tried many solutions but I couldn't get any response from the server: this is the result of QNetworkReply::error() function
Error: QNetworkReply::ProtocolInvalidOperationError - "Error transferring https://rtc.***.com/qm/authenticated/j_security_check - server replied: Bad Request"
One of my latest implementations is the following:
const static QString BASE_URL = "https://rtc.***.com/";
const static QString QM_AUTH_URL = "qm/authenticated/j_security_check";
void MainWindow::login(QString u, QString p) {
uname = u;
pwd = p;
netManager = new QNetworkAccessManager(this);
// Read the SSL certificate
QFile file("./myCert.cer");
if(!file.open(QIODevice::ReadOnly)) {
qDebug()<<"File opening error!";
return;
}
// Create a certificate object
const QSslCertificate certificate(file.readAll());
// Add this certificate to all SSL connections
QSslConfiguration conf = QSslConfiguration::defaultConfiguration();
conf.addCaCertificate(certificate);
QSslConfiguration::setDefaultConfiguration(conf);
sslsock = new QSslSocket(this);
if(!sslsock->isOpen() || !sslsock->isEncrypted() || !sslsock->isValid()) {
connect(sslsock, &QSslSocket::sslErrors, this, &MainWindow::printSslErrors);
connect(sslsock, &QSslSocket::encrypted, this, &MainWindow::socketConnected);
sslsock->setLocalCertificate(certificate);
sslsock->setSslConfiguration(conf);
sslsock->connectToHostEncrypted("rtc.***.com", 443);
} else {
socketConnected();
}
void MainWindow::printSslErrors(const QList<QSslError> &err) { //never called
for(int i=0; i<err.size(); i++) {
qDebug()<<"Error "<<(i+1)<<": "<<err[i].error()<<" - "<<err[i].errorString();
}
sslsock->ignoreSslErrors(err);
}
void MainWindow::socketConnected() {
qDebug()<<"SSL handshake completed!";
qDebug()<<"sslsock->isEncrypted(): "<<sslsock->isEncrypted();
qDebug()<<"sslsock->isOpen(): "<<sslsock->isOpen();
qDebug()<<"sslsock->isReadable(): "<<sslsock->isReadable();
qDebug()<<"sslsock->isValid(): "<<sslsock->isValid();
qDebug()<<"sslsock->isWritable(): "<<sslsock->isWritable();
qDebug()<<sslsock->peerCertificate() << " cert";
netManager->setStrictTransportSecurityEnabled(true);
QUrlQuery params;
params.addQueryItem("j_username", uname);
params.addQueryItem("j_password", pwd);
QNetworkRequest req(QUrl(BASE_URL+QM_AUTH_URL));
QSslConfiguration conf = QSslConfiguration::defaultConfiguration();
req.setSslConfiguration(conf);
req.setRawHeader("Accept", "application/xml");
req.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/x-www-form-urlencoded");
repl = netManager->post(req, params.query(QUrl::FullyEncoded).toUtf8());
connect(repl, &QNetworkReply::finished, this, &MainWindow::finishReading);
connect(repl, &QNetworkReply::sslErrors, this, &MainWindow::printSslErrors);
}
void MainWindow::readData() {
dataBuffer.clear();
dataBuffer.append(repl->readAll());
}
void MainWindow::finishReading() {
readData();
#if DEBUG
std::ofstream dataBuffFile, reqFile;
reqFile.open("request.txt", std::ios::out);
if(reqFile) {
reqFile<<"RawHeaderList size: "<<repl->request().rawHeaderList().size()<<std::endl;
for(int i=0; i<repl->request().rawHeaderList().size(); i++) {
reqFile<<repl->request().rawHeaderList().at(i).data()<<std::endl;
}
reqFile<<"Accept: "<<repl->request().rawHeader("Accept").data()<<std::endl;
reqFile<<"Content-Type: "<<repl->request().rawHeader("Content-Type").data()<<std::endl;
reqFile<<"Content-Length: "<<repl->request().rawHeader("Content-Length").data()<<std::endl;
reqFile<<"URL: "<<repl->request().url().toDisplayString().toStdString()<<std::endl;
reqFile.close();
} else {
qDebug()<<"Error in file opening!";
}
dataBuffFile.open("dataBuffer.txt", std::ios::out);
if(dataBuffFile) {
dataBuffFile<<dataBuffer.data();
dataBuffFile.close();
} else {
qDebug()<<"Error in file opening!";
}
#endif
if(repl->error() != QNetworkReply::NoError) {
qDebug()<<"Error: "<<repl->error()<<" - "<<repl->errorString();
warnMsg(this, "Error", QString("Request[Error] : %1").arg(repl->errorString()));
} else {
//TO_DO: CONVERT DATA
dataBuffer.clear();
}
}
SSL handshake is ok, I have no problems setting SSL configuration and using OpenSSL.
I simply can't login with the jazz server, which replies with "bad request". I've tried also to make an HTTPS request to "www.google.com", but the outcome is -more or less- the same.
What is the methodology to be able to make HTTPS requests with Qt/C++?