mirror of https://github.com/nymea/nymea.git
277 lines
8.3 KiB
C++
277 lines
8.3 KiB
C++
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
*
|
|
* Copyright 2013 - 2020, nymea GmbH
|
|
* Contact: contact@nymea.io
|
|
*
|
|
* This file is part of nymea.
|
|
* This project including source code and documentation is protected by
|
|
* copyright law, and remains the property of nymea GmbH. All rights, including
|
|
* reproduction, publication, editing and translation, are reserved. The use of
|
|
* this project is subject to the terms of a license agreement to be concluded
|
|
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
|
|
* under https://nymea.io/license
|
|
*
|
|
* GNU Lesser General Public License Usage
|
|
* Alternatively, this project may be redistributed and/or modified under the
|
|
* terms of the GNU Lesser General Public License as published by the Free
|
|
* Software Foundation; version 3. This project is distributed in the hope that
|
|
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this project. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
* For any further details and any questions please contact us under
|
|
* contact@nymea.io or see our FAQ/Licensing Information on
|
|
* https://nymea.io/license/faq
|
|
*
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
#include "oauth2.h"
|
|
#include "loggingcategories.h"
|
|
|
|
#include <QDebug>
|
|
#include <QNetworkRequest>
|
|
#include <QJsonDocument>
|
|
|
|
OAuth2::OAuth2(QString clientId, QString clientSecret, QObject *parent) :
|
|
QObject(parent),
|
|
m_clientId(clientId),
|
|
m_clientSecret(clientSecret),
|
|
m_authenticated(false)
|
|
{
|
|
m_networkManager = new QNetworkAccessManager(this);
|
|
connect(m_networkManager, &QNetworkAccessManager::finished, this, &OAuth2::replyFinished);
|
|
|
|
m_timer = new QTimer(this);
|
|
m_timer->setSingleShot(false);
|
|
|
|
connect(m_timer, &QTimer::timeout, this, &OAuth2::refreshTimeout);
|
|
}
|
|
|
|
QUrl OAuth2::url() const
|
|
{
|
|
return m_url;
|
|
}
|
|
|
|
void OAuth2::setUrl(const QUrl &url)
|
|
{
|
|
m_url = url;
|
|
}
|
|
|
|
QUrlQuery OAuth2::query() const
|
|
{
|
|
return m_query;
|
|
}
|
|
|
|
void OAuth2::setQuery(const QUrlQuery &query)
|
|
{
|
|
m_query = query;
|
|
}
|
|
|
|
QString OAuth2::username() const
|
|
{
|
|
return m_username;
|
|
}
|
|
|
|
void OAuth2::setUsername(const QString &username)
|
|
{
|
|
m_username = username;
|
|
}
|
|
|
|
QString OAuth2::password() const
|
|
{
|
|
return m_password;
|
|
}
|
|
|
|
void OAuth2::setPassword(const QString &password)
|
|
{
|
|
m_password = password;
|
|
}
|
|
|
|
QString OAuth2::clientId() const
|
|
{
|
|
return m_clientId;
|
|
}
|
|
|
|
void OAuth2::setClientId(const QString &clientId)
|
|
{
|
|
m_clientId = clientId;
|
|
}
|
|
|
|
QString OAuth2::clientSecret() const
|
|
{
|
|
return m_clientSecret;
|
|
}
|
|
|
|
void OAuth2::setClientSecret(const QString clientSecret)
|
|
{
|
|
m_clientSecret = clientSecret;
|
|
}
|
|
|
|
QString OAuth2::scope() const
|
|
{
|
|
return m_scope;
|
|
}
|
|
|
|
void OAuth2::setScope(const QString &scope)
|
|
{
|
|
m_scope = scope;
|
|
}
|
|
|
|
QString OAuth2::token() const
|
|
{
|
|
return m_token;
|
|
}
|
|
|
|
bool OAuth2::authenticated() const
|
|
{
|
|
return m_authenticated;
|
|
}
|
|
|
|
void OAuth2::startAuthentication()
|
|
{
|
|
qCDebug(dcOAuth2) << "Start authentication" << m_username;
|
|
|
|
QUrlQuery query;
|
|
query.addQueryItem("grant_type", "password");
|
|
query.addQueryItem("client_id", m_clientId);
|
|
query.addQueryItem("client_secret", m_clientSecret);
|
|
query.addQueryItem("username", m_username);
|
|
query.addQueryItem("password", m_password);
|
|
query.addQueryItem("scope", m_scope);
|
|
setQuery(query);
|
|
|
|
QNetworkRequest request(m_url);
|
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded; charset=UTF-8");
|
|
m_tokenRequests.append(m_networkManager->post(request, m_query.toString().toUtf8()));
|
|
}
|
|
|
|
void OAuth2::setAuthenticated(const bool &authenticated)
|
|
{
|
|
if (authenticated) {
|
|
qCDebug(dcOAuth2) << "Authenticated successfully" << m_username;
|
|
} else {
|
|
m_timer->stop();
|
|
qCWarning(dcOAuth2) << "Authentication failed" << m_username;
|
|
}
|
|
m_authenticated = authenticated;
|
|
emit authenticationChanged();
|
|
}
|
|
|
|
void OAuth2::setToken(const QString &token)
|
|
{
|
|
m_token = token;
|
|
emit tokenChanged();
|
|
}
|
|
|
|
void OAuth2::replyFinished(QNetworkReply *reply)
|
|
{
|
|
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
|
|
|
// token request
|
|
if (m_tokenRequests.contains(reply)) {
|
|
|
|
QByteArray data = reply->readAll();
|
|
m_tokenRequests.removeAll(reply);
|
|
|
|
// check HTTP status code
|
|
if (status != 200) {
|
|
qCWarning(dcOAuth2) << "Request token reply HTTP error:" << status << reply->errorString();
|
|
qCWarning(dcOAuth2) << data;
|
|
setAuthenticated(false);
|
|
reply->deleteLater();
|
|
return;
|
|
}
|
|
|
|
// check JSON
|
|
QJsonParseError error;
|
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
|
if (error.error != QJsonParseError::NoError) {
|
|
qCWarning(dcOAuth2) << "Request token reply JSON error:" << error.errorString();
|
|
setAuthenticated(false);
|
|
reply->deleteLater();
|
|
return;
|
|
}
|
|
|
|
if (!jsonDoc.toVariant().toMap().contains("access_token")) {
|
|
qCWarning(dcOAuth2) << "Could not get access token" << jsonDoc.toJson();
|
|
setAuthenticated(false);
|
|
reply->deleteLater();
|
|
return;
|
|
}
|
|
|
|
setToken(jsonDoc.toVariant().toMap().value("access_token").toString());
|
|
setAuthenticated(true);
|
|
|
|
if (jsonDoc.toVariant().toMap().contains("expires_in") && jsonDoc.toVariant().toMap().contains("refresh_token")) {
|
|
int expireTime = jsonDoc.toVariant().toMap().value("expires_in").toInt();
|
|
m_refreshToken = jsonDoc.toVariant().toMap().value("refresh_token").toString();
|
|
qCDebug(dcOAuth2) << "Token will be refreshed in" << expireTime << "[s]";
|
|
m_timer->start((expireTime - 20) * 1000);
|
|
}
|
|
|
|
} else if (m_refreshTokenRequests.contains(reply)) {
|
|
|
|
QByteArray data = reply->readAll();
|
|
m_refreshTokenRequests.removeAll(reply);
|
|
|
|
// check HTTP status code
|
|
if (status != 200) {
|
|
qCWarning(dcOAuth2) << "Refresh token reply HTTP error:" << status << reply->errorString();
|
|
qCWarning(dcOAuth2) << data;
|
|
setAuthenticated(false);
|
|
reply->deleteLater();
|
|
return;
|
|
}
|
|
|
|
// check JSON
|
|
QJsonParseError error;
|
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
|
if (error.error != QJsonParseError::NoError) {
|
|
qCWarning(dcOAuth2) << "Refresh token reply JSON error:" << error.errorString();
|
|
setAuthenticated(false);
|
|
reply->deleteLater();
|
|
return;
|
|
}
|
|
|
|
if (!jsonDoc.toVariant().toMap().contains("access_token")) {
|
|
qCWarning(dcOAuth2) << "Could not get access token after refresh" << jsonDoc.toJson();
|
|
setAuthenticated(false);
|
|
reply->deleteLater();
|
|
return;
|
|
}
|
|
|
|
setToken(jsonDoc.toVariant().toMap().value("access_token").toString());
|
|
qCDebug(dcOAuth2) << "Token refreshed successfully";
|
|
|
|
if (jsonDoc.toVariant().toMap().contains("expires_in") && jsonDoc.toVariant().toMap().contains("refresh_token")) {
|
|
int expireTime = jsonDoc.toVariant().toMap().value("expires_in").toInt();
|
|
m_refreshToken = jsonDoc.toVariant().toMap().value("refresh_token").toString();
|
|
qCDebug(dcOAuth2) << "Token will be refreshed in" << expireTime << "[s]";
|
|
m_timer->start((expireTime - 20) * 1000);
|
|
}
|
|
|
|
if (!authenticated())
|
|
setAuthenticated(true);
|
|
}
|
|
|
|
reply->deleteLater();
|
|
}
|
|
|
|
void OAuth2::refreshTimeout()
|
|
{
|
|
qCDebug(dcOAuth2) << "Refresh authentication token for" << m_username;
|
|
|
|
QUrlQuery query;
|
|
query.addQueryItem("grant_type", "refresh_token");
|
|
query.addQueryItem("refresh_token", m_refreshToken);
|
|
query.addQueryItem("client_id", m_clientId);
|
|
query.addQueryItem("client_secret", m_clientSecret);
|
|
|
|
QNetworkRequest request(m_url);
|
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded; charset=UTF-8");
|
|
m_refreshTokenRequests.append(m_networkManager->post(request, query.toString().toUtf8()));
|
|
}
|