more work on authentication, show login window when domain asks

This commit is contained in:
Stephen Birarda 2014-02-18 13:21:32 -08:00
parent c762b92e5a
commit 8a0136efe1
13 changed files with 165 additions and 35 deletions

View file

@ -41,7 +41,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
_staticAssignmentHash(),
_assignmentQueue(),
_hasCompletedRestartHold(false),
_nodeAuthenticationHostname(DEFAULT_NODE_AUTH_URL)
_nodeAuthenticationURL(DEFAULT_NODE_AUTH_URL)
{
const char CUSTOM_PORT_OPTION[] = "-p";
const char* customPortString = getCmdOption(argc, (const char**) argv, CUSTOM_PORT_OPTION);
@ -65,9 +65,9 @@ DomainServer::DomainServer(int argc, char* argv[]) :
const QString NO_AUTH_OPTION = "--noAuth";
const QString CUSTOM_AUTH_OPTION = "--customAuth";
if ((argumentIndex = argumentList.indexOf(NO_AUTH_OPTION) != -1)) {
_nodeAuthenticationHostname = QUrl();
_nodeAuthenticationURL = QUrl();
} else if ((argumentIndex = argumentList.indexOf(CUSTOM_AUTH_OPTION)) != -1) {
_nodeAuthenticationHostname = QUrl(argumentList.value(argumentIndex + 1));
_nodeAuthenticationURL = QUrl(argumentList.value(argumentIndex + 1));
}
NodeList* nodeList = NodeList::createInstance(NodeType::DomainServer, domainServerPort);
@ -254,14 +254,14 @@ void DomainServer::readAvailableDatagrams() {
QUuid nodeUUID = uuidFromPacketHeader(receivedPacket);
if (!_nodeAuthenticationHostname.isEmpty() &&
if (!_nodeAuthenticationURL.isEmpty() &&
(nodeUUID.isNull() || !nodeList->nodeWithUUID(nodeUUID))) {
// this is a node we do not recognize and we need authentication - ask them to do so
// by providing them the hostname they should authenticate with
QByteArray authenticationRequestPacket = byteArrayWithPopluatedHeader(PacketTypeDomainServerAuthRequest);
QDataStream authPacketStream(&authenticationRequestPacket, QIODevice::Append);
authPacketStream << _nodeAuthenticationHostname;
authPacketStream << _nodeAuthenticationURL;
qDebug() << "Asking node at" << senderSockAddr << "to authenticate.";

View file

@ -59,7 +59,7 @@ private:
bool _hasCompletedRestartHold;
QUrl _nodeAuthenticationHostname;
QUrl _nodeAuthenticationURL;
private slots:
void readAvailableDatagrams();
void addStaticAssignmentsBackToQueueAfterRestart();

View file

@ -207,6 +207,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_voxels, SLOT(nodeKilled(SharedNodePointer)));
connect(nodeList, &NodeList::uuidChanged, this, &Application::updateWindowTitle);
connect(&AccountManager::getInstance(), SIGNAL(authenticationRequiredForRootURL(const QUrl&)),
Menu::getInstance(), SLOT(showLoginForRootURL(const QUrl&)));
// read the ApplicationInfo.ini file for Name/Version/Domain information
QSettings applicationInfo("resources/info/ApplicationInfo.ini", QSettings::IniFormat);
@ -4216,6 +4219,5 @@ void Application::takeSnapshot() {
player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath()));
player->play();
Snapshot::saveSnapshot(_glWidget, AccountManager::getUsername(), _myAvatar->getPosition());
}
Snapshot::saveSnapshot(_glWidget, AccountManager::getInstance().getUsername(), _myAvatar->getPosition());
}

View file

