From d34dbbdb0bc58700b0f9bb4e1ed3f9c62c6eab3d Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 3 Jul 2017 14:51:20 +0200 Subject: [PATCH] OAuth: Redirects to the server in case of sucessfull login Requires https://github.com/owncloud/oauth2/pull/45 This commit moves the reply after we got the token reply from the server, that allows to reply with an error to the browser if the login does not work. --- src/gui/creds/oauth.cpp | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/gui/creds/oauth.cpp b/src/gui/creds/oauth.cpp index 38e279d29..710e190ac 100644 --- a/src/gui/creds/oauth.cpp +++ b/src/gui/creds/oauth.cpp @@ -29,15 +29,23 @@ OAuth::~OAuth() { } -static void httpReplyAndClose(QTcpSocket *socket, const char *code, const char *html) +static void httpReplyAndClose(QTcpSocket *socket, const char *code, const char *html, + const char *moreHeaders = nullptr) { socket->write("HTTP/1.1 "); socket->write(code); socket->write("\r\nContent-Type: text/html\r\nConnection: close\r\nContent-Length: "); socket->write(QByteArray::number(qstrlen(html))); + if (moreHeaders) { + socket->write("\r\n"); + socket->write(moreHeaders); + } socket->write("\r\n\r\n"); socket->write(html); socket->disconnectFromHost(); + // We don't want that deleting the server too early prevent queued data to be sent on this socket. + // The socket will be deleted after disconnection because disconnected is connected to deleteLater + socket->setParent(nullptr); } void OAuth::start() @@ -64,9 +72,6 @@ void OAuth::start() return; } - // TODO: add redirect to the page on the server - httpReplyAndClose(socket, "200 OK", "

Login Successful

You can close this window.

"); - QString code = rx.cap(1); // The 'code' is the first capture of the regexp QUrl requestToken(_account->url().toString() @@ -79,21 +84,45 @@ void OAuth::start() req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); auto reply = _account->sendRequest("POST", requestToken, req); QTimer::singleShot(30 * 1000, reply, &QNetworkReply::abort); - QObject::connect(reply, &QNetworkReply::finished, this, [this, reply] { + QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, socket] { auto jsonData = reply->readAll(); QJsonParseError jsonParseError; QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object(); QString accessToken = json["access_token"].toString(); QString refreshToken = json["refresh_token"].toString(); QString user = json["user_id"].toString(); + QUrl messageUrl = json["message_url"].toString(); if (reply->error() != QNetworkReply::NoError || jsonParseError.error != QJsonParseError::NoError || json.isEmpty() || refreshToken.isEmpty() || accessToken.isEmpty() || json["token_type"].toString() != QLatin1String("Bearer")) { - qCWarning(lcOauth) << "Error when getting the accessToken" << reply->error() << json << jsonParseError.errorString(); + QString errorReason; + QString errorFromJson = json["error"].toString(); + if (!errorFromJson.isEmpty()) { + errorReason = tr("Error returned from the server: %1") + .arg(errorFromJson.toHtmlEscaped()); + } else if (reply->error() != QNetworkReply::NoError) { + errorReason = tr("There was an error accessing the 'token' endpoint:
%1") + .arg(reply->errorString().toHtmlEscaped()); + } else if (jsonParseError.error != QJsonParseError::NoError) { + errorReason = tr("Could not parse the JSON returned from the server:
%1") + .arg(jsonParseError.errorString()); + } else { + errorReason = tr("The reply from the server did not contain all expected fields"); + } + qCWarning(lcOauth) << "Error when getting the accessToken" << json << errorReason; + httpReplyAndClose(socket, "500 Internal Server Error", + tr("

Login Error

%1

").arg(errorReason).toUtf8().constData()); emit result(Error); return; } + const char *loginSuccessfullHtml = "

Login Successful

You can close this window.

"; + if (messageUrl.isValid()) { + httpReplyAndClose(socket, "303 See Other", loginSuccessfullHtml, + QByteArray("Location: " + messageUrl.toEncoded()).constData()); + } else { + httpReplyAndClose(socket, "200 OK", loginSuccessfullHtml); + } emit result(LoggedIn, user, accessToken, refreshToken); }); }); -- 2.30.2