#include "PFXOauth.h" namespace test_namespace { /* * Base class to perform oauth2 flows * */ void OauthBase::onFinish(QNetworkReply *rep) { //TODO emit error signal when token is wrong QJsonDocument document = QJsonDocument::fromJson(rep->readAll()); QJsonObject rootObj = document.object(); QString token = rootObj.find("access_token").value().toString(); QString scope = rootObj.find("scope").value().toString(); QString type = rootObj.find("token_type").value().toString(); int expiresIn = rootObj.find("expires_in").value().toInt(); addToken(oauthToken(token, expiresIn, scope, type)); } oauthToken OauthBase::getToken(QString scope) { auto tokenIt = m_oauthTokenMap.find(scope); return tokenIt != m_oauthTokenMap.end() ? tokenIt.value() : oauthToken(); } void OauthBase::addToken(oauthToken token) { m_oauthTokenMap.insert(token.getScope(),token); Q_EMIT tokenReceived(); } void OauthBase::removeToken(QString scope) { m_oauthTokenMap.remove(scope); } /* * Class to perform the authorization code flow * */ OauthCode::OauthCode(QObject *parent) : OauthBase(parent){} void OauthCode::link(){ connect(&m_server, SIGNAL(dataReceived(QMap)), this, SLOT(onVerificationReceived(QMap))); connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); connect(this, SIGNAL(tokenReceived()), &m_server, SLOT(stop())); } void OauthCode::unlink() { disconnect(this, nullptr, nullptr, nullptr); disconnect(&m_server, nullptr, nullptr, nullptr); } void OauthCode::setVariables(QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType){ m_authUrl = QUrl(authUrl); m_tokenUrl = QUrl(tokenUrl); m_scope = scope; m_accessType = accessType; m_state = state; m_redirectUri = redirectUri; m_clientId = clientId; m_clientSecret = clientSecret; } void OauthCode::authenticationNeededCallback() { QDesktopServices::openUrl(QUrl(m_authUrl.toString() + "?scope=" + m_scope + (m_accessType=="" ? "" : "&access_type=" + m_accessType) + "&response_type=code" + "&state=" + m_state + "&redirect_uri=" + m_redirectUri + "&client_id=" + m_clientId)); m_server.start(); } void OauthCode::onVerificationReceived(const QMap response) { // Save access code QString state(response.value("state")); QString scope(response.value("scope")); QString code(response.value("code")); //create query with the required fields QUrlQuery postData; postData.addQueryItem("grant_type", "authorization_code"); postData.addQueryItem("client_id", m_clientId); postData.addQueryItem("client_secret", m_clientSecret); postData.addQueryItem("code", code); postData.addQueryItem("redirect_uri", m_redirectUri); QNetworkAccessManager * manager = new QNetworkAccessManager(this); QNetworkRequest request(m_tokenUrl); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onFinish(QNetworkReply *))); manager->post(request, postData.query().toUtf8()); } /* * Class to perform the implicit flow * */ OauthImplicit::OauthImplicit(QObject *parent) : OauthBase(parent){} void OauthImplicit::link() { //TODO correct linking connect(&m_server, SIGNAL(dataReceived(QMap)), this, SLOT(ImplicitTokenReceived(QMap))); connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); connect(this, SIGNAL(tokenReceived()), &m_server, SLOT(stop())); m_linked = true; } void OauthImplicit::unlink() { disconnect(this, nullptr, nullptr, nullptr); disconnect(&m_server, nullptr, nullptr, nullptr); m_linked = false; } void OauthImplicit::setVariables(QString authUrl, QString scope, QString state, QString redirectUri, QString clientId, QString accessType){ m_authUrl = QUrl(authUrl); m_scope = scope; m_accessType = accessType; m_state = state; m_redirectUri = redirectUri; m_clientId = clientId; } void OauthImplicit::authenticationNeededCallback() { QDesktopServices::openUrl(QUrl(m_authUrl.toString() + "?scope=" + m_scope + (m_accessType=="" ? "" : "&access_type=" + m_accessType) + "&response_type=token" + "&state=" + m_state + "&redirect_uri=" + m_redirectUri + "&client_id=" + m_clientId)); m_server.start(); } void OauthImplicit::ImplicitTokenReceived(const QMap response) { QString token = response.find("access_token").value(); QString scope = response.find("scope").value(); QString type = response.find("token_type").value(); int expiresIn = response.find("expires_in").value().toInt(); addToken(oauthToken(token, expiresIn, scope, type)); } /* * Class to perform the client credentials flow * */ OauthCredentials::OauthCredentials(QObject *parent) : OauthBase(parent){} void OauthCredentials::link() { connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); } void OauthCredentials::unlink() { disconnect(this, nullptr, nullptr, nullptr); } void OauthCredentials::setVariables(QString tokenUrl, QString scope, QString clientId, QString clientSecret){ m_tokenUrl = QUrl(tokenUrl); m_scope = scope; m_clientId = clientId; m_clientSecret = clientSecret; } void OauthCredentials::authenticationNeededCallback() { //create query with the required fields QUrlQuery postData; postData.addQueryItem("grant_type", "client_credentials"); postData.addQueryItem("client_id", m_clientId); postData.addQueryItem("client_secret", m_clientSecret); postData.addQueryItem("scope", m_scope); QNetworkAccessManager * manager = new QNetworkAccessManager(this); QNetworkRequest request(m_tokenUrl); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onFinish(QNetworkReply *))); manager->post(request, postData.query().toUtf8()); } /* * Class to perform the resource owner password flow * */ OauthPassword::OauthPassword(QObject *parent) : OauthBase(parent){} void OauthPassword::link() { connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); } void OauthPassword::unlink() { disconnect(this, nullptr, nullptr, nullptr); } void OauthPassword::setVariables(QString tokenUrl, QString scope, QString clientId, QString clientSecret, QString username, QString password){ m_tokenUrl = QUrl(tokenUrl); m_scope = scope; m_clientId = clientId; m_clientSecret = clientSecret; m_username = username; m_password = password; } void OauthPassword::authenticationNeededCallback() { //create query with the required fields QUrlQuery postData; postData.addQueryItem("grant_type", "password"); postData.addQueryItem("username", m_username); postData.addQueryItem("password", m_password); postData.addQueryItem("client_id", m_clientId); postData.addQueryItem("client_secret", m_clientSecret); postData.addQueryItem("scope", m_scope); QNetworkAccessManager * manager = new QNetworkAccessManager(this); QNetworkRequest request(m_tokenUrl); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onFinish(QNetworkReply *))); manager->post(request, postData.query().toUtf8()); } /* * Class that provides a simple reply server * */ ReplyServer::ReplyServer(QObject *parent) : QTcpServer(parent) { connect(this, SIGNAL(newConnection()), this, SLOT(onConnected())); m_reply ="you can close this window now!"; } void ReplyServer::start() { if(!listen(QHostAddress::Any, 9999)) { qDebug() << "Server could not start"; } else { qDebug() << "Server started!"; } } void ReplyServer::stop() { qDebug() << "Stopping the Server..."; QTcpServer::close(); } void ReplyServer::onConnected() { // need to grab the socket QTcpSocket *socket = nextPendingConnection(); connect(socket, SIGNAL(readyRead()), this, SLOT(read()), Qt::UniqueConnection); connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater())); } void ReplyServer::read() { QTcpSocket *socket = qobject_cast(sender()); if (!socket) { qDebug() << "No socket available"; return; } qDebug() << "Socket connected"; QTextStream os(socket); os.setAutoDetectUnicode(true); os << "HTTP/1.0 200 Ok\r\n" "Content-Type: text/html; charset=\"utf-8\"\r\n" "\r\n" <<"\ \ \ \ \ \

You can close this window now!

\ \ "; QByteArray data = socket->readLine(); QString splitGetLine = QString(data); splitGetLine.remove("GET"); splitGetLine.remove("HTTP/1.1"); splitGetLine.remove("\r\n"); splitGetLine.remove(" "); //prefix is needed to extract query params QUrl getTokenUrl("http://" + splitGetLine); QList< QPair > tokens; QUrlQuery query(getTokenUrl); tokens = query.queryItems(); QMap queryParams; for (auto tokenPair : tokens) { QString key = QUrl::fromPercentEncoding(QByteArray().append(tokenPair.first.trimmed().toLatin1())); QString value = QUrl::fromPercentEncoding(QByteArray().append(tokenPair.second.trimmed().toLatin1())); queryParams.insert(key, value); } if (!queryParams.contains("state")) { socket->close(); return; } socket->close(); Q_EMIT dataReceived(queryParams); } } // namespace test_namespace