OAuth: Don't use implicit POST bodies

The query args of POST requests become the request body. If there's a
redirect, the redirected url will therefore not contain the query
arguments. Use an explicit request body to make the redirection work.
This commit is contained in:
Christian Kamm 2017-09-11 12:24:29 +02:00 committed by Roeland Jago Douma
parent a79b0a3791
commit e47b8ffaca
No known key found for this signature in database
GPG key ID: F941078878347C0C
3 changed files with 34 additions and 11 deletions

View file

@ -15,6 +15,7 @@
#include <QDesktopServices>
#include <QNetworkReply>
#include <QTimer>
#include <QBuffer>
#include "account.h"
#include "creds/oauth.h"
#include <QJsonObject>
@ -75,16 +76,21 @@ void OAuth::start()
QString code = rx.cap(1); // The 'code' is the first capture of the regexp
QUrl requestToken(_account->url().toString()
+ QLatin1String("/index.php/apps/oauth2/api/v1/token?grant_type=authorization_code&code=")
+ code
+ QLatin1String("&redirect_uri=http://localhost:") + QString::number(_server.serverPort()));
QUrl requestToken(_account->url().toString() + QLatin1String("/index.php/apps/oauth2/api/v1/token"));
QNetworkRequest req;
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QString basicAuth = QString("%1:%2").arg(
Theme::instance()->oauthClientId(), Theme::instance()->oauthClientSecret());
req.setRawHeader("Authorization", "Basic " + basicAuth.toUtf8().toBase64());
auto job = _account->sendRequest("POST", requestToken, req);
auto requestBody = new QBuffer;
QUrlQuery arguments(QString(
"grant_type=authorization_code&code=%1&redirect_uri=http://localhost:%2")
.arg(code, QString::number(_server.serverPort())));
requestBody->setData(arguments.query(QUrl::FullyEncoded).toLatin1());
auto job = _account->sendRequest("POST", requestToken, req, requestBody);
QObject::connect(job, &SimpleNetworkJob::finishedSignal, this, [this, socket](QNetworkReply *reply) {
auto jsonData = reply->readAll();
QJsonParseError jsonParseError;

View file

@ -173,6 +173,17 @@ void AbstractNetworkJob::slotFinished()
if (_followRedirects && !redirectUrl.isEmpty()) {
_redirectCount++;
// 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
QByteArray verb = requestVerb(*reply());

View file

@ -20,6 +20,7 @@
#include <QSslKey>
#include <QJsonObject>
#include <QJsonDocument>
#include <QBuffer>
#include <keychain.h>
@ -296,14 +297,19 @@ bool HttpCredentials::refreshAccessToken()
if (_refreshToken.isEmpty())
return false;
QUrl requestToken(_account->url().toString()
+ QLatin1String("/index.php/apps/oauth2/api/v1/token?grant_type=refresh_token&refresh_token=")
+ _refreshToken);
requestToken.setUserName(Theme::instance()->oauthClientId());
requestToken.setPassword(Theme::instance()->oauthClientSecret());
QUrl requestToken(_account->url().toString() + QLatin1String("/index.php/apps/oauth2/api/v1/token"));
QNetworkRequest req;
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
auto job = _account->sendRequest("POST", requestToken, req);
QString basicAuth = QString("%1:%2").arg(
Theme::instance()->oauthClientId(), Theme::instance()->oauthClientSecret());
req.setRawHeader("Authorization", "Basic " + basicAuth.toUtf8().toBase64());
auto requestBody = new QBuffer;
QUrlQuery arguments(QString("grant_type=refresh_token&refresh_token=%1").arg(_refreshToken));
requestBody->setData(arguments.query(QUrl::FullyEncoded).toLatin1());
auto job = _account->sendRequest("POST", requestToken, req, requestBody);
QObject::connect(job, &SimpleNetworkJob::finishedSignal, this, [this](QNetworkReply *reply) {
auto jsonData = reply->readAll();
QJsonParseError jsonParseError;