From 15c6baceb8ed6a21a4a6a1e741b8c854ebecfb26 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 1 Aug 2020 18:57:21 +1200 Subject: [PATCH] Send OAuth2 username and tokens to domain server --- domain-server/src/DomainGatekeeper.cpp | 21 ++++++------- domain-server/src/DomainGatekeeper.h | 4 +-- .../networking/src/DomainAccountManager.cpp | 22 +++++++++++--- .../networking/src/DomainAccountManager.h | 10 ++++++- libraries/networking/src/NodeList.cpp | 30 ++++++++++++------- libraries/networking/src/NodeList.h | 2 ++ 6 files changed, 61 insertions(+), 28 deletions(-) diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index f41c20e245..a1581c26f1 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -95,7 +95,7 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointersecond); } else if (!STATICALLY_ASSIGNED_NODES.contains(nodeConnection.nodeType)) { QByteArray usernameSignature; - QByteArray domainUsernameSignature; + QString domainTokens; if (message->getBytesLeftToRead() > 0) { // read username from packet @@ -110,14 +110,14 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer> domainUsername; if (message->getBytesLeftToRead() > 0) { - // Read domain signature from packet. - packetStream >> domainUsernameSignature; + // Read domain tokens from packet. + packetStream >> domainTokens; } } } } - node = processAgentConnectRequest(nodeConnection, username, usernameSignature, domainUsername, domainUsernameSignature); + node = processAgentConnectRequest(nodeConnection, username, usernameSignature, domainUsername, domainTokens); } if (node) { @@ -452,7 +452,7 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect const QString& username, const QByteArray& usernameSignature, const QString& domainUsername, - const QByteArray& domainUsernameSignature) { + const QString& domainTokens) { auto limitedNodeList = DependencyManager::get(); @@ -502,17 +502,18 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect QString verifiedDomainUsername; QStringList verifiedDomainUserGroups; if (domainHasLogin() && !domainUsername.isEmpty()) { - if (domainUsernameSignature.isEmpty()) { + if (domainTokens.isEmpty()) { // User is attempting to prove their domain identity. // ####### TODO: OAuth2 corollary of metaverse code, above. - getDomainGroupMemberships(domainUsernameSignature); // Optimistically get started on group memberships. + // ####### TODO: Do the following now? Probably can't! + //getDomainGroupMemberships(domainUsername); // Optimistically get started on group memberships. #ifdef WANT_DEBUG qDebug() << "stalling login because we have no domain username-signature:" << domainUsername; #endif return SharedNodePointer(); - } else if (verifyDomainUserSignature(domainUsername, domainUsernameSignature, nodeConnection.senderSockAddr)) { + } else if (verifyDomainUserSignature(domainUsername, domainTokens, nodeConnection.senderSockAddr)) { // User's domain identity is confirmed. getDomainGroupMemberships(domainUsername); verifiedDomainUsername = domainUsername.toLower(); @@ -742,10 +743,10 @@ bool DomainGatekeeper::verifyUserSignature(const QString& username, } bool DomainGatekeeper::verifyDomainUserSignature(const QString& domainUsername, - const QByteArray& domainUsernameSignature, + const QString& domainTokens, const HifiSockAddr& senderSockAddr) { - // ####### TODO: Verify via domain OAuth2. + // ####### TODO: Verify response from domain OAuth2 request to WordPress, if it's arrived yet. bool success = true; if (success) { return true; diff --git a/domain-server/src/DomainGatekeeper.h b/domain-server/src/DomainGatekeeper.h index 99bd875457..0cb757a9ea 100644 --- a/domain-server/src/DomainGatekeeper.h +++ b/domain-server/src/DomainGatekeeper.h @@ -79,13 +79,13 @@ private: const QString& username, const QByteArray& usernameSignature, const QString& domainUsername, - const QByteArray& domainUsernameSignature); + const QString& domainTokens); SharedNodePointer addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection); bool verifyUserSignature(const QString& username, const QByteArray& usernameSignature, const HifiSockAddr& senderSockAddr); - bool verifyDomainUserSignature(const QString& domainUsername, const QByteArray& domainUsernameSignature, + bool verifyDomainUserSignature(const QString& domainUsername, const QString& domainUsernameSignature, const HifiSockAddr& senderSockAddr); bool isWithinMaxCapacity(); diff --git a/libraries/networking/src/DomainAccountManager.cpp b/libraries/networking/src/DomainAccountManager.cpp index d36f4b5f09..cb0b93232e 100644 --- a/libraries/networking/src/DomainAccountManager.cpp +++ b/libraries/networking/src/DomainAccountManager.cpp @@ -11,6 +11,8 @@ #include "DomainAccountManager.h" +// ####### TODO: Check that all #includes are still needed. + #include #include @@ -43,7 +45,12 @@ Setting::Handle domainAccessTokenExpiresIn {"private/domainAccessTokenExpir Setting::Handle domainAccessTokenType {"private/domainAccessTokenType", "" }; -DomainAccountManager::DomainAccountManager() { +DomainAccountManager::DomainAccountManager() : + _authURL(), + _username(), + _access_token(), + _refresh_token() +{ connect(this, &DomainAccountManager::loginComplete, this, &DomainAccountManager::sendInterfaceAccessTokenToServer); } @@ -57,8 +64,11 @@ void DomainAccountManager::setAuthURL(const QUrl& authURL) { } } -void DomainAccountManager::requestAccessToken(const QString& login, const QString& password) { +void DomainAccountManager::requestAccessToken(const QString& username, const QString& password) { + _username = username; + _access_token = ""; + _refresh_token = ""; QNetworkRequest request; @@ -69,7 +79,7 @@ void DomainAccountManager::requestAccessToken(const QString& login, const QStrin QByteArray formData; formData.append("grant_type=password&"); - formData.append("username=" + QUrl::toPercentEncoding(login) + "&"); + formData.append("username=" + QUrl::toPercentEncoding(username) + "&"); formData.append("password=" + QUrl::toPercentEncoding(password) + "&"); formData.append("scope=" + DOMAIN_ACCOUNT_MANAGER_REQUESTED_SCOPE); // ####### TODO: Include state? @@ -122,7 +132,7 @@ void DomainAccountManager::requestAccessTokenFinished() { } void DomainAccountManager::sendInterfaceAccessTokenToServer() { - // TODO: Send successful packet to the domain-server. + emit newTokens(); } bool DomainAccountManager::accessTokenIsExpired() { @@ -159,7 +169,11 @@ bool DomainAccountManager::hasValidAccessToken() { } void DomainAccountManager::setAccessTokenFromJSON(const QJsonObject& jsonObject) { + _access_token = jsonObject["access_token"].toString(); + _refresh_token = jsonObject["refresh_token"].toString(); + // ####### TODO: Enable and use these. + // ####### TODO: Protect these per AccountManager? /* domainAccessToken.set(jsonObject["access_token"].toString()); domainAccessRefreshToken.set(jsonObject["refresh_token"].toString()); diff --git a/libraries/networking/src/DomainAccountManager.h b/libraries/networking/src/DomainAccountManager.h index eb0f2659dd..08b625a246 100644 --- a/libraries/networking/src/DomainAccountManager.h +++ b/libraries/networking/src/DomainAccountManager.h @@ -25,10 +25,14 @@ public: void setAuthURL(const QUrl& authURL); + QString getUsername() { return _username; } + QString getAccessToken() { return _access_token; } + QString getRefreshToken() { return _refresh_token; } + Q_INVOKABLE bool checkAndSignalForAccessToken(); public slots: - void requestAccessToken(const QString& login, const QString& password); + void requestAccessToken(const QString& username, const QString& password); void requestAccessTokenFinished(); signals: @@ -36,6 +40,7 @@ signals: void loginComplete(const QUrl& authURL); void loginFailed(); void logoutComplete(); + void newTokens(); private slots: @@ -46,6 +51,9 @@ private: void sendInterfaceAccessTokenToServer(); QUrl _authURL; + QString _username; // ####### TODO: Store elsewhere? + QString _access_token; // ####... "" + QString _refresh_token; // ####... "" }; #endif // hifi_DomainAccountManager_h diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 262ad0d2a4..16eba6c6a1 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -34,6 +34,7 @@ #include "AddressManager.h" #include "Assignment.h" #include "AudioHelpers.h" +#include "DomainAccountManager.h" #include "HifiSockAddr.h" #include "FingerprintUtils.h" @@ -104,6 +105,13 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort) // clear our NodeList when logout is requested connect(accountManager.data(), &AccountManager::logoutComplete , this, [this]{ reset("Logged out"); }); + // Only used in Interface. + auto domainAccountManager = DependencyManager::get(); + if (domainAccountManager) { + _hasDomainAccountManager = true; + connect(domainAccountManager.data(), &DomainAccountManager::newTokens, this, &NodeList::sendDomainServerCheckIn); + } + // anytime we get a new node we will want to attempt to punch to it connect(this, &LimitedNodeList::nodeAdded, this, &NodeList::startNodeHolePunch); connect(this, &LimitedNodeList::nodeSocketUpdated, this, &NodeList::startNodeHolePunch); @@ -468,6 +476,7 @@ void NodeList::sendDomainServerCheckIn() { packetStream << _ownerType.load() << publicSockAddr << localSockAddr << _nodeTypesOfInterest.toList(); packetStream << DependencyManager::get()->getPlaceName(); + // ####### TODO: Also send if need to send new domainLogin data? if (!domainIsConnected) { DataServerAccountInfo& accountInfo = accountManager->getAccountInfo(); packetStream << accountInfo.getUsername(); @@ -477,21 +486,20 @@ void NodeList::sendDomainServerCheckIn() { const QByteArray& usernameSignature = accountManager->getAccountInfo().getUsernameSignature(connectionToken); packetStream << usernameSignature; } else { - packetStream << QString(""); // Placeholder in case have domainUsername. + // ####### TODO: Only append if are going to send domain username? + packetStream << QString(""); // Placeholder in case have domain username. } } else { - packetStream << QString(""); // Placeholder in case have domainUsername. + // ####### TODO: Only append if are going to send domainUsername? + packetStream << QString("") << QString(""); // Placeholders in case have domain username. } - // ####### TODO: Send domain username and signature if domain has these and aren't logged in. - // ####### If get into difficulties, could perhaps send domain's username and signature instead of metaverse. - bool domainLoginIsConnected = false; - if (!domainLoginIsConnected) { - if (false) { // ####### For testing, false causes user to be considered "not logged in". - packetStream << QString("a@b.c"); - if (true) { // ####### For testing, false is unhandled at this stage. - packetStream << QString("signature"); // #######: Consider "logged in" if this is sent during testing. - } + // Send domain domain login data from Interface to domain server. + if (_hasDomainAccountManager) { + auto domainAccountManager = DependencyManager::get(); + if (!domainAccountManager->getUsername().isEmpty()) { + packetStream << domainAccountManager->getUsername(); + packetStream << (domainAccountManager->getAccessToken() + ":" + domainAccountManager->getRefreshToken()); } } diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index c377ea89cb..4954c53c84 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -196,6 +196,8 @@ private: #if (PR_BUILD || DEV_BUILD) bool _shouldSendNewerVersion { false }; #endif + + bool _hasDomainAccountManager { false }; }; #endif // hifi_NodeList_h