0

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++?

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83

0 Answers0