Handle log in for multiple domains with domain login

This commit is contained in:
David Rowe 2020-08-20 12:32:03 +12:00
parent bf60cf5b4c
commit 662b2bfc5e
2 changed files with 45 additions and 88 deletions

View file

@ -29,77 +29,56 @@
const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false; const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false;
// ####### TODO: Enable and use these?
// ####### TODO: Add storing domain URL and check against it when retrieving values?
// ####### TODO: Add storing _authURL and check against it when retrieving values?
/*
Setting::Handle<QString> domainAccessToken {"private/domainAccessToken", "" };
Setting::Handle<QString> domainAccessRefreshToken {"private/domainAccessToken", "" };
Setting::Handle<int> domainAccessTokenExpiresIn {"private/domainAccessTokenExpiresIn", -1 };
Setting::Handle<QString> domainAccessTokenType {"private/domainAccessTokenType", "" };
*/
DomainAccountManager::DomainAccountManager() { DomainAccountManager::DomainAccountManager() {
connect(this, &DomainAccountManager::loginComplete, this, &DomainAccountManager::sendInterfaceAccessTokenToServer); connect(this, &DomainAccountManager::loginComplete, this, &DomainAccountManager::sendInterfaceAccessTokenToServer);
} }
void DomainAccountManager::setDomainURL(const QUrl& domainURL) { void DomainAccountManager::setDomainURL(const QUrl& domainURL) {
qDebug() << "####### DomainAccountManager::setDomainURL()" << domainURL;
if (domainURL == _domainURL) { if (domainURL == _currentAuth.domainURL) {
qDebug() << "####... Early return";
return; return;
} }
_domainURL = domainURL; qCDebug(networking) << "DomainAccountManager domain URL has been changed to" << qPrintable(domainURL.toString());
qCDebug(networking) << "DomainAccountManager domain URL has been changed to" << qPrintable(_domainURL.toString());
// Restore OAuth2 authorization if have it for this domain. // Restore OAuth2 authorization if have it for this domain.
if (_domainURL == _previousDomainURL) { if (_knownAuths.contains(domainURL)) {
_authURL = _previousAuthURL; _currentAuth = _knownAuths.value(domainURL);
_clientID = _previousClientID;
_username = _previousUsername;
_accessToken = _previousAccessToken;
_refreshToken = _previousRefreshToken;
_authedDomainName = _previousAuthedDomainName;
// ####### TODO: Refresh OAuth2 access token if necessary.
} else { } else {
_authURL.clear(); _currentAuth = DomainAccountDetails();
_clientID.clear(); _currentAuth.domainURL = domainURL;
_username.clear();
_accessToken.clear();
_refreshToken.clear();
_authedDomainName.clear();
} }
} }
void DomainAccountManager::setAuthURL(const QUrl& authURL) { void DomainAccountManager::setAuthURL(const QUrl& authURL) {
if (_authURL == authURL) { if (authURL == _currentAuth.authURL) {
return; return;
} }
_authURL = authURL; _currentAuth.authURL = authURL;
qCDebug(networking) << "DomainAccountManager URL for authenticated requests has been changed to" qCDebug(networking) << "DomainAccountManager URL for authenticated requests has been changed to"
<< qPrintable(_authURL.toString()); << qPrintable(_currentAuth.authURL.toString());
_accessToken = ""; _currentAuth.accessToken = "";
_refreshToken = ""; _currentAuth.refreshToken = "";
} }
bool DomainAccountManager::hasLogIn() { bool DomainAccountManager::hasLogIn() {
return !_authURL.isEmpty(); return !_currentAuth.authURL.isEmpty();
} }
bool DomainAccountManager::isLoggedIn() { bool DomainAccountManager::isLoggedIn() {
return !_authURL.isEmpty() && hasValidAccessToken(); return !_currentAuth.authURL.isEmpty() && hasValidAccessToken();
} }
void DomainAccountManager::requestAccessToken(const QString& username, const QString& password) { void DomainAccountManager::requestAccessToken(const QString& username, const QString& password) {
_username = username; _currentAuth.username = username;
_accessToken = ""; _currentAuth.accessToken = "";
_refreshToken = ""; _currentAuth.refreshToken = "";
QNetworkRequest request; QNetworkRequest request;
@ -113,9 +92,9 @@ void DomainAccountManager::requestAccessToken(const QString& username, const QSt
formData.append("grant_type=password&"); formData.append("grant_type=password&");
formData.append("username=" + QUrl::toPercentEncoding(username) + "&"); formData.append("username=" + QUrl::toPercentEncoding(username) + "&");
formData.append("password=" + QUrl::toPercentEncoding(password) + "&"); formData.append("password=" + QUrl::toPercentEncoding(password) + "&");
formData.append("client_id=" + _clientID); formData.append("client_id=" + _currentAuth.clientID);
request.setUrl(_authURL); request.setUrl(_currentAuth.authURL);
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
@ -138,19 +117,13 @@ void DomainAccountManager::requestAccessTokenFinished() {
if (rootObject.contains("access_token")) { if (rootObject.contains("access_token")) {
// Success. // Success.
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
_authedDomainName = nodeList->getDomainHandler().getHostname(); _currentAuth.authedDomainName = nodeList->getDomainHandler().getHostname();
QUrl rootURL = requestReply->url(); QUrl rootURL = requestReply->url();
rootURL.setPath(""); rootURL.setPath("");
setTokensFromJSON(rootObject, rootURL); setTokensFromJSON(rootObject, rootURL);
// Remember domain login for the current Interface session. // Remember domain login for the current Interface session.
_previousDomainURL = _domainURL; _knownAuths.insert(_currentAuth.domainURL, _currentAuth);
_previousAuthURL = _authURL;
_previousClientID = _clientID;
_previousUsername = _username;
_previousAccessToken = _accessToken;
_previousRefreshToken = _refreshToken;
_previousAuthedDomainName = _authedDomainName;
// ####### TODO: Handle "keep me logged in". // ####### TODO: Handle "keep me logged in".
@ -176,22 +149,19 @@ void DomainAccountManager::sendInterfaceAccessTokenToServer() {
bool DomainAccountManager::accessTokenIsExpired() { bool DomainAccountManager::accessTokenIsExpired() {
// ####### TODO: accessTokenIsExpired() // ####### TODO: accessTokenIsExpired()
return true; return true;
/*
return domainAccessTokenExpiresIn.get() != -1 && domainAccessTokenExpiresIn.get() <= QDateTime::currentMSecsSinceEpoch();
*/
} }
bool DomainAccountManager::hasValidAccessToken() { bool DomainAccountManager::hasValidAccessToken() {
// ###### TODO: wire this up to actually retrieve a token (based on session or storage) and confirm that it is in fact valid and relevant to the current domain. // ###### TODO: wire this up to actually retrieve a token (based on session or storage) and confirm that it is in fact valid and relevant to the current domain.
// QString currentDomainAccessToken = domainAccessToken.get(); // QString currentDomainAccessToken = domainAccessToken.get();
QString currentDomainAccessToken = _accessToken; QString currentDomainAccessToken = _currentAuth.accessToken;
// if (currentDomainAccessToken.isEmpty() || accessTokenIsExpired()) { // if (currentDomainAccessToken.isEmpty() || accessTokenIsExpired()) {
if (currentDomainAccessToken.isEmpty()) { if (currentDomainAccessToken.isEmpty()) {
if (VERBOSE_HTTP_REQUEST_DEBUGGING) { if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
qCDebug(networking) << "An access token is required for requests to" qCDebug(networking) << "An access token is required for requests to"
<< qPrintable(_authURL.toString()); << qPrintable(_currentAuth.authURL.toString());
} }
return false; return false;
@ -207,17 +177,8 @@ bool DomainAccountManager::hasValidAccessToken() {
} }
void DomainAccountManager::setTokensFromJSON(const QJsonObject& jsonObject, const QUrl& url) { void DomainAccountManager::setTokensFromJSON(const QJsonObject& jsonObject, const QUrl& url) {
_accessToken = jsonObject["access_token"].toString(); _currentAuth.accessToken = jsonObject["access_token"].toString();
_refreshToken = jsonObject["refresh_token"].toString(); _currentAuth.refreshToken = jsonObject["refresh_token"].toString();
// ####### TODO: Enable and use these?
// ####### TODO: Protect these per AccountManager?
// ######: TODO: clientID needed?
// qCDebug(networking) << "Storing a domain account with access-token for" << qPrintable(url.toString());
// domainAccessToken.set(jsonObject["access_token"].toString());
// domainAccessRefreshToken.set(jsonObject["refresh_token"].toString());
// domainAccessTokenExpiresIn.set(QDateTime::currentMSecsSinceEpoch() + (jsonObject["expires_in"].toDouble() * 1000));
// domainAccessTokenType.set(jsonObject["token_type"].toString());
} }
bool DomainAccountManager::checkAndSignalForAccessToken() { bool DomainAccountManager::checkAndSignalForAccessToken() {
@ -232,7 +193,7 @@ bool DomainAccountManager::checkAndSignalForAccessToken() {
// Emit a signal so somebody can call back to us and request an access token given a user name and password. // Emit a signal so somebody can call back to us and request an access token given a user name and password.
// Dialog can be hidden immediately after showing if we've just teleported to the domain, unless the signal is delayed. // Dialog can be hidden immediately after showing if we've just teleported to the domain, unless the signal is delayed.
auto domain = _authURL.host(); auto domain = _currentAuth.authURL.host();
QTimer::singleShot(500, this, [this, domain] { QTimer::singleShot(500, this, [this, domain] {
emit this->authRequired(domain); emit this->authRequired(domain);
}); });

View file

@ -18,6 +18,17 @@
#include <DependencyManager.h> #include <DependencyManager.h>
struct DomainAccountDetails {
QUrl domainURL;
QUrl authURL;
QString clientID;
QString username;
QString accessToken;
QString refreshToken;
QString authedDomainName;
};
class DomainAccountManager : public QObject, public Dependency { class DomainAccountManager : public QObject, public Dependency {
Q_OBJECT Q_OBJECT
public: public:
@ -25,12 +36,12 @@ public:
void setDomainURL(const QUrl& domainURL); void setDomainURL(const QUrl& domainURL);
void setAuthURL(const QUrl& authURL); void setAuthURL(const QUrl& authURL);
void setClientID(const QString& clientID) { _clientID = clientID; } void setClientID(const QString& clientID) { _currentAuth.clientID = clientID; }
const QString& getUsername() { return _username; } const QString& getUsername() { return _currentAuth.username; }
const QString& getAccessToken() { return _accessToken; } const QString& getAccessToken() { return _currentAuth.accessToken; }
const QString& getRefreshToken() { return _refreshToken; } const QString& getRefreshToken() { return _currentAuth.refreshToken; }
const QString& getAuthedDomainName() { return _authedDomainName; } const QString& getAuthedDomainName() { return _currentAuth.authedDomainName; }
bool hasLogIn(); bool hasLogIn();
bool isLoggedIn(); bool isLoggedIn();
@ -56,23 +67,8 @@ private:
void setTokensFromJSON(const QJsonObject&, const QUrl& url); void setTokensFromJSON(const QJsonObject&, const QUrl& url);
void sendInterfaceAccessTokenToServer(); void sendInterfaceAccessTokenToServer();
QUrl _domainURL; DomainAccountDetails _currentAuth;
QUrl _authURL; QHash<QUrl, DomainAccountDetails> _knownAuths; // <domainURL, DomainAccountDetails>
QString _clientID;
QString _username;
QString _accessToken;
QString _refreshToken;
QString _authedDomainName;
// ####### TODO: Handle more than one domain.
QUrl _previousDomainURL;
QUrl _previousAuthURL;
QString _previousClientID;
QString _previousUsername;
QString _previousAccessToken;
QString _previousRefreshToken;
QString _previousAuthedDomainName;
}; };
#endif // hifi_DomainAccountManager_h #endif // hifi_DomainAccountManager_h