Commit 1eaecb17 authored by Jesus Fernandez's avatar Jesus Fernandez Committed by Jesus Fernandez

OAuthTool

parent e82aa048
......@@ -81,6 +81,7 @@ public:
QPair<QString, QString> clientCredentials;
QString token;
QString scope;
QString state = generateRandomState();
QString userAgent = "qoauth/0.1";
const QString bearerFormat = QStringLiteral("Bearer %1");
QDateTime expiresAt;
......
......@@ -70,7 +70,7 @@ public:
QOAuth2AuthorizationCodeFlowPrivate(quint16 port = 0);
QOAuth2AuthorizationCodeFlowPrivate(QNetworkAccessManager *manager, quint16 port);
void handleCallback(const QVariantMap &data, const QString state);
void handleCallback(const QVariantMap &data);
void accessTokenRequestFinished(QNetworkReply *reply);
void authenticate(QNetworkReply *reply, QAuthenticator *authenticator);
......
......@@ -151,6 +151,7 @@ Q_SIGNALS:
void authorizationRequested(const QUrl &url);
void granted();
void finished(QNetworkReply *reply);
void replyDataReceived(const QByteArray &data);
protected:
explicit QAbstractOAuth(QAbstractOAuthPrivate &, QObject *parent = nullptr);
......
......@@ -306,6 +306,21 @@ void QAbstractOAuth2::setPort(uint port)
}
}
QString QAbstractOAuth2::state() const
{
Q_D(const QAbstractOAuth2);
return d->state;
}
void QAbstractOAuth2::setState(const QString &state)
{
Q_D(QAbstractOAuth2);
if (state != d->state) {
d->state = state;
Q_EMIT stateChanged(state);
}
}
QDateTime QAbstractOAuth2::expirationAt() const
{
Q_D(const QAbstractOAuth2);
......
......@@ -60,6 +60,7 @@ class OAUTH_EXPORT QAbstractOAuth2 : public QAbstractOAuth
WRITE setClientIdentifierSharedKey
NOTIFY clientIdentifierSharedKeyChanged)
Q_PROPERTY(uint port READ port WRITE setPort NOTIFY portChanged)
Q_PROPERTY(QString state READ state WRITE setState NOTIFY stateChanged)
public:
explicit QAbstractOAuth2(QObject *parent = nullptr);
......@@ -96,6 +97,9 @@ public:
uint port() const;
void setPort(uint port);
QString state() const;
void setState(const QString &state);
QDateTime expirationAt() const;
Q_SIGNALS:
......@@ -107,6 +111,8 @@ Q_SIGNALS:
void consumerTokenKeyChanged(const QString &key);
void tokenChanged(const QString &token);
void portChanged(quint16 port);
void stateChanged(const QString &state);
void authorizationCallbackReceived(const QVariantMap &data);
protected:
explicit QAbstractOAuth2(QAbstractOAuth2Private &, QObject *parent = nullptr);
......
......@@ -65,6 +65,9 @@ Q_SIGNALS:
void callbackReceived(const QVariantMap &values);
void tokensReceived(const QVariantMap &tokens);
void replyDataReceived(const QByteArray &data);
void callbackDataReceived(const QByteArray &data);
protected:
QAbstractOAuthReplyHandler(QObjectPrivate &d, QObject *parent = nullptr);
......
......@@ -65,8 +65,7 @@ QOAuth2AuthorizationCodeFlowPrivate::QOAuth2AuthorizationCodeFlowPrivate(
: QAbstractOAuth2Private(manager, port)
{}
void QOAuth2AuthorizationCodeFlowPrivate::handleCallback(const QVariantMap &data,
const QString state)
void QOAuth2AuthorizationCodeFlowPrivate::handleCallback(const QVariantMap &data)
{
Q_Q(QOAuth2AuthorizationCodeFlow);
typedef QAbstractOAuth2Private::OAuth2KeyString Key;
......@@ -119,8 +118,15 @@ void QOAuth2AuthorizationCodeFlowPrivate::accessTokenRequestFinished(QNetworkRep
setStatus(QAbstractOAuth::Status::NotAuthenticated);
return;
}
const auto json = reply->readAll();
qDebug() << json;
const QByteArray json = reply->readAll();
Q_EMIT q->replyDataReceived(json);
if (json.isEmpty()) {
qCritical("QOAuth2AuthorizationCodeFlowPrivate::accessTokenRequestFinished: Empty answer");
return;
}
qDebug("QOAuth2AuthorizationCodeFlowPrivate::accessTokenRequestFinished: %s", qPrintable(json));
const auto document = QJsonDocument::fromJson(json);
Q_ASSERT(document.isObject());
const auto object = document.object();
......@@ -241,6 +247,8 @@ void QOAuth2AuthorizationCodeFlow::grant()
}
const QUrl url = buildAuthenticateUrl();
QObjectPrivate::connect(this, &QOAuth2AuthorizationCodeFlow::authorizationCallbackReceived, d,
&QOAuth2AuthorizationCodeFlowPrivate::handleCallback);
Q_EMIT authorizationRequested(url);
}
......@@ -282,7 +290,9 @@ QUrl QOAuth2AuthorizationCodeFlow::buildAuthenticateUrl(const QVariantMap &param
Q_D(QOAuth2AuthorizationCodeFlow);
typedef QAbstractOAuth2Private::OAuth2KeyString Key;
const QString state = QAbstractOAuth2Private::generateRandomState();
if (d->state.isEmpty())
d->state = QAbstractOAuth2Private::generateRandomState();
const QString state = d->state;
QVariantMap p(parameters);
QUrl url(d->authorizationUrl);
......@@ -295,9 +305,8 @@ QUrl QOAuth2AuthorizationCodeFlow::buildAuthenticateUrl(const QVariantMap &param
if (d->modifyParametersFunction)
d->modifyParametersFunction(Stage::RequestingAuthorization, &p);
url.setQuery(d->createQuery(p));
const auto bind = std::bind(&QOAuth2AuthorizationCodeFlowPrivate::handleCallback, d,
std::placeholders::_1, state);
connect(d->replyHandler.data(), &QAbstractOAuthReplyHandler::callbackReceived, bind);
connect(d->replyHandler.data(), &QAbstractOAuthReplyHandler::callbackReceived, this,
&QOAuth2AuthorizationCodeFlow::authorizationCallbackReceived);
setStatus(QAbstractOAuth::Status::NotAuthenticated);
qDebug() << url;
return url;
......
......@@ -77,8 +77,10 @@ void QOAuthHttpServerReplyHandlerPrivate::answerClient()
{
Q_Q(QOAuthHttpServerReplyHandler);
QTcpSocket *socket = static_cast<QTcpSocket*>(currentSender->sender);
const QString data = QString::fromUtf8(socket->readAll());
if (data.startsWith(QStringLiteral("GET /?"))) {
const QByteArray data = socket->readAll();
qDebug("QOAuthHttpServerReplyHandlerPrivate::answerClient: %s", qPrintable(data));
Q_EMIT q->callbackDataReceived(data);
if (data.startsWith("GET /?")) {
QVariantMap receivedData;
QUrl url(q->callback() + data.split(' ').at(1));
const QUrlQuery query(url.query());
......@@ -141,6 +143,22 @@ void QOAuthHttpServerReplyHandler::setCallbackText(const QString &text)
d->text = text;
}
quint16 QOAuthHttpServerReplyHandler::port() const
{
Q_D(const QOAuthHttpServerReplyHandler);
return d->httpServer.serverPort();
}
bool QOAuthHttpServerReplyHandler::listen(quint16 port)
{
Q_D(QOAuthHttpServerReplyHandler);
if (d->httpServer.serverPort() != port) {
d->httpServer.close();
return d->httpServer.listen(QHostAddress::Any, port);
}
return true;
}
QT_END_NAMESPACE
#endif // QT_NO_HTTP
......
......@@ -63,6 +63,10 @@ public:
QString callbackText() const;
void setCallbackText(const QString &text);
quint16 port() const;
bool listen(quint16 port = 0);
private:
Q_DECLARE_PRIVATE(QOAuthHttpServerReplyHandler)
};
......
......@@ -63,6 +63,7 @@ void QOAuthOobReplyHandler::networkReplyFinished()
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
Q_ASSERT(reply);
const QByteArray data = reply->readAll();
Q_EMIT replyDataReceived(data);
if (data.isEmpty())
return;
......
......@@ -4,4 +4,5 @@ SUBDIRS += \
twittertimeline \
redditclient \
qtgcal \
googlecalendar
googlecalendar \
oauthtool
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "oauthdialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setApplicationName("Qt OAuth Tool");
a.setOrganizationDomain("qt.io");
a.setOrganizationName("The Qt Company");
OAuthDialog w;
w.show();
return a.exec();
}
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "oauthdialog.h"
#include <QtOAuth/qoauthhttpserverreplyhandler.h>
#include <QtWebEngineWidgets>
OAuthDialog::OAuthDialog(QWidget *parent) :
QDialog(parent),
oauth2(new OAuth2(this)),
webEngineView(new QWebEngineView(this)),
replyHandler(new QOAuthHttpServerReplyHandler(this))
{
setupUi(this);
webEngineView->load(QUrl("https://www.qt.io"));
webEngineViewWidget->layout()->addWidget(webEngineView);
oauth2->setReplyHandler(replyHandler);
callbackPortSpinBox->setValue(replyHandler->port());
stateLineEdit->setText(oauth2->state());
connect(userAgentLineEdit, &QLineEdit::textChanged, oauth2,
&QOAuth2AuthorizationCodeFlow::setUserAgent);
connect(clientIdentifierLineEdit, &QLineEdit::textChanged, oauth2,
&QOAuth2AuthorizationCodeFlow::setClientIdentifier);
connect(clientSharedKeyLineEdit, &QLineEdit::textChanged, oauth2,
&QOAuth2AuthorizationCodeFlow::setClientIdentifierSharedKey);
connect(authorizationUrlLineEdit, &QLineEdit::textChanged, oauth2,
&QOAuth2AuthorizationCodeFlow::setAuthorizationUrl);
connect(callbackPortSpinBox, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),
replyHandler, &QOAuthHttpServerReplyHandler::listen);
connect(scopeLineEdit, &QLineEdit::textChanged, oauth2,
&QOAuth2AuthorizationCodeFlow::setScope);
connect(stateLineEdit, &QLineEdit::textChanged, oauth2,
&QOAuth2AuthorizationCodeFlow::setState);
connect(accessTokenUrlLineEdit, &QLineEdit::textChanged, oauth2,
&QOAuth2AuthorizationCodeFlow::setAccessTokenUrl);
connect(oauth2, &OAuth2::authorizationCallbackReceived, this, &OAuthDialog::handleCallback);
connect(replyHandler, &QOAuthHttpServerReplyHandler::callbackDataReceived,
[=](const QByteArray &data) {
authorizationAnswerPlainTextEdit->setPlainText(QString::fromUtf8(data));
});
connect(oauth2, &QOAuth2AuthorizationCodeFlow::replyDataReceived, [=](const QByteArray &data) {
requestAccessTokenPlainTextEdit->setPlainText(QString::fromUtf8(data));
});
connect(oauth2, &QOAuth2AuthorizationCodeFlow::tokenChanged, accessTokenLineEdit,
&QLineEdit::setText);
readSettings();
}
void OAuthDialog::on_authorizePushButton_clicked(bool checked)
{
Q_UNUSED(checked);
const QUrl url = oauth2->buildAuthenticateUrl();
webEngineView->load(url);
}
void OAuthDialog::on_requestAccessTokenPushButton_clicked(bool checked)
{
Q_UNUSED(checked);
oauth2->requestAccessToken(codeLineEdit->text());
}
void OAuthDialog::on_authenticatedCallPushButton_clicked(bool checked)
{
Q_UNUSED(checked);
QNetworkReply *reply = oauth2->get(QUrl(authenticatedCallLineEdit->text()));
connect(reply, &QNetworkReply::finished, [=]() {
if (reply->error() != QNetworkReply::NoError) {
answerAuthenticatedCallPlainTextEdit->setPlainText(reply->errorString());
return;
}
const QByteArray data = reply->readAll();
answerAuthenticatedCallPlainTextEdit->setPlainText(QString::fromUtf8(data));
webEngineView->setContent(data);
});
}
void OAuthDialog::handleCallback(const QVariantMap &data)
{
qDebug() << "Received values" << data;
codeLineEdit->setText(data.value("code").toString());
}
void OAuthDialog::closeEvent(QCloseEvent *event)
{
Q_UNUSED(event);
writeSettings();
}
void OAuthDialog::readSettings()
{
QSettings settings;
clientIdentifierLineEdit->setText(settings.value("clientIdentifier").toString());
clientSharedKeyLineEdit->setText(settings.value("clientSharedKey").toString());
authorizationUrlLineEdit->setText(settings.value("authorizationUrl").toString());
replyHandler->listen(settings.value("callbackPort", 0).toUInt());
callbackPortSpinBox->setValue(replyHandler->port());
scopeLineEdit->setText(settings.value("scope").toString());
stateLineEdit->setText(settings.value("state").toString());
accessTokenUrlLineEdit->setText(settings.value("accessTokenUrl").toString());
userAgentLabel->setText(settings.value("userAgent", "Qt OAuth Tool").toString());
authenticatedCallLineEdit->setText(settings.value("authenticatedCall").toString());
}
void OAuthDialog::writeSettings()
{
QSettings settings;
settings.setValue("clientIdentifier", clientIdentifierLineEdit->text());
settings.setValue("clientSharedKey", clientSharedKeyLineEdit->text());
settings.setValue("authorizationUrl", authorizationUrlLineEdit->text());
settings.setValue("callbackPort", callbackPortSpinBox->value());
settings.setValue("scope", scopeLineEdit->text());
settings.setValue("state", stateLineEdit->text());
settings.setValue("accessTokenUrl", accessTokenUrlLineEdit->text());
settings.setValue("userAgent", userAgentLineEdit->text());
settings.setValue("authenticatedCall", authenticatedCallLineEdit->text());
}
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QtOAuth/qoauth2authorizationcodeflow.h>
#include "ui_oauthdialog.h"
class OAuth2;
class QOAuthHttpServerReplyHandler;
class QWebEngineView;
class OAuthDialog : public QDialog, protected Ui::OAuthDialog
{
Q_OBJECT
public:
explicit OAuthDialog(QWidget *parent = 0);
protected slots:
void on_authorizePushButton_clicked(bool checked);
void on_requestAccessTokenPushButton_clicked(bool checked);
void on_authenticatedCallPushButton_clicked(bool checked);
void handleCallback(const QVariantMap &data);
protected:
void closeEvent(QCloseEvent *event);
void readSettings();
void writeSettings();
private:
class OAuth2 : public QOAuth2AuthorizationCodeFlow
{
friend class OAuthDialog;
public:
using QOAuth2AuthorizationCodeFlow::QOAuth2AuthorizationCodeFlow;
using QOAuth2AuthorizationCodeFlow::buildAuthenticateUrl;
using QOAuth2AuthorizationCodeFlow::requestAccessToken;
} *oauth2;
QWebEngineView *webEngineView;
QOAuthHttpServerReplyHandler *replyHandler;
};
#endif // DIALOG_H
This diff is collapsed.
QT += core gui webengine webenginewidgets
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = oauthtool
TEMPLATE = app
SOURCES += \
main.cpp\
oauthdialog.cpp
HEADERS += oauthdialog.h
FORMS += oauthdialog.ui
include(../../QtOAuth.pri)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment