Skip to content

Commit

Permalink
Merge pull request #591 from kasenvr/oauth2-wordpress
Browse files Browse the repository at this point in the history
OAuth2 WordPress
  • Loading branch information
two-one-five authored Aug 7, 2020
2 parents a80ddea + 95e0907 commit e74cbee
Show file tree
Hide file tree
Showing 23 changed files with 959 additions and 75 deletions.
37 changes: 36 additions & 1 deletion domain-server/resources/describe-settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"settings": [
{
"name": "metaverse",
"label": "Metaverse / Networking",
"label": "Networking / Metaverse",
"settings": [
{
"name": "access_token",
Expand Down Expand Up @@ -57,6 +57,39 @@
}
]
},
{
"name": "authentication",
"label": "Networking / WordPress OAuth2",
"settings": [
{
"name": "enable_oauth2",
"label": "Enable OAuth2 Authentication",
"help": "Allow a WordPress-based (miniOrange) OAuth2 service to assign users to groups based on their role with the service.",
"default": false,
"type": "checkbox",
"advanced": true
},
{
"name": "oauth2_url_path",
"label": "Authentication URL",
"help": "The URL that the Interface will use to login via OAuth2.",
"advanced": true
},
{
"name": "wordpress_url_base",
"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
}
]
},
{
"label": "Monitoring",
"name": "monitoring",
Expand Down Expand Up @@ -381,6 +414,7 @@
"name": "group_permissions",
"type": "table",
"caption": "Permissions for Users in Groups",
"help": "For groups that are provided from WordPress you need to denote them by putting an \"@\" symbol in front of each item, e.g., \"@silver\".",
"categorize_by_key": "permissions_id",
"can_add_new_categories": true,
"can_add_new_rows": false,
Expand Down Expand Up @@ -509,6 +543,7 @@
"name": "group_forbiddens",
"type": "table",
"caption": "Permissions Denied to Users in Groups",
"help": "For groups that are provided from WordPress you need to denote them by putting an \"@\" symbol in front of each item, e.g., \"@silver\".",
"categorize_by_key": "permissions_id",
"can_add_new_categories": true,
"can_add_new_rows": false,
Expand Down
267 changes: 251 additions & 16 deletions domain-server/src/DomainGatekeeper.cpp

Large diffs are not rendered by default.

33 changes: 29 additions & 4 deletions domain-server/src/DomainGatekeeper.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//
// Created by Stephen Birarda on 2015-08-24.
// Copyright 2015 High Fidelity, Inc.
// Copyright 2020 Vircadia contributors.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
Expand All @@ -29,6 +30,8 @@
#include "NodeConnectionData.h"
#include "PendingAssignedNodeData.h"

const QString DOMAIN_GROUP_CHAR = "@";

class DomainServer;

class DomainGatekeeper : public QObject {
Expand Down Expand Up @@ -71,16 +74,28 @@ public slots:

private slots:
void handlePeerPingTimeout();

// Login and groups for domain, separate from metaverse.
void requestDomainUserFinished();

private:
SharedNodePointer processAssignmentConnectRequest(const NodeConnectionData& nodeConnection,
const PendingAssignedNodeData& pendingAssignment);
SharedNodePointer processAgentConnectRequest(const NodeConnectionData& nodeConnection,
const QString& username,
const QByteArray& usernameSignature);
const QByteArray& usernameSignature,
const QString& domainUsername,
const QString& domainAccessToken,
const QString& domainRefreshToken);
SharedNodePointer addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection);

bool verifyUserSignature(const QString& username, const QByteArray& usernameSignature,
const HifiSockAddr& senderSockAddr);

bool needToVerifyDomainUserIdentity(const QString& username, const QString& accessToken, const QString& refreshToken);
bool verifyDomainUserIdentity(const QString& username, const QString& accessToken, const QString& refreshToken,
const HifiSockAddr& senderSockAddr);

bool isWithinMaxCapacity();

bool shouldAllowConnectionFromNode(const QString& username, const QByteArray& usernameSignature,
Expand Down Expand Up @@ -120,8 +135,9 @@ private slots:
QSet<QString> _domainOwnerFriends; // keep track of friends of the domain owner
QSet<QString> _inFlightGroupMembershipsRequests; // keep track of which we've already asked for

NodePermissions setPermissionsForUser(bool isLocalUser, QString verifiedUsername, const QHostAddress& senderAddress,
const QString& hardwareAddress, const QUuid& machineFingerprint);
NodePermissions setPermissionsForUser(bool isLocalUser, QString verifiedUsername, QString verifiedDomainUsername,
const QHostAddress& senderAddress, const QString& hardwareAddress,
const QUuid& machineFingerprint);

void getGroupMemberships(const QString& username);
// void getIsGroupMember(const QString& username, const QUuid groupID);
Expand All @@ -133,9 +149,18 @@ private slots:
using LocalIDs = std::unordered_set<Node::LocalID>;
LocalIDs _localIDs;
UUIDToLocalID _uuidToLocalID;

Node::LocalID _currentLocalID;
Node::LocalID _idIncrement;

// Login and groups for domain, separate from metaverse.
bool domainHasLogin();
void requestDomainUser(const QString& username, const QString& accessToken, const QString& refreshToken);

typedef QHash<QString, QPair<QString, QString>> DomainUserIdentities; // <domainUserName, <access_token, refresh_token>>
DomainUserIdentities _inFlightDomainUserIdentityRequests; // Domain user identity requests currently in progress.
DomainUserIdentities _verifiedDomainUserIdentities; // Verified domain users.

QHash<QString, QStringList> _domainGroupMemberships; // <domainUserName, [domainGroupName]>
};


Expand Down
22 changes: 22 additions & 0 deletions domain-server/src/DomainServerSettingsManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1966,6 +1966,10 @@ void DomainServerSettingsManager::apiRefreshGroupInformation() {
QStringList groupNames = getAllKnownGroupNames();
foreach (QString groupName, groupNames) {
QString lowerGroupName = groupName.toLower();
if (lowerGroupName.startsWith(DOMAIN_GROUP_CHAR)) {
// Ignore domain groups. (Assumption: metaverse group names can't start with a "@".)
return;
}
if (_groupIDs.contains(lowerGroupName)) {
// we already know about this one. recall setGroupID in case the group has been
// added to another section (the same group is found in both groups and blacklists).
Expand Down Expand Up @@ -2185,6 +2189,24 @@ QList<QUuid> DomainServerSettingsManager::getBlacklistGroupIDs() {
return result.toList();
}

QStringList DomainServerSettingsManager::getDomainServerGroupNames() {
// All names as listed in the domain server settings; both metaverse groups and domain groups
QSet<QString> result;
foreach(NodePermissionsKey groupKey, _groupPermissions.keys()) {
result += _groupPermissions[groupKey]->getID();
}
return result.toList();
}

QStringList DomainServerSettingsManager::getDomainServerBlacklistGroupNames() {
// All names as listed in the domain server settings; not necessarily mnetaverse groups.
QSet<QString> result;
foreach (NodePermissionsKey groupKey, _groupForbiddens.keys()) {
result += _groupForbiddens[groupKey]->getID();
}
return result.toList();
}

void DomainServerSettingsManager::debugDumpGroupsState() {
qDebug() << "--------- GROUPS ---------";

Expand Down
9 changes: 6 additions & 3 deletions domain-server/src/DomainServerSettingsManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@

#include <HifiConfigVariantMap.h>
#include <HTTPManager.h>

#include <Node.h>
#include <ReceivedMessage.h>
#include "NodePermissions.h"

#include <Node.h>
#include "DomainGatekeeper.h"
#include "NodePermissions.h"

const QString SETTINGS_PATHS_KEY = "paths";

Expand Down Expand Up @@ -105,6 +105,9 @@ class DomainServerSettingsManager : public QObject {
QList<QUuid> getGroupIDs();
QList<QUuid> getBlacklistGroupIDs();

QStringList getDomainServerGroupNames();
QStringList getDomainServerBlacklistGroupNames();

// these are used to locally cache the result of calling "api/v1/groups/.../is_member/..." on metaverse's api
void clearGroupMemberships(const QString& name) { _groupMembership[name.toLower()].clear(); }
void recordGroupMembership(const QString& name, const QUuid groupID, QUuid rankID);
Expand Down
Loading

0 comments on commit e74cbee

Please sign in to comment.