mirror of
https://github.com/overte-org/overte.git
synced 2025-08-05 17:09:36 +02:00
Tidy networking code
This commit is contained in:
parent
dfbad4efc0
commit
43b6e77235
5 changed files with 54 additions and 49 deletions
|
@ -85,9 +85,9 @@
|
||||||
"backup": false
|
"backup": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "oauth2_url_base",
|
"name": "oauth2_url_path",
|
||||||
"label": "Authentication URL Base",
|
"label": "Authentication URL",
|
||||||
"help": "The URL base that the Interface will use to login via OAuth2.",
|
"help": "The URL that the Interface will use to login via OAuth2.",
|
||||||
"advanced": true
|
"advanced": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -450,7 +450,7 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString AUTHENTICATION_ENAABLED = "authentication.enable_oauth2";
|
const QString AUTHENTICATION_ENAABLED = "authentication.enable_oauth2";
|
||||||
const QString AUTHENTICATION_OAUTH2_URL_BASE = "authentication.oauth2_url_base";
|
const QString AUTHENTICATION_OAUTH2_URL_PATH = "authentication.oauth2_url_path";
|
||||||
const QString AUTHENTICATION_WORDPRESS_URL_BASE = "authentication.wordpress_url_base";
|
const QString AUTHENTICATION_WORDPRESS_URL_BASE = "authentication.wordpress_url_base";
|
||||||
const QString MAXIMUM_USER_CAPACITY = "security.maximum_user_capacity";
|
const QString MAXIMUM_USER_CAPACITY = "security.maximum_user_capacity";
|
||||||
const QString MAXIMUM_USER_CAPACITY_REDIRECT_LOCATION = "security.maximum_user_capacity_redirect_location";
|
const QString MAXIMUM_USER_CAPACITY_REDIRECT_LOCATION = "security.maximum_user_capacity_redirect_location";
|
||||||
|
@ -548,10 +548,9 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
|
||||||
if (!userPerms.can(NodePermissions::Permission::canConnectToDomain)) {
|
if (!userPerms.can(NodePermissions::Permission::canConnectToDomain)) {
|
||||||
if (domainHasLogin()) {
|
if (domainHasLogin()) {
|
||||||
QString domainAuthURL;
|
QString domainAuthURL;
|
||||||
auto domainAuthURLVariant = _server->_settingsManager.valueForKeyPath(AUTHENTICATION_OAUTH2_URL_BASE);
|
auto domainAuthURLVariant = _server->_settingsManager.valueForKeyPath(AUTHENTICATION_OAUTH2_URL_PATH);
|
||||||
if (domainAuthURLVariant.canConvert<QString>()) {
|
if (domainAuthURLVariant.canConvert<QString>()) {
|
||||||
domainAuthURL = domainAuthURLVariant.toString();
|
domainAuthURL = domainAuthURLVariant.toString();
|
||||||
qDebug() << "Domain authorization URL:" << domainAuthURL;
|
|
||||||
}
|
}
|
||||||
sendConnectionDeniedPacket("You lack the required permissions to connect to this domain.",
|
sendConnectionDeniedPacket("You lack the required permissions to connect to this domain.",
|
||||||
nodeConnection.senderSockAddr, DomainHandler::ConnectionRefusedReason::NotAuthorizedDomain, domainAuthURL);
|
nodeConnection.senderSockAddr, DomainHandler::ConnectionRefusedReason::NotAuthorizedDomain, domainAuthURL);
|
||||||
|
@ -1220,7 +1219,7 @@ bool DomainGatekeeper::domainHasLogin() {
|
||||||
// The domain may have its own users and groups in a WordPress site.
|
// The domain may have its own users and groups in a WordPress site.
|
||||||
// ####### TODO: Add checks of any further domain server settings used.
|
// ####### TODO: Add checks of any further domain server settings used.
|
||||||
return _server->_settingsManager.valueForKeyPath(AUTHENTICATION_ENAABLED).toBool()
|
return _server->_settingsManager.valueForKeyPath(AUTHENTICATION_ENAABLED).toBool()
|
||||||
&& !_server->_settingsManager.valueForKeyPath(AUTHENTICATION_OAUTH2_URL_BASE).toString().isEmpty()
|
&& !_server->_settingsManager.valueForKeyPath(AUTHENTICATION_OAUTH2_URL_PATH).toString().isEmpty()
|
||||||
&& !_server->_settingsManager.valueForKeyPath(AUTHENTICATION_WORDPRESS_URL_BASE).toString().isEmpty();
|
&& !_server->_settingsManager.valueForKeyPath(AUTHENTICATION_WORDPRESS_URL_BASE).toString().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1233,7 +1232,7 @@ void DomainGatekeeper::requestDomainUser(const QString& username, const QString&
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_inFlightDomainUserIdentityRequests.contains(username)) {
|
if (_inFlightDomainUserIdentityRequests.contains(username)) {
|
||||||
// Domain identify request for this username is already flight.
|
// Domain identify request for this username is already in progress.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_inFlightDomainUserIdentityRequests.insert(username, QPair<QString, QString>(accessToken, refreshToken));
|
_inFlightDomainUserIdentityRequests.insert(username, QPair<QString, QString>(accessToken, refreshToken));
|
||||||
|
@ -1248,9 +1247,9 @@ void DomainGatekeeper::requestDomainUser(const QString& username, const QString&
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get data pertaining to "me", the user who generated the access token.
|
// Get data pertaining to "me", the user who generated the access token.
|
||||||
// ####### TODO: Confirm API_ROUTE w.r.t. OAuth2 plugin's capabilities.
|
// ####### TODO: Confirm API route and data w.r.t. OAuth2 plugin's capabilities. [plugin]
|
||||||
QString API_ROUTE = "wp/v2/users/me?context=edit&_fields=id,username,roles";
|
const QString WORDPRESS_USER_ROUTE = "wp/v2/users/me?context=edit&_fields=id,username,roles";
|
||||||
QUrl domainUserURL = apiBase + API_ROUTE;
|
QUrl domainUserURL = apiBase + WORDPRESS_USER_ROUTE;
|
||||||
|
|
||||||
// ####### TODO: Append a random key to check in response?
|
// ####### TODO: Append a random key to check in response?
|
||||||
|
|
||||||
|
@ -1258,7 +1257,6 @@ void DomainGatekeeper::requestDomainUser(const QString& username, const QString&
|
||||||
|
|
||||||
request.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT);
|
request.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT);
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||||
// ####### TODO: WordPress plugin's authorization requirements.
|
|
||||||
request.setRawHeader(QByteArray("Authorization"), QString("Bearer " + accessToken).toUtf8());
|
request.setRawHeader(QByteArray("Authorization"), QString("Bearer " + accessToken).toUtf8());
|
||||||
|
|
||||||
QByteArray formData; // No data to send.
|
QByteArray formData; // No data to send.
|
||||||
|
@ -1278,12 +1276,13 @@ void DomainGatekeeper::requestDomainUserFinished() {
|
||||||
|
|
||||||
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
|
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
|
||||||
|
|
||||||
|
QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll());
|
||||||
|
const QJsonObject& rootObject = jsonResponse.object();
|
||||||
|
|
||||||
auto httpStatus = requestReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
auto httpStatus = requestReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
if (200 <= httpStatus && httpStatus < 300) {
|
if (200 <= httpStatus && httpStatus < 300) {
|
||||||
// Success.
|
// Success.
|
||||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll());
|
// ####### TODO: Verify Expected response. [plugin]
|
||||||
const QJsonObject& rootObject = jsonResponse.object();
|
|
||||||
// ####### Expected response:
|
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
|
@ -1292,22 +1291,24 @@ void DomainGatekeeper::requestDomainUserFinished() {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// ####### TODO: Handle invalid / unexpected response.
|
|
||||||
|
|
||||||
QString username = rootObject["username"].toString().toLower();
|
QString username = rootObject["username"].toString().toLower();
|
||||||
// ####### TODO: Handle invalid username or one that isn't in the _inFlight list.
|
|
||||||
|
|
||||||
if (_inFlightDomainUserIdentityRequests.contains(username)) {
|
if (_inFlightDomainUserIdentityRequests.contains(username)) {
|
||||||
// Success! Verified user.
|
// Success! Verified user.
|
||||||
_verifiedDomainUserIdentities.insert(username, _inFlightDomainUserIdentityRequests.value(username));
|
_verifiedDomainUserIdentities.insert(username, _inFlightDomainUserIdentityRequests.value(username));
|
||||||
_inFlightDomainUserIdentityRequests.remove(username);
|
_inFlightDomainUserIdentityRequests.remove(username);
|
||||||
} else {
|
} else {
|
||||||
// Unexpected response.
|
// Failure.
|
||||||
// ####### TODO
|
qDebug() << "Unexpected username in response for user details -" << username;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ####### TODO: Handle roles if available. [plugin]
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Failure.
|
// Failure.
|
||||||
|
|
||||||
|
// ####### TODO: Error fields to report. [plugin]
|
||||||
|
qDebug() << "Error in response for user details -" << rootObject["error"].toString();
|
||||||
|
|
||||||
// ####### TODO: Is this the best way to handle _inFlightDomainUserIdentityRequests?
|
// ####### TODO: Is this the best way to handle _inFlightDomainUserIdentityRequests?
|
||||||
// If there's a brief network glitch will it recover?
|
// If there's a brief network glitch will it recover?
|
||||||
// Perhaps clear on a timer? Cancel timer upon subsequent successful responses?
|
// Perhaps clear on a timer? Cancel timer upon subsequent successful responses?
|
||||||
|
|
|
@ -155,7 +155,7 @@ private:
|
||||||
void requestDomainUser(const QString& username, const QString& accessToken, const QString& refreshToken);
|
void requestDomainUser(const QString& username, const QString& accessToken, const QString& refreshToken);
|
||||||
|
|
||||||
typedef QHash<QString, QPair<QString, QString>> DomainUserIdentities; // <domainUserName, <access_token, refresh_token>>
|
typedef QHash<QString, QPair<QString, QString>> DomainUserIdentities; // <domainUserName, <access_token, refresh_token>>
|
||||||
DomainUserIdentities _inFlightDomainUserIdentityRequests; // Keep track of domain user identity requests in progress.
|
DomainUserIdentities _inFlightDomainUserIdentityRequests; // Domain user identity requests currently in progress.
|
||||||
DomainUserIdentities _verifiedDomainUserIdentities; // Verified domain users.
|
DomainUserIdentities _verifiedDomainUserIdentities; // Verified domain users.
|
||||||
|
|
||||||
void getDomainGroupMemberships(const QString& domainUserName);
|
void getDomainGroupMemberships(const QString& domainUserName);
|
||||||
|
|
|
@ -60,7 +60,12 @@ void DomainAccountManager::setAuthURL(const QUrl& authURL) {
|
||||||
|
|
||||||
qCDebug(networking) << "AccountManager URL for authenticated requests has been changed to" << qPrintable(_authURL.toString());
|
qCDebug(networking) << "AccountManager URL for authenticated requests has been changed to" << qPrintable(_authURL.toString());
|
||||||
|
|
||||||
// ####### TODO: See AccountManager::setAuthURL().
|
_access_token = "";
|
||||||
|
_refresh_token = "";
|
||||||
|
|
||||||
|
// ####### TODO: Restore and refresh OAuth2 tokens if have them for this domain.
|
||||||
|
|
||||||
|
// ####### TODO: Handle "keep me logged in".
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,9 +89,7 @@ void DomainAccountManager::requestAccessToken(const QString& username, const QSt
|
||||||
formData.append("scope=" + DOMAIN_ACCOUNT_MANAGER_REQUESTED_SCOPE);
|
formData.append("scope=" + DOMAIN_ACCOUNT_MANAGER_REQUESTED_SCOPE);
|
||||||
// ####### TODO: Include state?
|
// ####### TODO: Include state?
|
||||||
|
|
||||||
QUrl domainAuthURL = _authURL;
|
request.setUrl(_authURL);
|
||||||
domainAuthURL.setPath("/token"); // ####### TODO: miniOrange-mandated URL. ####### TODO: Should this be included in the server settings value?
|
|
||||||
request.setUrl(domainAuthURL);
|
|
||||||
|
|
||||||
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||||
|
|
||||||
|
@ -96,40 +99,40 @@ void DomainAccountManager::requestAccessToken(const QString& username, const QSt
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainAccountManager::requestAccessTokenFinished() {
|
void DomainAccountManager::requestAccessTokenFinished() {
|
||||||
|
|
||||||
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
|
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
|
||||||
|
|
||||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll());
|
QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll());
|
||||||
const QJsonObject& rootObject = jsonResponse.object();
|
const QJsonObject& rootObject = jsonResponse.object();
|
||||||
|
|
||||||
// ####### TODO: Test HTTP response codes rather than object contains "error".
|
auto httpStatus = requestReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
// #### reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200
|
if (200 <= httpStatus && httpStatus < 300) {
|
||||||
if (!rootObject.contains("error")) {
|
|
||||||
// ####### TODO: Process response scope?
|
|
||||||
// ####### TODO: Process response state?
|
|
||||||
// ####### TODO: Check that token type == "Bearer"?
|
// ####### TODO: Check that token type == "Bearer"?
|
||||||
|
// ####### TODO: Process response state?
|
||||||
|
// ####### TODO: Process response scope?
|
||||||
|
|
||||||
if (!rootObject.contains("access_token")
|
if (rootObject.contains("access_token")) {
|
||||||
// ####### TODO: Does WordPRess plugin provide "expires_in"?
|
// Success.
|
||||||
// If so, handle here, or is it just the domain server that needs to use it?
|
|
||||||
//|| !rootObject.contains("expires_in")
|
|
||||||
|| !rootObject.contains("token_type")) {
|
|
||||||
|
|
||||||
qCDebug(networking) << "Received a response for password grant that is missing one or more expected values.";
|
|
||||||
emit loginFailed();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// clear the path from the response URL so we have the right root URL for this access token
|
|
||||||
QUrl rootURL = requestReply->url();
|
QUrl rootURL = requestReply->url();
|
||||||
rootURL.setPath("");
|
rootURL.setPath("");
|
||||||
|
|
||||||
qCDebug(networking) << "Storing a domain account with access-token for" << qPrintable(rootURL.toString());
|
setTokensFromJSON(rootObject, rootURL);
|
||||||
setAccessTokenFromJSON(rootObject);
|
|
||||||
|
|
||||||
emit loginComplete(rootURL);
|
emit loginComplete();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Failure.
|
||||||
|
qCDebug(networking) << "Received a response for password grant that is missing one or more expected values.";
|
||||||
|
emit loginFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qCDebug(networking) << "Error in response for password grant -" << rootObject["error_description"].toString();
|
// Failure.
|
||||||
|
|
||||||
|
// ####### TODO: Error object fields to report. [plugin]
|
||||||
|
qCDebug(networking) << "Error in response for password grant -" << rootObject["error"].toString();
|
||||||
emit loginFailed();
|
emit loginFailed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,13 +174,14 @@ bool DomainAccountManager::hasValidAccessToken() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainAccountManager::setAccessTokenFromJSON(const QJsonObject& jsonObject) {
|
void DomainAccountManager::setTokensFromJSON(const QJsonObject& jsonObject, const QUrl& url) {
|
||||||
_access_token = jsonObject["access_token"].toString();
|
_access_token = jsonObject["access_token"].toString();
|
||||||
_refresh_token = jsonObject["refresh_token"].toString();
|
_refresh_token = jsonObject["refresh_token"].toString();
|
||||||
|
|
||||||
// ####### TODO: Enable and use these.
|
// ####### TODO: Enable and use these.
|
||||||
// ####### TODO: Protect these per AccountManager?
|
// ####### TODO: Protect these per AccountManager?
|
||||||
/*
|
/*
|
||||||
|
qCDebug(networking) << "Storing a domain account with access-token for" << qPrintable(url.toString());
|
||||||
domainAccessToken.set(jsonObject["access_token"].toString());
|
domainAccessToken.set(jsonObject["access_token"].toString());
|
||||||
domainAccessRefreshToken.set(jsonObject["refresh_token"].toString());
|
domainAccessRefreshToken.set(jsonObject["refresh_token"].toString());
|
||||||
domainAccessTokenExpiresIn.set(QDateTime::currentMSecsSinceEpoch() + (jsonObject["expires_in"].toDouble() * 1000));
|
domainAccessTokenExpiresIn.set(QDateTime::currentMSecsSinceEpoch() + (jsonObject["expires_in"].toDouble() * 1000));
|
||||||
|
|
|
@ -37,7 +37,7 @@ public slots:
|
||||||
void requestAccessTokenFinished();
|
void requestAccessTokenFinished();
|
||||||
signals:
|
signals:
|
||||||
void authRequired();
|
void authRequired();
|
||||||
void loginComplete(const QUrl& authURL);
|
void loginComplete();
|
||||||
void loginFailed();
|
void loginFailed();
|
||||||
void logoutComplete();
|
void logoutComplete();
|
||||||
void newTokens();
|
void newTokens();
|
||||||
|
@ -47,7 +47,7 @@ private slots:
|
||||||
private:
|
private:
|
||||||
bool hasValidAccessToken();
|
bool hasValidAccessToken();
|
||||||
bool accessTokenIsExpired();
|
bool accessTokenIsExpired();
|
||||||
void setAccessTokenFromJSON(const QJsonObject&);
|
void setTokensFromJSON(const QJsonObject&, const QUrl& url);
|
||||||
void sendInterfaceAccessTokenToServer();
|
void sendInterfaceAccessTokenToServer();
|
||||||
|
|
||||||
QUrl _authURL;
|
QUrl _authURL;
|
||||||
|
|
Loading…
Reference in a new issue