mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 19:52:26 +02:00
pipe username signature requirement through to DomainHandler
This commit is contained in:
parent
0d2b1e361c
commit
31df339565
8 changed files with 17 additions and 234 deletions
|
@ -64,7 +64,7 @@
|
||||||
"name": "allowed_users",
|
"name": "allowed_users",
|
||||||
"type": "table",
|
"type": "table",
|
||||||
"label": "Allowed Users",
|
"label": "Allowed Users",
|
||||||
"help": "A list of usernames for the High Fidelity users you want to allow into your domain.<br>If the list is blank, all users are allowed to connect.<br>You are always allowed to connect to your domain directly from your local machine.",
|
"help": "List the High Fidelity names for people you want to be able to connect to this domain.<br/>An empty list means everyone.<br/>You can always connect from this machine.",
|
||||||
"numbered": false,
|
"numbered": false,
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -276,13 +276,15 @@ function makeTable(setting, setting_name, setting_value) {
|
||||||
html += "<td class='" + Settings.DATA_COL_CLASS + "'>"
|
html += "<td class='" + Settings.DATA_COL_CLASS + "'>"
|
||||||
|
|
||||||
if (isArray) {
|
if (isArray) {
|
||||||
colIsArray = _.isArray(row)
|
rowIsObject = setting.columns.length > 1
|
||||||
colValue = colIsArray ? row : row[col.name]
|
colValue = rowIsObject ? row[col.name] : row
|
||||||
html += colValue
|
html += colValue
|
||||||
|
|
||||||
// for arrays we add a hidden input to this td so that values can be posted appropriately
|
// for arrays we add a hidden input to this td so that values can be posted appropriately
|
||||||
html += "<input type='hidden' name='" + setting_name + "[" + indexOrName + "]"
|
html += "<input type='hidden' name='" + setting_name + "[" + indexOrName + "]"
|
||||||
+ (colIsArray ? "" : "." + col.name) + "' value='" + colValue + "'/>"
|
+ (rowIsObject ? "." + col.name : "") + "' value='" + colValue + "'/>"
|
||||||
|
|
||||||
|
console.log(html)
|
||||||
} else if (row.hasOwnProperty(col.name)) {
|
} else if (row.hasOwnProperty(col.name)) {
|
||||||
html += row[col.name]
|
html += row[col.name]
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,6 @@
|
||||||
#include "scripting/WindowScriptingInterface.h"
|
#include "scripting/WindowScriptingInterface.h"
|
||||||
|
|
||||||
#include "ui/InfoView.h"
|
#include "ui/InfoView.h"
|
||||||
#include "ui/OAuthWebViewHandler.h"
|
|
||||||
#include "ui/Snapshot.h"
|
#include "ui/Snapshot.h"
|
||||||
#include "ui/Stats.h"
|
#include "ui/Stats.h"
|
||||||
#include "ui/TextRenderer.h"
|
#include "ui/TextRenderer.h"
|
||||||
|
@ -219,10 +218,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
listenPort = atoi(portStr);
|
listenPort = atoi(portStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// call the OAuthWebviewHandler static getter so that its instance lives in our thread
|
|
||||||
// make sure it is ready before the NodeList might need it
|
|
||||||
OAuthWebViewHandler::getInstance();
|
|
||||||
|
|
||||||
// start the nodeThread so its event loop is running
|
// start the nodeThread so its event loop is running
|
||||||
_nodeThread->start();
|
_nodeThread->start();
|
||||||
|
|
||||||
|
@ -3522,9 +3517,6 @@ void Application::domainChanged(const QString& domainHostname) {
|
||||||
|
|
||||||
// reset the voxels renderer
|
// reset the voxels renderer
|
||||||
_voxels.killLocalVoxels();
|
_voxels.killLocalVoxels();
|
||||||
|
|
||||||
// reset the auth URL for OAuth web view handler
|
|
||||||
OAuthWebViewHandler::getInstance().clearLastAuthorizationURL();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::connectedToDomain(const QString& hostname) {
|
void Application::connectedToDomain(const QString& hostname) {
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "Menu.h"
|
#include "Menu.h"
|
||||||
#include "ui/OAuthWebViewHandler.h"
|
|
||||||
|
|
||||||
#include "DatagramProcessor.h"
|
#include "DatagramProcessor.h"
|
||||||
|
|
||||||
|
@ -136,16 +135,11 @@ void DatagramProcessor::processDatagrams() {
|
||||||
application->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(incomingPacket.size());
|
application->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(incomingPacket.size());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PacketTypeDomainOAuthRequest: {
|
case PacketTypeDomainUsernameRequest: {
|
||||||
QDataStream readStream(incomingPacket);
|
// flag the domain handler so it knows to send a username signature on next check-in
|
||||||
readStream.skipRawData(numBytesForPacketHeader(incomingPacket));
|
// and then make it send that next check in
|
||||||
|
nodeList->getDomainHandler().setRequiresUsernameSignature(true);
|
||||||
QUrl authorizationURL;
|
nodeList->sendDomainServerCheckIn();
|
||||||
readStream >> authorizationURL;
|
|
||||||
|
|
||||||
QMetaObject::invokeMethod(&OAuthWebViewHandler::getInstance(), "displayWebviewForAuthorizationURL",
|
|
||||||
Q_ARG(const QUrl&, authorizationURL));
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PacketTypeMuteEnvironment: {
|
case PacketTypeMuteEnvironment: {
|
||||||
|
|
|
@ -1,168 +0,0 @@
|
||||||
//
|
|
||||||
// OAuthWebViewHandler.cpp
|
|
||||||
// interface/src/ui
|
|
||||||
//
|
|
||||||
// Created by Stephen Birarda on 2014-05-01.
|
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <qwebview.h>
|
|
||||||
#include <qurlquery.h>
|
|
||||||
|
|
||||||
#include <AccountManager.h>
|
|
||||||
|
|
||||||
#include "Application.h"
|
|
||||||
|
|
||||||
#include "OAuthWebViewHandler.h"
|
|
||||||
|
|
||||||
OAuthWebViewHandler& OAuthWebViewHandler::getInstance() {
|
|
||||||
static OAuthWebViewHandler sharedInstance;
|
|
||||||
return sharedInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
OAuthWebViewHandler::OAuthWebViewHandler() :
|
|
||||||
_activeWebView(NULL),
|
|
||||||
_webViewRedisplayTimer(),
|
|
||||||
_lastAuthorizationURL()
|
|
||||||
{
|
|
||||||
addHighFidelityRootCAToSSLConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
const char HIGH_FIDELITY_CA[] = "-----BEGIN CERTIFICATE-----\n"
|
|
||||||
"MIID6TCCA1KgAwIBAgIJANlfRkRD9A8bMA0GCSqGSIb3DQEBBQUAMIGqMQswCQYD\n"
|
|
||||||
"VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j\n"
|
|
||||||
"aXNjbzEbMBkGA1UEChMSSGlnaCBGaWRlbGl0eSwgSW5jMRMwEQYDVQQLEwpPcGVy\n"
|
|
||||||
"YXRpb25zMRgwFgYDVQQDEw9oaWdoZmlkZWxpdHkuaW8xIjAgBgkqhkiG9w0BCQEW\n"
|
|
||||||
"E29wc0BoaWdoZmlkZWxpdHkuaW8wHhcNMTQwMzI4MjIzMzM1WhcNMjQwMzI1MjIz\n"
|
|
||||||
"MzM1WjCBqjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNV\n"
|
|
||||||
"BAcTDVNhbiBGcmFuY2lzY28xGzAZBgNVBAoTEkhpZ2ggRmlkZWxpdHksIEluYzET\n"
|
|
||||||
"MBEGA1UECxMKT3BlcmF0aW9uczEYMBYGA1UEAxMPaGlnaGZpZGVsaXR5LmlvMSIw\n"
|
|
||||||
"IAYJKoZIhvcNAQkBFhNvcHNAaGlnaGZpZGVsaXR5LmlvMIGfMA0GCSqGSIb3DQEB\n"
|
|
||||||
"AQUAA4GNADCBiQKBgQDyo1euYiPPEdnvDZnIjWrrP230qUKMSj8SWoIkbTJF2hE8\n"
|
|
||||||
"2eP3YOgbgSGBzZ8EJBxIOuNmj9g9Eg6691hIKFqy5W0BXO38P04Gg+pVBvpHFGBi\n"
|
|
||||||
"wpqGbfsjaUDuYmBeJRcMO0XYkLCRQG+lAQNHoFDdItWAJfC3FwtP3OCDnz8cNwID\n"
|
|
||||||
"AQABo4IBEzCCAQ8wHQYDVR0OBBYEFCSv2kmiGg6VFMnxXzLDNP304cPAMIHfBgNV\n"
|
|
||||||
"HSMEgdcwgdSAFCSv2kmiGg6VFMnxXzLDNP304cPAoYGwpIGtMIGqMQswCQYDVQQG\n"
|
|
||||||
"EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNj\n"
|
|
||||||
"bzEbMBkGA1UEChMSSGlnaCBGaWRlbGl0eSwgSW5jMRMwEQYDVQQLEwpPcGVyYXRp\n"
|
|
||||||
"b25zMRgwFgYDVQQDEw9oaWdoZmlkZWxpdHkuaW8xIjAgBgkqhkiG9w0BCQEWE29w\n"
|
|
||||||
"c0BoaWdoZmlkZWxpdHkuaW+CCQDZX0ZEQ/QPGzAMBgNVHRMEBTADAQH/MA0GCSqG\n"
|
|
||||||
"SIb3DQEBBQUAA4GBAEkQl3p+lH5vuoCNgyfa67nL0MsBEt+5RSBOgjwCjjASjzou\n"
|
|
||||||
"FTv5w0he2OypgMQb8i/BYtS1lJSFqjPJcSM1Salzrm3xDOK5pOXJ7h6SQLPDVEyf\n"
|
|
||||||
"Hy2/9d/to+99+SOUlvfzfgycgjOc+s/AV7Y+GBd7uzGxUdrN4egCZW1F6/mH\n"
|
|
||||||
"-----END CERTIFICATE-----\n";
|
|
||||||
|
|
||||||
void OAuthWebViewHandler::addHighFidelityRootCAToSSLConfig() {
|
|
||||||
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
|
|
||||||
|
|
||||||
// add the High Fidelity root CA to the list of trusted CA certificates
|
|
||||||
QByteArray highFidelityCACertificate(HIGH_FIDELITY_CA, sizeof(HIGH_FIDELITY_CA));
|
|
||||||
sslConfig.setCaCertificates(sslConfig.caCertificates() + QSslCertificate::fromData(highFidelityCACertificate));
|
|
||||||
|
|
||||||
// set the modified configuration
|
|
||||||
QSslConfiguration::setDefaultConfiguration(sslConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int WEB_VIEW_REDISPLAY_ELAPSED_MSECS = 5 * 1000;
|
|
||||||
|
|
||||||
void OAuthWebViewHandler::displayWebviewForAuthorizationURL(const QUrl& authorizationURL) {
|
|
||||||
if (!_activeWebView) {
|
|
||||||
|
|
||||||
if (!_lastAuthorizationURL.isEmpty()) {
|
|
||||||
if (_lastAuthorizationURL.host() == authorizationURL.host()
|
|
||||||
&& _webViewRedisplayTimer.elapsed() < WEB_VIEW_REDISPLAY_ELAPSED_MSECS) {
|
|
||||||
// this would be re-displaying an OAuth dialog for the same auth URL inside of the redisplay ms
|
|
||||||
// so return instead
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_lastAuthorizationURL = authorizationURL;
|
|
||||||
|
|
||||||
_activeWebView = new QWebView;
|
|
||||||
|
|
||||||
// keep the window on top and delete it when it closes
|
|
||||||
_activeWebView->setWindowFlags(Qt::Sheet);
|
|
||||||
_activeWebView->setAttribute(Qt::WA_DeleteOnClose);
|
|
||||||
|
|
||||||
qDebug() << "Displaying QWebView for OAuth authorization at" << authorizationURL.toString();
|
|
||||||
|
|
||||||
AccountManager& accountManager = AccountManager::getInstance();
|
|
||||||
|
|
||||||
QUrl codedAuthorizationURL = authorizationURL;
|
|
||||||
|
|
||||||
// check if we have an access token for this host - if so we can bypass login by adding it to the URL
|
|
||||||
if (accountManager.getAuthURL().host() == authorizationURL.host()
|
|
||||||
&& accountManager.hasValidAccessToken()) {
|
|
||||||
|
|
||||||
const QString ACCESS_TOKEN_QUERY_STRING_KEY = "access_token";
|
|
||||||
|
|
||||||
QUrlQuery authQuery(codedAuthorizationURL);
|
|
||||||
authQuery.addQueryItem(ACCESS_TOKEN_QUERY_STRING_KEY, accountManager.getAccountInfo().getAccessToken().token);
|
|
||||||
|
|
||||||
codedAuthorizationURL.setQuery(authQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(_activeWebView.data(), &QWebView::urlChanged, this, &OAuthWebViewHandler::handleURLChanged);
|
|
||||||
|
|
||||||
_activeWebView->load(codedAuthorizationURL);
|
|
||||||
|
|
||||||
connect(_activeWebView->page()->networkAccessManager(), &QNetworkAccessManager::sslErrors,
|
|
||||||
this, &OAuthWebViewHandler::handleSSLErrors);
|
|
||||||
connect(_activeWebView->page()->networkAccessManager(), &QNetworkAccessManager::finished,
|
|
||||||
this, &OAuthWebViewHandler::handleReplyFinished);
|
|
||||||
connect(_activeWebView.data(), &QWebView::loadFinished, this, &OAuthWebViewHandler::handleLoadFinished);
|
|
||||||
|
|
||||||
// connect to the destroyed signal so after the web view closes we can start a timer
|
|
||||||
connect(_activeWebView.data(), &QWebView::destroyed, this, &OAuthWebViewHandler::handleWebViewDestroyed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OAuthWebViewHandler::handleSSLErrors(QNetworkReply* networkReply, const QList<QSslError>& errorList) {
|
|
||||||
qDebug() << "SSL Errors:" << errorList;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OAuthWebViewHandler::handleLoadFinished(bool success) {
|
|
||||||
if (success && _activeWebView->url().host() == NodeList::getInstance()->getDomainHandler().getHostname()) {
|
|
||||||
qDebug() << "OAuth authorization code passed successfully to domain-server.";
|
|
||||||
|
|
||||||
// grab the UUID that is set as the state parameter in the auth URL
|
|
||||||
// since that is our new session UUID
|
|
||||||
QUrlQuery authQuery(_activeWebView->url());
|
|
||||||
|
|
||||||
const QString AUTH_STATE_QUERY_KEY = "state";
|
|
||||||
NodeList::getInstance()->setSessionUUID(QUuid(authQuery.queryItemValue(AUTH_STATE_QUERY_KEY)));
|
|
||||||
|
|
||||||
_activeWebView->close();
|
|
||||||
_activeWebView = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OAuthWebViewHandler::handleReplyFinished(QNetworkReply* reply) {
|
|
||||||
if (_activeWebView && reply->error() != QNetworkReply::NoError) {
|
|
||||||
qDebug() << "Error loading" << reply->url() << "-" << reply->errorString();
|
|
||||||
_activeWebView->close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OAuthWebViewHandler::handleWebViewDestroyed(QObject* destroyedObject) {
|
|
||||||
_webViewRedisplayTimer.restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OAuthWebViewHandler::handleURLChanged(const QUrl& url) {
|
|
||||||
// check if this is the authorization screen - if it is then we need to show the OAuthWebViewHandler
|
|
||||||
const QString ACCESS_TOKEN_URL_REGEX_STRING = "redirect_uri=[\\w:\\/\\.]+&access_token=";
|
|
||||||
QRegExp accessTokenRegex(ACCESS_TOKEN_URL_REGEX_STRING);
|
|
||||||
|
|
||||||
if (accessTokenRegex.indexIn(url.toString()) != -1) {
|
|
||||||
_activeWebView->show();
|
|
||||||
} else if (url.toString() == DEFAULT_NODE_AUTH_URL.toString() + "/login") {
|
|
||||||
// this is a login request - we're going to close the webview and signal the AccountManager that we need a login
|
|
||||||
qDebug() << "data-server replied with login request. Signalling that login is required to proceed with OAuth.";
|
|
||||||
_activeWebView->close();
|
|
||||||
AccountManager::getInstance().checkAndSignalForAccessToken();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
//
|
|
||||||
// OAuthWebviewHandler.h
|
|
||||||
// interface/src/ui
|
|
||||||
//
|
|
||||||
// Created by Stephen Birarda on 2014-05-01.
|
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef hifi_OAuthWebviewHandler_h
|
|
||||||
#define hifi_OAuthWebviewHandler_h
|
|
||||||
|
|
||||||
#include <QtCore/QUrl>
|
|
||||||
|
|
||||||
class QWebView;
|
|
||||||
|
|
||||||
class OAuthWebViewHandler : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
OAuthWebViewHandler();
|
|
||||||
static OAuthWebViewHandler& getInstance();
|
|
||||||
static void addHighFidelityRootCAToSSLConfig();
|
|
||||||
|
|
||||||
void clearLastAuthorizationURL() { _lastAuthorizationURL = QUrl(); }
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void displayWebviewForAuthorizationURL(const QUrl& authorizationURL);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void handleSSLErrors(QNetworkReply* networkReply, const QList<QSslError>& errorList);
|
|
||||||
void handleLoadFinished(bool success);
|
|
||||||
void handleReplyFinished(QNetworkReply* reply);
|
|
||||||
void handleWebViewDestroyed(QObject* destroyedObject);
|
|
||||||
void handleURLChanged(const QUrl& url);
|
|
||||||
private:
|
|
||||||
QPointer<QWebView> _activeWebView;
|
|
||||||
QElapsedTimer _webViewRedisplayTimer;
|
|
||||||
QUrl _lastAuthorizationURL;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // hifi_OAuthWebviewHandler_h
|
|
|
@ -30,6 +30,7 @@ DomainHandler::DomainHandler(QObject* parent) :
|
||||||
_iceServerSockAddr(),
|
_iceServerSockAddr(),
|
||||||
_icePeer(),
|
_icePeer(),
|
||||||
_isConnected(false),
|
_isConnected(false),
|
||||||
|
_requiresUsernameSignature(false),
|
||||||
_handshakeTimer(NULL),
|
_handshakeTimer(NULL),
|
||||||
_settingsObject(),
|
_settingsObject(),
|
||||||
_failedSettingsRequests(0)
|
_failedSettingsRequests(0)
|
||||||
|
@ -48,6 +49,7 @@ void DomainHandler::clearConnectionInfo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
_isConnected = false;
|
_isConnected = false;
|
||||||
|
_requiresUsernameSignature = false;
|
||||||
|
|
||||||
emit disconnectedFromDomain();
|
emit disconnectedFromDomain();
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,9 @@ public:
|
||||||
bool isConnected() const { return _isConnected; }
|
bool isConnected() const { return _isConnected; }
|
||||||
void setIsConnected(bool isConnected);
|
void setIsConnected(bool isConnected);
|
||||||
|
|
||||||
|
bool requiresUsernameSignature() const { return _requiresUsernameSignature; }
|
||||||
|
void setRequiresUsernameSignature(bool requiresUsernameSignature) { _requiresUsernameSignature = requiresUsernameSignature; }
|
||||||
|
|
||||||
bool hasSettings() const { return !_settingsObject.isEmpty(); }
|
bool hasSettings() const { return !_settingsObject.isEmpty(); }
|
||||||
void requestDomainSettings();
|
void requestDomainSettings();
|
||||||
const QJsonObject& getSettingsObject() const { return _settingsObject; }
|
const QJsonObject& getSettingsObject() const { return _settingsObject; }
|
||||||
|
@ -104,6 +107,7 @@ private:
|
||||||
HifiSockAddr _iceServerSockAddr;
|
HifiSockAddr _iceServerSockAddr;
|
||||||
NetworkPeer _icePeer;
|
NetworkPeer _icePeer;
|
||||||
bool _isConnected;
|
bool _isConnected;
|
||||||
|
bool _requiresUsernameSignature;
|
||||||
QTimer* _handshakeTimer;
|
QTimer* _handshakeTimer;
|
||||||
QJsonObject _settingsObject;
|
QJsonObject _settingsObject;
|
||||||
int _failedSettingsRequests;
|
int _failedSettingsRequests;
|
||||||
|
|
Loading…
Reference in a new issue