mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 13:18:38 +02:00
Merge pull request #577 from ctrlaltdavid/feature/domain-groups
Feature/domain groups
This commit is contained in:
commit
c66452b416
5 changed files with 87 additions and 34 deletions
|
@ -156,10 +156,8 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer<ReceivedMessag
|
||||||
}
|
}
|
||||||
|
|
||||||
NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QString verifiedUsername,
|
NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QString verifiedUsername,
|
||||||
QString verifiedDomainUserName,
|
QString verifiedDomainUserName, const QHostAddress& senderAddress,
|
||||||
QStringList verifiedDomainUserGroups,
|
const QString& hardwareAddress, const QUuid& machineFingerprint) {
|
||||||
const QHostAddress& senderAddress, const QString& hardwareAddress,
|
|
||||||
const QUuid& machineFingerprint) {
|
|
||||||
NodePermissions userPerms;
|
NodePermissions userPerms;
|
||||||
|
|
||||||
userPerms.setAll(false);
|
userPerms.setAll(false);
|
||||||
|
@ -171,21 +169,25 @@ NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QStrin
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this user is a known member of an externally-hosted group, give them the implied permissions.
|
// If this user is a known member of a domain group, give them the implied permissions.
|
||||||
// Do before processing verifiedUsername in case user is logged into the metaverse and is a member of a blacklist group.
|
// Do before processing verifiedUsername in case user is logged into the metaverse and is a member of a blacklist group.
|
||||||
if (!verifiedDomainUserName.isEmpty() && !verifiedDomainUserGroups.isEmpty()) {
|
if (!verifiedDomainUserName.isEmpty()) {
|
||||||
foreach (QString group, verifiedDomainUserGroups) {
|
auto userGroups = _domainGroupMemberships[verifiedDomainUserName];
|
||||||
if (_server->_settingsManager.getAllKnownGroupNames().contains(group)) {
|
foreach (QString userGroup, userGroups) {
|
||||||
userPerms |= _server->_settingsManager.getPermissionsForGroup(group, QUuid());
|
// Domain groups may be specified as comma- and/or space-separated lists of group names.
|
||||||
//#ifdef WANT_DEBUG
|
// For example, "silver gold, platinum".
|
||||||
qDebug() << "| user-permissions: domain user " << verifiedDomainUserName << "is in group:" << group << "so:" << userPerms;
|
auto domainGroups = _server->_settingsManager.getDomainGroupNames()
|
||||||
//#endif
|
.filter(QRegularExpression("^(.*[\\s,])?" + userGroup + "([\\s,].*)?$",
|
||||||
|
QRegularExpression::CaseInsensitiveOption));
|
||||||
|
foreach(QString domainGroup, domainGroups) {
|
||||||
|
userPerms |= _server->_settingsManager.getPermissionsForGroup(domainGroup, QUuid()); // No rank for domain groups.
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
qDebug() << "| user-permissions: domain user " << verifiedDomainUserName << "is in group:" << domainGroup
|
||||||
|
<< "so:" << userPerms;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
userPerms.setVerifiedDomainUserName(verifiedDomainUserName);
|
|
||||||
userPerms.setVerifiedDomainUserGroups(verifiedDomainUserGroups);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verifiedUsername.isEmpty()) {
|
if (verifiedUsername.isEmpty()) {
|
||||||
|
@ -289,6 +291,26 @@ NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QStrin
|
||||||
userPerms.setVerifiedUserName(verifiedUsername);
|
userPerms.setVerifiedUserName(verifiedUsername);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this user is a known member of an domain group that is blacklisted, remove the implied permissions.
|
||||||
|
if (!verifiedDomainUserName.isEmpty()) {
|
||||||
|
auto userGroups = _domainGroupMemberships[verifiedDomainUserName];
|
||||||
|
foreach(QString userGroup, userGroups) {
|
||||||
|
// Domain groups may be specified as comma- and/or space-separated lists of group names.
|
||||||
|
// For example, "silver gold, platinum".
|
||||||
|
auto domainGroups = _server->_settingsManager.getDomainBlacklistGroupNames()
|
||||||
|
.filter(QRegularExpression("^(.*[\\s,])?" + userGroup + "([\\s,].*)?$",
|
||||||
|
QRegularExpression::CaseInsensitiveOption));
|
||||||
|
foreach(QString domainGroup, domainGroups) {
|
||||||
|
userPerms &= ~_server->_settingsManager.getForbiddensForGroup(domainGroup, QUuid());
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
qDebug() << "| user-permissions: domain user is in blacklist group:" << domainGroup << "so:" << userPerms;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
userPerms.setVerifiedDomainUserName(verifiedDomainUserName);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
qDebug() << "| user-permissions: final:" << userPerms;
|
qDebug() << "| user-permissions: final:" << userPerms;
|
||||||
#endif
|
#endif
|
||||||
|
@ -309,7 +331,6 @@ void DomainGatekeeper::updateNodePermissions() {
|
||||||
// authentication and verifiedUsername is only set once they user's key has been confirmed.
|
// authentication and verifiedUsername is only set once they user's key has been confirmed.
|
||||||
QString verifiedUsername = node->getPermissions().getVerifiedUserName();
|
QString verifiedUsername = node->getPermissions().getVerifiedUserName();
|
||||||
QString verifiedDomainUserName = node->getPermissions().getVerifiedDomainUserName();
|
QString verifiedDomainUserName = node->getPermissions().getVerifiedDomainUserName();
|
||||||
QStringList verifiedDomainUserGroups = node->getPermissions().getVerifiedDomainUserGroups();
|
|
||||||
NodePermissions userPerms(NodePermissionsKey(verifiedUsername, 0));
|
NodePermissions userPerms(NodePermissionsKey(verifiedUsername, 0));
|
||||||
|
|
||||||
if (node->getPermissions().isAssignment) {
|
if (node->getPermissions().isAssignment) {
|
||||||
|
@ -345,8 +366,7 @@ void DomainGatekeeper::updateNodePermissions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, verifiedDomainUserName,
|
userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, verifiedDomainUserName,
|
||||||
verifiedDomainUserGroups, connectingAddr.getAddress(),
|
connectingAddr.getAddress(), hardwareAddress, machineFingerprint);
|
||||||
hardwareAddress, machineFingerprint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
node->setPermissions(userPerms);
|
node->setPermissions(userPerms);
|
||||||
|
@ -486,31 +506,28 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
|
||||||
|
|
||||||
// ####### TODO: OAuth2 corollary of metaverse code, above.
|
// ####### TODO: OAuth2 corollary of metaverse code, above.
|
||||||
|
|
||||||
|
getDomainGroupMemberships(domainUsernameSignature); // Optimistically get started on group memberships.
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
qDebug() << "stalling login because we have no domain username-signature:" << domainUsername;
|
||||||
|
#endif
|
||||||
return SharedNodePointer();
|
return SharedNodePointer();
|
||||||
} else if (verifyDomainUserSignature(domainUsername, domainUsernameSignature, nodeConnection.senderSockAddr)) {
|
} else if (verifyDomainUserSignature(domainUsername, domainUsernameSignature, nodeConnection.senderSockAddr)) {
|
||||||
// User's domain identity is confirmed.
|
// User's domain identity is confirmed.
|
||||||
|
getDomainGroupMemberships(domainUsername);
|
||||||
// ####### TODO: Get user's domain group memberships (WordPress roles) from domain.
|
|
||||||
// This may already be provided at the same time as the "verify" call to the domain API.
|
|
||||||
// If it isn't, need to initiate getting them then handle their receipt along the lines of the
|
|
||||||
// metaverse code, above.
|
|
||||||
verifiedDomainUserGroups = QString("test-group").toLower().split(" ");
|
|
||||||
|
|
||||||
verifiedDomainUsername = domainUsername.toLower();
|
verifiedDomainUsername = domainUsername.toLower();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// User's identity didn't check out.
|
// User's identity didn't check out.
|
||||||
|
|
||||||
// ####### TODO: OAuth2 corollary of metaverse code, above.
|
// ####### TODO: OAuth2 corollary of metaverse code, above.
|
||||||
|
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
qDebug() << "stalling login because signature verification failed:" << username;
|
qDebug() << "stalling login because domain signature verification failed:" << domainUsername;
|
||||||
#endif
|
#endif
|
||||||
return SharedNodePointer();
|
return SharedNodePointer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, verifiedDomainUsername, verifiedDomainUserGroups,
|
userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, verifiedDomainUsername,
|
||||||
nodeConnection.senderSockAddr.getAddress(), nodeConnection.hardwareAddress,
|
nodeConnection.senderSockAddr.getAddress(), nodeConnection.hardwareAddress,
|
||||||
nodeConnection.machineFingerprint);
|
nodeConnection.machineFingerprint);
|
||||||
|
|
||||||
|
@ -1004,7 +1021,6 @@ void DomainGatekeeper::getGroupMemberships(const QString& username) {
|
||||||
AccountManagerAuth::Required,
|
AccountManagerAuth::Required,
|
||||||
QNetworkAccessManager::PostOperation, callbackParams,
|
QNetworkAccessManager::PostOperation, callbackParams,
|
||||||
QJsonDocument(json).toJson());
|
QJsonDocument(json).toJson());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString extractUsernameFromGroupMembershipsReply(QNetworkReply* requestReply) {
|
QString extractUsernameFromGroupMembershipsReply(QNetworkReply* requestReply) {
|
||||||
|
@ -1059,6 +1075,21 @@ void DomainGatekeeper::getIsGroupMemberErrorCallback(QNetworkReply* requestReply
|
||||||
_inFlightGroupMembershipsRequests.remove(extractUsernameFromGroupMembershipsReply(requestReply));
|
_inFlightGroupMembershipsRequests.remove(extractUsernameFromGroupMembershipsReply(requestReply));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DomainGatekeeper::getDomainGroupMemberships(const QString& domainUserName) {
|
||||||
|
|
||||||
|
// ####### TODO: Get user's domain group memberships (WordPress roles) from domain.
|
||||||
|
// This may be able to be provided at the same time as the "authenticate user" call to the domain API, in which case
|
||||||
|
// a copy of some of the following code can be made there. However, this code is still needed for refreshing groups.
|
||||||
|
|
||||||
|
// ####### TODO: Check how often this method and the WordPress API is called.
|
||||||
|
|
||||||
|
QStringList wordpressGroupsForUser;
|
||||||
|
wordpressGroupsForUser << "silVER" << "gold" << "coal";
|
||||||
|
_domainGroupMemberships[domainUserName] = wordpressGroupsForUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DomainGatekeeper::getDomainOwnerFriendsList() {
|
void DomainGatekeeper::getDomainOwnerFriendsList() {
|
||||||
JSONCallbackParameters callbackParams;
|
JSONCallbackParameters callbackParams;
|
||||||
callbackParams.callbackReceiver = this;
|
callbackParams.callbackReceiver = this;
|
||||||
|
@ -1107,6 +1138,7 @@ void DomainGatekeeper::getDomainOwnerFriendsListErrorCallback(QNetworkReply* req
|
||||||
qDebug() << "getDomainOwnerFriendsList api call failed:" << requestReply->error();
|
qDebug() << "getDomainOwnerFriendsList api call failed:" << requestReply->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ####### TODO: Domain equivalent or addition
|
||||||
void DomainGatekeeper::refreshGroupsCache() {
|
void DomainGatekeeper::refreshGroupsCache() {
|
||||||
// if agents are connected to this domain, refresh our cached information about groups and memberships in such.
|
// if agents are connected to this domain, refresh our cached information about groups and memberships in such.
|
||||||
getDomainOwnerFriendsList();
|
getDomainOwnerFriendsList();
|
||||||
|
|
|
@ -128,14 +128,17 @@ private:
|
||||||
QSet<QString> _inFlightGroupMembershipsRequests; // keep track of which we've already asked for
|
QSet<QString> _inFlightGroupMembershipsRequests; // keep track of which we've already asked for
|
||||||
|
|
||||||
NodePermissions setPermissionsForUser(bool isLocalUser, QString verifiedUsername, QString verifiedDomainUsername,
|
NodePermissions setPermissionsForUser(bool isLocalUser, QString verifiedUsername, QString verifiedDomainUsername,
|
||||||
QStringList verifiedDomainUserGroups, const QHostAddress& senderAddress,
|
const QHostAddress& senderAddress, const QString& hardwareAddress,
|
||||||
const QString& hardwareAddress, const QUuid& machineFingerprint);
|
const QUuid& machineFingerprint);
|
||||||
|
|
||||||
void getGroupMemberships(const QString& username);
|
void getGroupMemberships(const QString& username);
|
||||||
// void getIsGroupMember(const QString& username, const QUuid groupID);
|
// void getIsGroupMember(const QString& username, const QUuid groupID);
|
||||||
void getDomainOwnerFriendsList();
|
void getDomainOwnerFriendsList();
|
||||||
|
|
||||||
|
// Login and groups for domain, separate from metaverse.
|
||||||
bool domainHasLogin();
|
bool domainHasLogin();
|
||||||
|
void getDomainGroupMemberships(const QString& domainUserName);
|
||||||
|
QHash<QString, QStringList> _domainGroupMemberships; // <domainUserName, [domainGroupName]>
|
||||||
|
|
||||||
// Local ID management.
|
// Local ID management.
|
||||||
void initLocalIDManagement();
|
void initLocalIDManagement();
|
||||||
|
|
|
@ -2185,6 +2185,24 @@ QList<QUuid> DomainServerSettingsManager::getBlacklistGroupIDs() {
|
||||||
return result.toList();
|
return result.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList DomainServerSettingsManager::getDomainGroupNames() {
|
||||||
|
// Names as configured in domain server; not necessarily mnetaverse groups.
|
||||||
|
QSet<QString> result;
|
||||||
|
foreach(NodePermissionsKey groupKey, _groupPermissions.keys()) {
|
||||||
|
result += _groupPermissions[groupKey]->getID();
|
||||||
|
}
|
||||||
|
return result.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList DomainServerSettingsManager::getDomainBlacklistGroupNames() {
|
||||||
|
// Names as configured in domain server; not necessarily mnetaverse groups.
|
||||||
|
QSet<QString> result;
|
||||||
|
foreach (NodePermissionsKey groupKey, _groupForbiddens.keys()) {
|
||||||
|
result += _groupForbiddens[groupKey]->getID();
|
||||||
|
}
|
||||||
|
return result.toList();
|
||||||
|
}
|
||||||
|
|
||||||
void DomainServerSettingsManager::debugDumpGroupsState() {
|
void DomainServerSettingsManager::debugDumpGroupsState() {
|
||||||
qDebug() << "--------- GROUPS ---------";
|
qDebug() << "--------- GROUPS ---------";
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,9 @@ public:
|
||||||
QList<QUuid> getGroupIDs();
|
QList<QUuid> getGroupIDs();
|
||||||
QList<QUuid> getBlacklistGroupIDs();
|
QList<QUuid> getBlacklistGroupIDs();
|
||||||
|
|
||||||
|
QStringList getDomainGroupNames();
|
||||||
|
QStringList getDomainBlacklistGroupNames();
|
||||||
|
|
||||||
// these are used to locally cache the result of calling "api/v1/groups/.../is_member/..." on metaverse's api
|
// 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 clearGroupMemberships(const QString& name) { _groupMembership[name.toLower()].clear(); }
|
||||||
void recordGroupMembership(const QString& name, const QUuid groupID, QUuid rankID);
|
void recordGroupMembership(const QString& name, const QUuid groupID, QUuid rankID);
|
||||||
|
|
|
@ -54,8 +54,6 @@ public:
|
||||||
|
|
||||||
void setVerifiedDomainUserName(QString userName) { _verifiedDomainUserName = userName.toLower(); }
|
void setVerifiedDomainUserName(QString userName) { _verifiedDomainUserName = userName.toLower(); }
|
||||||
const QString& getVerifiedDomainUserName() const { return _verifiedDomainUserName; }
|
const QString& getVerifiedDomainUserName() const { return _verifiedDomainUserName; }
|
||||||
void setVerifiedDomainUserGroups(QStringList userGroups) { _verifiedDomainUserGroups = userGroups; }
|
|
||||||
const QStringList& getVerifiedDomainUserGroups() const { return _verifiedDomainUserGroups; }
|
|
||||||
|
|
||||||
void setGroupID(QUuid groupID) { _groupID = groupID; if (!groupID.isNull()) { _groupIDSet = true; }}
|
void setGroupID(QUuid groupID) { _groupID = groupID; if (!groupID.isNull()) { _groupIDSet = true; }}
|
||||||
QUuid getGroupID() const { return _groupID; }
|
QUuid getGroupID() const { return _groupID; }
|
||||||
|
@ -106,7 +104,6 @@ protected:
|
||||||
QUuid _rankID { QUuid() }; // 0 unless this is for a group
|
QUuid _rankID { QUuid() }; // 0 unless this is for a group
|
||||||
QString _verifiedUserName;
|
QString _verifiedUserName;
|
||||||
QString _verifiedDomainUserName;
|
QString _verifiedDomainUserName;
|
||||||
QStringList _verifiedDomainUserGroups;
|
|
||||||
|
|
||||||
bool _groupIDSet { false };
|
bool _groupIDSet { false };
|
||||||
QUuid _groupID;
|
QUuid _groupID;
|
||||||
|
|
Loading…
Reference in a new issue