Skip to content

Commit

Permalink
Merge pull request #6785 from nextcloud/bugfix/qt5/certificates
Browse files Browse the repository at this point in the history
Fix "The host name did not match any of the valid hosts for this certificate" notification even when the certificate was valid
  • Loading branch information
mgallien authored Jul 1, 2024
2 parents d8d7b03 + f1e3901 commit fdd5356
Show file tree
Hide file tree
Showing 4 changed files with 14 additions and 79 deletions.
1 change: 0 additions & 1 deletion src/gui/owncloudsetupwizard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,6 @@ void OwncloudSetupWizard::slotConnectToOCUrl(const QString &url)
void OwncloudSetupWizard::testOwnCloudConnect()
{
AccountPtr account = _ocWizard->account();

auto *job = new PropfindJob(account, "/", this);
job->setIgnoreCredentialFailure(true);
// There is custom redirect handling in the error handler,
Expand Down
75 changes: 11 additions & 64 deletions src/libsync/abstractnetworkjob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ QNetworkReply *AbstractNetworkJob::addTimer(QNetworkReply *reply)
QNetworkReply *AbstractNetworkJob::sendRequest(const QByteArray &verb, const QUrl &url,
QNetworkRequest req, QIODevice *requestBody)
{
req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
auto reply = _account->sendRawRequest(verb, url, req, requestBody);
_requestBody = requestBody;
if (_requestBody) {
Expand All @@ -139,6 +140,7 @@ QNetworkReply *AbstractNetworkJob::sendRequest(const QByteArray &verb, const QUr
QNetworkReply *AbstractNetworkJob::sendRequest(const QByteArray &verb, const QUrl &url,
QNetworkRequest req, const QByteArray &requestBody)
{
req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
auto reply = _account->sendRawRequest(verb, url, req, requestBody);
_requestBody = nullptr;
adoptRequest(reply);
Expand All @@ -150,6 +152,7 @@ QNetworkReply *AbstractNetworkJob::sendRequest(const QByteArray &verb,
QNetworkRequest req,
QHttpMultiPart *requestBody)
{
req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
auto reply = _account->sendRawRequest(verb, url, req, requestBody);
_requestBody = nullptr;
adoptRequest(reply);
Expand Down Expand Up @@ -181,10 +184,11 @@ void AbstractNetworkJob::slotFinished()
if (_reply->error() == QNetworkReply::SslHandshakeFailedError) {
qCWarning(lcNetworkJob) << "SslHandshakeFailedError: " << errorString() << " : can be caused by a webserver wanting SSL client certificates";
}
// Qt doesn't yet transparently resend HTTP2 requests, do so here

// TODO: this could be removed with Qt6
const auto maxHttp2Resends = 3;
QByteArray verb = HttpLogger::requestVerb(*reply());
if (_reply->error() == QNetworkReply::ContentReSendError
if (const auto verb = HttpLogger::requestVerb(*reply());
_reply->error() == QNetworkReply::ContentReSendError
&& _reply->attribute(QNetworkRequest::Http2WasUsedAttribute).toBool()) {

if ((_requestBody && !_requestBody->isSequential()) || verb.isEmpty()) {
Expand Down Expand Up @@ -213,9 +217,9 @@ void AbstractNetworkJob::slotFinished()
}

if (_reply->error() != QNetworkReply::NoError) {

if (_account->credentials()->retryIfNeeded(this))
if (_account->credentials()->retryIfNeeded(this)) {
return;
}

if (!_ignoreCredentialFailure || _reply->error() != QNetworkReply::AuthenticationRequiredError) {
qCWarning(lcNetworkJob) << _reply->error() << errorString()
Expand All @@ -230,68 +234,11 @@ void AbstractNetworkJob::slotFinished()
// get the Date timestamp from reply
_responseTimestamp = _reply->rawHeader("Date");

QUrl requestedUrl = reply()->request().url();
QUrl redirectUrl = reply()->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
if (_followRedirects && !redirectUrl.isEmpty()) {
// Redirects may be relative
if (redirectUrl.isRelative())
redirectUrl = requestedUrl.resolved(redirectUrl);

// For POST requests where the target url has query arguments, Qt automatically
// moves these arguments to the body if no explicit body is specified.
// This can cause problems with redirected requests, because the redirect url
// will no longer contain these query arguments.
if (reply()->operation() == QNetworkAccessManager::PostOperation
&& requestedUrl.hasQuery()
&& !redirectUrl.hasQuery()
&& !_requestBody) {
qCWarning(lcNetworkJob) << "Redirecting a POST request with an implicit body loses that body";
}

// ### some of the qWarnings here should be exported via displayErrors() so they
// ### can be presented to the user if the job executor has a GUI
if (requestedUrl.scheme() == QLatin1String("https") && redirectUrl.scheme() == QLatin1String("http")) {
qCWarning(lcNetworkJob) << this << "HTTPS->HTTP downgrade detected!";
} else if (requestedUrl == redirectUrl || _redirectCount + 1 >= maxRedirects()) {
qCWarning(lcNetworkJob) << this << "Redirect loop detected!";
} else if (_requestBody && _requestBody->isSequential()) {
qCWarning(lcNetworkJob) << this << "cannot redirect request with sequential body";
} else if (verb.isEmpty()) {
qCWarning(lcNetworkJob) << this << "cannot redirect request: could not detect original verb";
} else {
emit redirected(_reply, redirectUrl, _redirectCount);

// The signal emission may have changed this value
if (_followRedirects) {
_redirectCount++;

// Create the redirected request and send it
qCInfo(lcNetworkJob) << "Redirecting" << verb << requestedUrl << redirectUrl;
resetTimeout();
if (_requestBody) {
if(!_requestBody->isOpen()) {
// Avoid the QIODevice::seek (QBuffer): The device is not open warning message
_requestBody->open(QIODevice::ReadOnly);
}
_requestBody->seek(0);
}
sendRequest(
verb,
redirectUrl,
reply()->request(),
_requestBody);
return;
}
}
}

AbstractCredentials *creds = _account->credentials();
if (!creds->stillValid(_reply) && !_ignoreCredentialFailure) {
if (auto *creds = _account->credentials();!creds->stillValid(_reply) && !_ignoreCredentialFailure) {
_account->handleInvalidCredentials();
}

bool discard = finished();
if (discard) {
if (finished()) {
qCDebug(lcNetworkJob) << "Network job" << metaObject()->className() << "finished for" << path();
deleteLater();
}
Expand Down
5 changes: 0 additions & 5 deletions src/libsync/account.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,11 +483,6 @@ QSslConfiguration Account::getOrCreateSslConfig()
// "An internal error number 1060 happened. SSL handshake failed, client certificate was requested: SSL error: sslv3 alert handshake failure"
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();

// Try hard to reuse session for different requests
sslConfig.setSslOption(QSsl::SslOptionDisableSessionTickets, false);
sslConfig.setSslOption(QSsl::SslOptionDisableSessionSharing, false);
sslConfig.setSslOption(QSsl::SslOptionDisableSessionPersistence, false);

sslConfig.setOcspStaplingEnabled(Theme::instance()->enableStaplingOCSP());

return sslConfig;
Expand Down
12 changes: 3 additions & 9 deletions src/libsync/networkjobs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -522,12 +522,6 @@ void CheckServerJob::metaDataChangedSlot()

bool CheckServerJob::finished()
{
if (reply()->request().url().scheme() == QLatin1String("https")
&& reply()->sslConfiguration().sessionTicket().isEmpty()
&& reply()->error() == QNetworkReply::NoError) {
qCWarning(lcCheckServerJob) << "No SSL session identifier / session ticket is used, this might impact sync performance negatively.";
}

mergeSslConfigurationForSslButton(reply()->sslConfiguration(), account());

// The server installs to /owncloud. Let's try that if the file wasn't found
Expand All @@ -540,14 +534,14 @@ bool CheckServerJob::finished()
return false;
}

QByteArray body = reply()->peek(4 * 1024);
int httpStatus = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
const auto body = reply()->peek(4 * 1024);
const auto httpStatus = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (body.isEmpty() || httpStatus != 200) {
qCWarning(lcCheckServerJob) << "error: status.php replied " << httpStatus << body;
emit instanceNotFound(reply());
} else {
QJsonParseError error{};
auto status = QJsonDocument::fromJson(body, &error);
const auto status = QJsonDocument::fromJson(body, &error);
// empty or invalid response
if (error.error != QJsonParseError::NoError || status.isNull()) {
qCWarning(lcCheckServerJob) << "status.php from server is not valid JSON!" << body << reply()->request().url() << error.errorString();
Expand Down

0 comments on commit fdd5356

Please sign in to comment.