Update to work with WordPress plugin

This commit is contained in:
David Rowe 2020-08-04 17:12:31 +12:00
parent 7da91d9557
commit bc56eb5ac7
5 changed files with 36 additions and 46 deletions

View file

@ -77,13 +77,6 @@
"type": "checkbox",
"advanced": true
},
{
"name": "domain_access_token",
"label": "Domain API Access Token",
"help": "This is the access token that your domain-server will use to verify users and their roles. This token must grant access to that permission set on your REST API server.",
"advanced": true,
"backup": false
},
{
"name": "oauth2_url_path",
"label": "Authentication URL",
@ -95,6 +88,13 @@
"label": "WordPress API URL Base",
"help": "The URL base that the domain server will use to make WordPress API calls. Typically \"https://oursite.com/wp-json/\". However, if using non-pretty permalinks or otherwise get a 404 error then try \"https://oursite.com/?rest_route=/\".",
"advanced": true
},
{
"name": "plugin_client_id",
"label": "WordPress Plugin Client ID",
"help": "This is the client ID from the WordPress plugin configuration.",
"advanced": true,
"backup": false
}
]
},

View file

@ -453,6 +453,7 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo
const QString AUTHENTICATION_ENAABLED = "authentication.enable_oauth2";
const QString AUTHENTICATION_OAUTH2_URL_PATH = "authentication.oauth2_url_path";
const QString AUTHENTICATION_WORDPRESS_URL_BASE = "authentication.wordpress_url_base";
const QString AUTHENTICATION_PLUGIN_CLIENT_ID = "authentication.plugin_client_id";
const QString MAXIMUM_USER_CAPACITY = "security.maximum_user_capacity";
const QString MAXIMUM_USER_CAPACITY_REDIRECT_LOCATION = "security.maximum_user_capacity_redirect_location";
@ -553,8 +554,15 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
if (domainAuthURLVariant.canConvert<QString>()) {
domainAuthURL = domainAuthURLVariant.toString();
}
QString domainAuthClientID;
auto domainAuthClientIDVariant = _server->_settingsManager.valueForKeyPath(AUTHENTICATION_PLUGIN_CLIENT_ID);
if (domainAuthClientIDVariant.canConvert<QString>()) {
domainAuthClientID = domainAuthClientIDVariant.toString();
}
sendConnectionDeniedPacket("You lack the required domain permissions to connect to this domain.",
nodeConnection.senderSockAddr, DomainHandler::ConnectionRefusedReason::NotAuthorizedDomain, domainAuthURL);
nodeConnection.senderSockAddr, DomainHandler::ConnectionRefusedReason::NotAuthorizedDomain,
domainAuthURL + "|" + domainAuthClientID);
} else {
sendConnectionDeniedPacket("You lack the required metaverse permissions to connect to this domain.",
nodeConnection.senderSockAddr, DomainHandler::ConnectionRefusedReason::NotAuthorizedMetaverse);
@ -1242,11 +1250,9 @@ void DomainGatekeeper::requestDomainUser(const QString& username, const QString&
}
// Get data pertaining to "me", the user who generated the access token.
// ####### TODO: Confirm API route and data w.r.t. OAuth2 plugin's capabilities. [plugin]
const QString WORDPRESS_USER_ROUTE = "wp/v2/users/me?context=edit&_fields=id,username,roles";
QUrl domainUserURL = apiBase + WORDPRESS_USER_ROUTE;
// ####### TODO: Append a random key to check in response? [security]
const QString WORDPRESS_USER_ROUTE = "wp/v2/users/me";
const QString WORDPRESS_USER_QUERY = "_fields=username,roles";
QUrl domainUserURL = apiBase + WORDPRESS_USER_ROUTE + (apiBase.contains("?") ? "&" : "?") + WORDPRESS_USER_QUERY;
QNetworkRequest request;
@ -1275,34 +1281,24 @@ void DomainGatekeeper::requestDomainUserFinished() {
auto httpStatus = requestReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (200 <= httpStatus && httpStatus < 300) {
// Success.
// ####### TODO: Verify Expected response. [plugin]
/*
{
id: 2,
username : 'apiuser',
roles : ['subscriber'] ,
}
*/
QString username = rootObject["username"].toString().toLower();
if (_inFlightDomainUserIdentityRequests.contains(username)) {
// Success! Verified user.
_verifiedDomainUserIdentities.insert(username, _inFlightDomainUserIdentityRequests.value(username));
_inFlightDomainUserIdentityRequests.remove(username);
// ####### TODO: Handle roles.
} else {
// Failure.
qDebug() << "Unexpected username in response for user details -" << username;
}
// ####### TODO: Handle roles if available. [plugin]
} else {
// Failure.
// ####### TODO: Error fields to report. [plugin]
qDebug() << "Error in response for user details -" << httpStatus << requestReply->error()
<< "-" << rootObject["error"].toString();
<< "-" << rootObject["error"].toString() << rootObject["error_description"].toString();
_inFlightDomainUserIdentityRequests.clear();
}

View file

@ -26,8 +26,6 @@
// FIXME: Generalize to other OAuth2 sources for domain login.
const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false;
const QString DOMAIN_ACCOUNT_MANAGER_REQUESTED_SCOPE = "foo bar"; // ####### TODO: WordPress plugin's required scope. [plugin]
// ####### TODO: Should scope be configured in domain server settings? [plugin]
// ####### TODO: Add storing domain URL and check against it when retrieving values?
// ####### TODO: Add storing _authURL and check against it when retrieving values?
@ -71,15 +69,15 @@ void DomainAccountManager::requestAccessToken(const QString& username, const QSt
request.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
// ####### TODO: WordPress plugin's authorization requirements. [plugin]
request.setRawHeader(QByteArray("Authorization"), QByteArray("Basic b2F1dGgtY2xpZW50LTE6b2F1dGgtY2xpZW50LXNlY3JldC0x"));
// miniOrange WordPress API Authentication plugin:
// - Requires "client_id" parameter.
// - Ignores "state" parameter.
QByteArray formData;
formData.append("grant_type=password&");
formData.append("username=" + QUrl::toPercentEncoding(username) + "&");
formData.append("password=" + QUrl::toPercentEncoding(password) + "&");
formData.append("scope=" + DOMAIN_ACCOUNT_MANAGER_REQUESTED_SCOPE);
// ####### TODO: Include state? [plugin]
formData.append("client_id=" + _clientID);
request.setUrl(_authURL);
@ -100,20 +98,13 @@ void DomainAccountManager::requestAccessTokenFinished() {
auto httpStatus = requestReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (200 <= httpStatus && httpStatus < 300) {
// ####### TODO: Process response state? [plugin]
// ####### TODO: Process response scope? [plugin]
// ####### TODO: Which method are the tokens provided in? [plugin]
// miniOrange plugin provides no scope.
if (rootObject.contains("access_token")) {
// Success.
QUrl rootURL = requestReply->url();
rootURL.setPath("");
setTokensFromJSON(rootObject, rootURL);
emit loginComplete();
} else {
// Failure.
qCDebug(networking) << "Received a response for password grant that is missing one or more expected values.";
@ -122,10 +113,8 @@ void DomainAccountManager::requestAccessTokenFinished() {
} else {
// Failure.
// ####### TODO: Error object fields to report. [plugin]
qCDebug(networking) << "Error in response for password grant -" << httpStatus << requestReply->error()
<< "_" << rootObject["error"].toString();
qCDebug(networking) << "Error in response for password grant -" << httpStatus << requestReply->error()
<< "-" << rootObject["error"].toString() << rootObject["error_description"].toString();
emit loginFailed();
}
}
@ -173,6 +162,7 @@ void DomainAccountManager::setTokensFromJSON(const QJsonObject& jsonObject, cons
// ####### 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());

View file

@ -24,6 +24,7 @@ public:
DomainAccountManager();
void setAuthURL(const QUrl& authURL);
void setClientID(const QString& clientID) { _clientID = clientID; }
QString getUsername() { return _username; }
QString getAccessToken() { return _access_token; }
@ -51,6 +52,7 @@ private:
void sendInterfaceAccessTokenToServer();
QUrl _authURL;
QString _clientID;
QString _username; // ####### TODO: Store elsewhere?
QString _access_token; // ####... ""
QString _refresh_token; // ####... ""

View file

@ -589,7 +589,9 @@ void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer<Rec
auto accountManager = DependencyManager::get<DomainAccountManager>();
if (!extraInfo.isEmpty()) {
accountManager->setAuthURL(extraInfo);
auto extraInfoComponents = extraInfo.split("|");
accountManager->setAuthURL(extraInfoComponents.value(0));
accountManager->setClientID(extraInfoComponents.value(1));
}
if (!_hasCheckedForDomainAccessToken) {