diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8bbbcc8f4b..ee0f5ec9e0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -260,6 +260,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : QNetworkDiskCache* cache = new QNetworkDiskCache(_networkAccessManager); cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache"); _networkAccessManager->setCache(cache); + + // give our AccountManager access to the single QNetworkAccessManager + AccountManager::getInstance().setNetworkAccessManager(_networkAccessManager); _window->setCentralWidget(_glWidget); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 709ae5d4e8..07d4cc14a8 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include "Application.h" @@ -742,18 +743,34 @@ void Menu::loginForCurrentDomain() { } void Menu::showLoginForRootURL(const QUrl& rootURL) { - QInputDialog loginDialog(Application::getInstance()->getWindow()); + QDialog loginDialog(Application::getInstance()->getWindow()); loginDialog.setWindowTitle("Login"); - loginDialog.setLabelText("Username:"); - QString username = QString(); - loginDialog.setTextValue(username); - loginDialog.setWindowFlags(Qt::Sheet); - loginDialog.resize(loginDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, loginDialog.size().height()); + + QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); + loginDialog.setLayout(layout); + + QFormLayout* form = new QFormLayout(); + layout->addLayout(form, 1); + + QLineEdit* usernameLineEdit = new QLineEdit(); + usernameLineEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH); + form->addRow("Username:", usernameLineEdit); + + QLineEdit* passwordLineEdit = new QLineEdit(); + passwordLineEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH); + passwordLineEdit->setEchoMode(QLineEdit::Password); + form->addRow("Password:", passwordLineEdit); + + QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + loginDialog.connect(buttons, SIGNAL(accepted()), SLOT(accept())); + loginDialog.connect(buttons, SIGNAL(rejected()), SLOT(reject())); + layout->addWidget(buttons); int dialogReturn = loginDialog.exec(); - if (dialogReturn == QDialog::Accepted && !loginDialog.textValue().isEmpty() && loginDialog.textValue() != username) { - // there has been a username change + if (dialogReturn == QDialog::Accepted && !usernameLineEdit->text().isEmpty() && !passwordLineEdit->text().isEmpty()) { + // attempt to get an access token given this username and password + AccountManager::getInstance().requestAccessToken(rootURL, usernameLineEdit->text(), passwordLineEdit->text()); } sendFakeEnterEvent(); @@ -764,9 +781,10 @@ void Menu::editPreferences() { QDialog dialog(applicationInstance->getWindow()); dialog.setWindowTitle("Interface Preferences"); + QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); dialog.setLayout(layout); - + QFormLayout* form = new QFormLayout(); layout->addLayout(form, 1); diff --git a/libraries/shared/src/AccountManager.cpp b/libraries/shared/src/AccountManager.cpp index 861592df27..4e83fad0ed 100644 --- a/libraries/shared/src/AccountManager.cpp +++ b/libraries/shared/src/AccountManager.cpp @@ -7,7 +7,11 @@ // #include +#include +#include #include +#include +#include #include "PacketHeaders.h" @@ -37,4 +41,58 @@ bool AccountManager::hasValidAccessTokenForRootURL(const QUrl &rootURL) { } else { return true; } +} + +const QString OAUTH_CLIENT_ID_FOR_DEFAULT_ROOT_URL = "12b7b18e7b8c118707b84ff0735e57a4473b5b0577c2af44734f02e08d02829c"; + +void AccountManager::requestAccessToken(const QUrl& rootURL, const QString& username, const QString& password) { + if (_networkAccessManager) { + QNetworkRequest request; + + QUrl grantURL = rootURL; + grantURL.setPath("/oauth/token"); + + QByteArray postData; + postData.append("client_id=12b7b18e7b8c118707b84ff0735e57a4473b5b0577c2af44734f02e08d02829c &"); + postData.append("grant_type=password&"); + postData.append("username=" + username + "&"); + postData.append("password=" + password); + + request.setUrl(grantURL); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + + QNetworkReply* requestReply = _networkAccessManager->post(request, postData); + connect(requestReply, &QNetworkReply::finished, this, &AccountManager::requestFinished); + connect(requestReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(requestError(QNetworkReply::NetworkError))); + } +} + +void AccountManager::requestFinished() { + QNetworkReply* requestReply = reinterpret_cast(sender()); + + QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll()); + const QJsonObject& rootObject = jsonResponse.object(); + + if (!rootObject.contains("error")) { + // construct an OAuthAccessToken from the json object + + if (!rootObject.contains("access_token") || !rootObject.contains("expires_in") + || !rootObject.contains("token_type")) { + // TODO: error handling - malformed token response + qDebug() << "Received a response for password grant that is missing one or more expected values."; + } else { + // clear the path from the response URL so we have the right root URL for this access token + QUrl rootURL = requestReply->url(); + rootURL.setPath(""); + + _accessTokens.insert(requestReply->url(), OAuthAccessToken(rootObject)); + } + } else { + // TODO: error handling + qDebug() << "Error in response for password grant -" << rootObject["error_description"].toString(); + } +} + +void AccountManager::requestError(QNetworkReply::NetworkError error) { + } \ No newline at end of file diff --git a/libraries/shared/src/AccountManager.h b/libraries/shared/src/AccountManager.h index fd498b2a91..8039cc7dbe 100644 --- a/libraries/shared/src/AccountManager.h +++ b/libraries/shared/src/AccountManager.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "OAuthAccessToken.h" @@ -23,10 +24,15 @@ public: bool hasValidAccessTokenForRootURL(const QUrl& rootURL); + void requestAccessToken(const QUrl& rootURL, const QString& username, const QString& password); + const QString& getUsername() const { return _username; } void setUsername(const QString& username) { _username = username; } void setNetworkAccessManager(QNetworkAccessManager* networkAccessManager) { _networkAccessManager = networkAccessManager; } +public slots: + void requestFinished(); + void requestError(QNetworkReply::NetworkError error); signals: void authenticationRequiredForRootURL(const QUrl& rootURL); private: diff --git a/libraries/shared/src/DomainInfo.cpp b/libraries/shared/src/DomainInfo.cpp index f1831f240b..69651231a5 100644 --- a/libraries/shared/src/DomainInfo.cpp +++ b/libraries/shared/src/DomainInfo.cpp @@ -52,7 +52,7 @@ void DomainInfo::setHostname(const QString& hostname) { // re-set the sock addr to null and fire off a lookup of the IP address for this domain-server's hostname qDebug("Looking up DS hostname %s.", _hostname.toLocal8Bit().constData()); - QHostInfo::lookupHost(_hostname, this, SLOT(completedHostnameLookup)); + QHostInfo::lookupHost(_hostname, this, SLOT(completedHostnameLookup(const QHostInfo&))); emit hostnameChanged(_hostname); } diff --git a/libraries/shared/src/OAuthAccessToken.cpp b/libraries/shared/src/OAuthAccessToken.cpp index add01caf1f..430ac0f20e 100644 --- a/libraries/shared/src/OAuthAccessToken.cpp +++ b/libraries/shared/src/OAuthAccessToken.cpp @@ -6,6 +6,8 @@ // Copyright (c) 2014 HighFidelity, Inc. All rights reserved. // +#include + #include "OAuthAccessToken.h" OAuthAccessToken::OAuthAccessToken() : @@ -17,6 +19,14 @@ OAuthAccessToken::OAuthAccessToken() : } +OAuthAccessToken::OAuthAccessToken(const QJsonObject& jsonObject) : + token(jsonObject["access_token"].toString()), + refreshToken(jsonObject["refresh_token"].toString()), + tokenType(jsonObject["token_type"].toString()) +{ + qDebug() << "the refresh token is" << refreshToken; +} + OAuthAccessToken::OAuthAccessToken(const OAuthAccessToken& otherToken) { token = otherToken.token; refreshToken = otherToken.refreshToken; diff --git a/libraries/shared/src/OAuthAccessToken.h b/libraries/shared/src/OAuthAccessToken.h index 7dff5416d5..a7fd7fed41 100644 --- a/libraries/shared/src/OAuthAccessToken.h +++ b/libraries/shared/src/OAuthAccessToken.h @@ -11,11 +11,13 @@ #include #include +#include class OAuthAccessToken : public QObject { Q_OBJECT public: OAuthAccessToken(); + OAuthAccessToken(const QJsonObject& jsonObject); OAuthAccessToken(const OAuthAccessToken& otherToken); OAuthAccessToken& operator=(const OAuthAccessToken& otherToken);