Commit b8461709 authored by Jesus Fernandez's avatar Jesus Fernandez

Callback changes

parent 28ad61dc
......@@ -66,6 +66,8 @@ class OAUTH_EXPORT QOAuth2ImplicitGrantFlowPrivate : public QAbstractOAuth2Priva
public:
QOAuth2ImplicitGrantFlowPrivate(QNetworkAccessManager *manager);
~QOAuth2ImplicitGrantFlowPrivate();
void _q_handleCallback(const QVariantMap &data);
};
QT_END_NAMESPACE
......
......@@ -60,6 +60,7 @@ class OAUTH_EXPORT QAbstractOAuth2 : public QAbstractOAuth
WRITE setClientIdentifierSharedKey
NOTIFY clientIdentifierSharedKeyChanged)
Q_PROPERTY(QString state READ state WRITE setState NOTIFY stateChanged)
Q_PROPERTY(QDateTime expiration READ expirationAt NOTIFY expirationAtChanged)
public:
explicit QAbstractOAuth2(QObject *parent = nullptr);
......@@ -109,6 +110,7 @@ Q_SIGNALS:
void portChanged(quint16 port);
void stateChanged(const QString &state);
void authorizationCallbackReceived(const QVariantMap &data);
void expirationAtChanged(const QDateTime &expiration);
protected:
explicit QAbstractOAuth2(QAbstractOAuth2Private &, QObject *parent = nullptr);
......
......@@ -124,6 +124,7 @@ void QOAuth2AuthorizationCodeFlowPrivate::_q_accessTokenRequestFinished(const QV
}
q->setToken(accessToken);
expiresAt = expiresIn > 0 ? QDateTime::currentDateTime().addSecs(expiresIn) : QDateTime();
Q_EMIT q->expirationAtChanged(expiresAt);
setStatus(QAbstractOAuth::Status::Granted);
}
......
......@@ -59,6 +59,55 @@ QOAuth2ImplicitGrantFlowPrivate::QOAuth2ImplicitGrantFlowPrivate(QNetworkAccessM
QOAuth2ImplicitGrantFlowPrivate::~QOAuth2ImplicitGrantFlowPrivate()
{}
void QOAuth2ImplicitGrantFlowPrivate::_q_handleCallback(const QVariantMap &data)
{
Q_Q(QOAuth2ImplicitGrantFlow);
typedef QAbstractOAuth2Private::OAuth2KeyString Key;
if (status != QAbstractOAuth::Status::NotAuthenticated) {
qWarning("QOAuth2AuthorizationCodeFlow: Unexpected call");
return;
}
Q_ASSERT(!state.isEmpty());
const QString error = data.value(Key::error).toString();
const QString token = data.value(Key::accessToken).toString();
const QString tokenType = data.value(Key::tokenType).toString();
bool ok;
int expiresIn = data.value(Key::expiresIn).toInt(&ok);
if (!ok)
expiresIn = -1;
const QString receivedState = data.value(Key::state).toString();
if (!error.isEmpty()) {
const QString uri = data.value(Key::errorUri).toString();
const QString description = data.value(Key::errorDescription).toString();
qCritical("QOAuth2ImplicitGrantFlow: AuthenticationError: %s(%s): %s",
qPrintable(error), qPrintable(uri), qPrintable(description));
return;
} else if (token.isEmpty()) {
qCritical("QOAuth2ImplicitGrantFlow: AuthenticationError: Token not received");
return;
} else if (tokenType != QStringLiteral("bearer")) {
qCritical("QOAuth2ImplicitGrantFlow: Invalid Token type");
return;
} else if (receivedState.isEmpty()) {
qCritical("QOAuth2ImplicitGrantFlow: State not received");
return;
} else if (state != receivedState) {
qCritical("QOAuth2ImplicitGrantFlow: State mismatch");
return;
}
setStatus(QAbstractOAuth::Status::TemporaryCredentialsReceived);
q->setToken(token);
expiresAt = expiresIn > 0 ? QDateTime::currentDateTime().addSecs(expiresIn) : QDateTime();
Q_EMIT q->expirationAtChanged(expiresAt);
setStatus(QAbstractOAuth::Status::Granted);
}
QOAuth2ImplicitGrantFlow::QOAuth2ImplicitGrantFlow(QObject *parent) :
QAbstractOAuth2(*new QOAuth2ImplicitGrantFlowPrivate(nullptr), parent)
{}
......@@ -87,8 +136,14 @@ QString QOAuth2ImplicitGrantFlow::responseType() const
void QOAuth2ImplicitGrantFlow::grant()
{
Q_D(const QOAuth2ImplicitGrantFlow);
const QString state = QAbstractOAuth2Private::generateRandomState();
const QUrl url = authorizationRequestUrl(state);
connect(d->replyHandler.data(), &QAbstractOAuthReplyHandler::callbackReceived, this,
&QOAuth2ImplicitGrantFlow::authorizationCallbackReceived, Qt::UniqueConnection);
QObjectPrivate::connect(d->replyHandler.data(), &QAbstractOAuthReplyHandler::callbackReceived,
d, &QOAuth2ImplicitGrantFlowPrivate::_q_handleCallback,
Qt::UniqueConnection);
Q_EMIT authorizeWithBrowser(url);
}
......@@ -104,6 +159,8 @@ QUrl QOAuth2ImplicitGrantFlow::authorizationRequestUrl(const QString &state) con
parameters.insert(Key::redirectUri, callback());
parameters.insert(Key::scope, d->scope);
parameters.insert(Key::state, state);
if (d->modifyParametersFunction)
d->modifyParametersFunction(Stage::RequestingAuthorization, &parameters);
url.setQuery(QAbstractOAuth2Private::createQuery(parameters));
return url;
}
......
......@@ -53,6 +53,13 @@
QT_BEGIN_NAMESPACE
#define CALLBACK_ADDRESS "/cb"
const char *httpReply = "HTTP/1.0 200 OK \r\n"
"Content-Type: text/html; charset=\"utf-8\"\r\n"
"Content-Length: %1\r\n\r\n"
"%2";
QOAuthHttpServerReplyHandlerPrivate::QOAuthHttpServerReplyHandlerPrivate(quint16 port)
: text(QObject::tr("Callback received. Feel free to close this page."))
{
......@@ -78,28 +85,32 @@ void QOAuthHttpServerReplyHandlerPrivate::_q_answerClient()
Q_Q(QOAuthHttpServerReplyHandler);
QTcpSocket *socket = static_cast<QTcpSocket*>(currentSender->sender);
const QByteArray data = socket->readAll();
qDebug("QOAuthHttpServerReplyHandlerPrivate::answerClient: %s", qPrintable(data));
Q_EMIT q->callbackDataReceived(data);
if (data.startsWith("GET /?")) {
if (!data.startsWith("GET " CALLBACK_ADDRESS "?")) {
qWarning("QOAuthHttpServerReplyHandlerPrivate::_q_answerClient: Invalid request: %s",
qPrintable(data));
} else {
QVariantMap receivedData;
QUrl url(q->callback() + data.split(' ').at(1));
const QUrlQuery query(url.query());
const int queryStart = strlen("GET " CALLBACK_ADDRESS "?"),
queryEnd = data.indexOf(" HTTP/1.1");
const QByteArray queryData = data.mid(queryStart, queryEnd - queryStart);
const QUrlQuery query(queryData);
const auto items = query.queryItems();
for (auto it = items.begin(), end = items.end(); it != end; ++it)
receivedData.insert(it->first, it->second);
Q_EMIT q->callbackReceived(receivedData);
}
const QString html = QString::fromLatin1("<html><head><title>%1</title><body>%2</body></html>")
.arg(qApp->applicationName(), text);
const QString replyMessage = QString::fromLatin1("HTTP/1.0 200 OK \r\n"
"Content-Type: text/html; "
"charset=\"utf-8\"\r\n"
"Content-Length: %1\r\n\r\n"
"%2").arg(html.size()).arg(html);
const QString html = QString::fromLatin1("<html><head><title>%1</title><body>%2</body></html>")
.arg(qApp->applicationName(), text);
const QString replyMessage = QString::fromLatin1("HTTP/1.0 200 OK \r\n"
"Content-Type: text/html; "
"charset=\"utf-8\"\r\n"
"Content-Length: %1\r\n\r\n"
"%2").arg(html.size()).arg(html);
socket->write(replyMessage.toUtf8());
socket->write(replyMessage.toUtf8());
}
socket->disconnectFromHost();
}
......@@ -127,7 +138,8 @@ QString QOAuthHttpServerReplyHandler::callback() const
Q_D(const QOAuthHttpServerReplyHandler);
Q_ASSERT(d->httpServer.isListening());
const QUrl url(QString::fromLatin1("http://localhost:%1/").arg(d->httpServer.serverPort()));
const QUrl url(QString::fromLatin1("http://localhost:%1" CALLBACK_ADDRESS)
.arg(d->httpServer.serverPort()));
return url.toString(QUrl::EncodeDelimiters);
}
......
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