@ -89,7 +89,7 @@ Menu::Menu() :
MenuOption::Login,
0,
this,
SLOT(login())));
SLOT(loginForCurrentDomain())));
addDisabledActionAndSeparator(fileMenu, "Scripts");
addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, appInstance, SLOT(loadDialog()));
@ -737,7 +737,11 @@ void sendFakeEnterEvent() {
const int QLINE_MINIMUM_WIDTH = 400;
const float DIALOG_RATIO_OF_WINDOW = 0.30f;
void Menu::login() {
void Menu::loginForCurrentDomain() {
showLoginForRootURL(NodeList::getInstance()->getDomainInfo().getRootAuthenticationURL());
}
void Menu::showLoginForRootURL(const QUrl& rootURL) {
QInputDialog loginDialog(Application::getInstance()->getWindow());
loginDialog.setWindowTitle("Login");
loginDialog.setLabelText("Username:");

View file

@ -76,7 +76,6 @@ public:
int getMaxVoxels() const { return _maxVoxels; }
QAction* getUseVoxelShader() const { return _useVoxelShader; }
void handleViewFrustumOffsetKeyModifier(int key);
// User Tweakable LOD Items
@ -102,6 +101,8 @@ public:
void goToDomain(const QString newDomain);
public slots:
void loginForCurrentDomain();
void showLoginForRootURL(const QUrl& rootURL);
void bandwidthDetails();
void voxelStatsDetails();
void lodTools();
@ -114,7 +115,6 @@ public slots:
private slots:
void aboutApp();
void login();
void editPreferences();
void goToDomain();
void goToLocation();

View file

@ -7,21 +7,34 @@
//
#include <QtCore/QDataStream>
#include <QtCore/QMap>
#include "PacketHeaders.h"
#include "AccountManager.h"
QString AccountManager::_username = "";
AccountManager& AccountManager::getInstance() {
static AccountManager sharedInstance;
return sharedInstance;
}
void AccountManager::processDomainServerAuthRequest(const QByteArray& packet) {
QDataStream authPacketStream(packet);
authPacketStream.skipRawData(numBytesForPacketHeader(packet));
AccountManager::AccountManager() :
_username(),
_accessTokens(),
_networkAccessManager(NULL)
{
// grab the hostname this domain-server wants us to authenticate with
QString authenticationHostname;
authPacketStream >> authenticationHostname;
// check if we already have an access token associated with that hostname
}
bool AccountManager::hasValidAccessTokenForRootURL(const QUrl &rootURL) {
OAuthAccessToken accessToken = _accessTokens.value(rootURL);
if (accessToken.token.isEmpty() || accessToken.isExpired()) {
// emit a signal so somebody can call back to us and request an access token given a username and password
qDebug() << "An access token is required for requests to" << qPrintable(rootURL.toString());
emit authenticationRequiredForRootURL(rootURL);
return false;
} else {
return true;
}
}

View file

@ -10,15 +10,33 @@
#define __hifi__AccountManager__
#include <QtCore/QByteArray>
#include <QtCore/QObject>
#include <QtCore/QUrl>
#include <QtNetwork/QNetworkAccessManager>
class AccountManager {
#include "OAuthAccessToken.h"
class AccountManager : public QObject {
Q_OBJECT
public:
static void processDomainServerAuthRequest(const QByteArray& packet);
static AccountManager& getInstance();
static const QString& getUsername() { return _username; }
static void setUsername(const QString& username) { _username = username; }
bool hasValidAccessTokenForRootURL(const QUrl& rootURL);
const QString& getUsername() const { return _username; }
void setUsername(const QString& username) { _username = username; }
void setNetworkAccessManager(QNetworkAccessManager* networkAccessManager) { _networkAccessManager = networkAccessManager; }
signals:
void authenticationRequiredForRootURL(const QUrl& rootURL);
private:
static QString _username;
AccountManager();
AccountManager(AccountManager const& other); // not implemented
void operator=(AccountManager const& other); // not implemented
QString _username;
QMap<QUrl, OAuthAccessToken> _accessTokens;
QNetworkAccessManager* _networkAccessManager;
};
#endif /* defined(__hifi__AccountManager__) */

View file

@ -10,9 +10,9 @@
DomainInfo::DomainInfo() :
_sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)),
_requiresAuthentication(false),
_connectionSecret(),
_registrationToken()
_registrationToken(),
_rootAuthenticationURL()
{
}

View file

@ -11,6 +11,7 @@
#include <QtCore/QObject>
#include <QtCore/QUuid>
#include <QtCore/QUrl>
#include <QtNetwork/QHostInfo>
#include "HifiSockAddr.h"
@ -34,14 +35,15 @@ public:
unsigned short getPort() const { return _sockAddr.getPort(); }
bool requiresAuthentication() const { return _requiresAuthentication; }
void setRequiresAuthentication(bool requiresAuthentication) { _requiresAuthentication = requiresAuthentication; }
const QUuid& getConnectionSecret() const { return _connectionSecret; }
void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; }
const QString& getRegistrationToken() const { return _registrationToken; }
void setRegistrationToken(const QString& registrationToken);
const QUrl& getRootAuthenticationURL() const { return _rootAuthenticationURL; }
void setRootAuthenticationURL(const QUrl& rootAuthenticationURL) { _rootAuthenticationURL = rootAuthenticationURL; }
private slots:
void completedHostnameLookup(const QHostInfo& hostInfo);
signals:
@ -49,9 +51,9 @@ signals:
private:
QString _hostname;
HifiSockAddr _sockAddr;
bool _requiresAuthentication;
QUuid _connectionSecret;
QString _registrationToken;
QUrl _rootAuthenticationURL;
};
#endif /* defined(__hifi__DomainInfo__) */

View file

@ -12,8 +12,10 @@
#include <QtCore/QDataStream>
#include <QtCore/QDebug>
#include <QtCore/QUrl>
#include <QtNetwork/QHostInfo>
#include "AccountManager.h"
#include "Assignment.h"
#include "HifiSockAddr.h"
#include "Logging.h"
@ -197,7 +199,7 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr
}
case PacketTypeDomainServerAuthRequest: {
// the domain-server has asked us to auth via a data-server
processDomainServerAuthRequest(packet);
break;
}
@ -471,7 +473,7 @@ void NodeList::sendDomainServerCheckIn() {
// send a STUN request to figure it out
sendSTUNRequest();
} else if (!_domainInfo.getIP().isNull()
&& (!_domainInfo.requiresAuthentication()
&& (_domainInfo.getRootAuthenticationURL().isEmpty()
|| !_sessionUUID.isNull()
|| !_domainInfo.getRegistrationToken().isEmpty()) ) {
// construct the DS check in packet
@ -562,6 +564,21 @@ int NodeList::processDomainServerList(const QByteArray& packet) {
return readNodes;
}
void NodeList::processDomainServerAuthRequest(const QByteArray& packet) {
QDataStream authPacketStream(packet);
authPacketStream.skipRawData(numBytesForPacketHeader(packet));
// grab the hostname this domain-server wants us to authenticate with
QUrl authenticationRootURL;
authPacketStream >> authenticationRootURL;
_domainInfo.setRootAuthenticationURL(authenticationRootURL);
if (AccountManager::getInstance().hasValidAccessTokenForRootURL(authenticationRootURL)) {
// request a domain-server registration
}
}
void NodeList::sendAssignment(Assignment& assignment) {
PacketType assignmentPacketType = assignment.getCommand() == Assignment::CreateCommand

View file

@ -148,6 +148,8 @@ private:
void clear();
void processDomainServerAuthRequest(const QByteArray& packet);
NodeHash _nodeHash;
QMutex _nodeHashMutex;
QUdpSocket _nodeSocket;

View file

@ -0,0 +1,40 @@
//
// OAuthAccessToken.cpp
// hifi
//
// Created by Stephen Birarda on 2/18/2014.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
#include "OAuthAccessToken.h"
OAuthAccessToken::OAuthAccessToken() :
token(),
refreshToken(),
expiryTimestamp(),
tokenType()
{
}
OAuthAccessToken::OAuthAccessToken(const OAuthAccessToken& otherToken) {
token = otherToken.token;
refreshToken = otherToken.refreshToken;
expiryTimestamp = otherToken.expiryTimestamp;
tokenType = otherToken.tokenType;
}
OAuthAccessToken& OAuthAccessToken::operator=(const OAuthAccessToken& otherToken) {
OAuthAccessToken temp(otherToken);
swap(temp);
return *this;
}
void OAuthAccessToken::swap(OAuthAccessToken& otherToken) {
using std::swap;
swap(token, otherToken.token);
swap(refreshToken, otherToken.refreshToken);
swap(expiryTimestamp, otherToken.expiryTimestamp);
swap(tokenType, otherToken.tokenType);
}

View file

@ -0,0 +1,32 @@
//
// OAuthAccessToken.h
// hifi
//
// Created by Stephen Birarda on 2/18/2014.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
#ifndef __hifi__OAuthAccessToken__
#define __hifi__OAuthAccessToken__
#include <QtCore/QObject>
#include <QtCore/QDateTime>
class OAuthAccessToken : public QObject {
Q_OBJECT
public:
OAuthAccessToken();
OAuthAccessToken(const OAuthAccessToken& otherToken);
OAuthAccessToken& operator=(const OAuthAccessToken& otherToken);
bool isExpired() { return expiryTimestamp <= QDateTime::currentMSecsSinceEpoch(); }
QString token;
QString refreshToken;
quint64 expiryTimestamp;
QString tokenType;
private:
void swap(OAuthAccessToken& otherToken);
};
#endif /* defined(__hifi__OAuthAccessToken__) */