mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:24:00 +02:00
add a list of blacklist groups which remove permissions rather than grant them
This commit is contained in:
parent
cc1b6f0cb2
commit
ead6e476a9
6 changed files with 237 additions and 12 deletions
|
@ -534,6 +534,77 @@
|
|||
}
|
||||
],
|
||||
|
||||
"columns": [
|
||||
{
|
||||
"name": "permissions_id",
|
||||
"label": "Group Name"
|
||||
},
|
||||
{
|
||||
"name": "group_id",
|
||||
"label": "Group ID",
|
||||
"readonly": true
|
||||
},
|
||||
{
|
||||
"name": "id_can_connect",
|
||||
"label": "Connect",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"name": "id_can_adjust_locks",
|
||||
"label": "Lock / Unlock",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez",
|
||||
"label": "Rez",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_rez_tmp",
|
||||
"label": "Rez Temporary",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_write_to_asset_server",
|
||||
"label": "Write Assets",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "id_can_connect_past_max_capacity",
|
||||
"label": "Ignore Max Capacity",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "group_forbiddens",
|
||||
"type": "table",
|
||||
"caption": "Permissions denied to Users in Groups",
|
||||
"can_add_new_rows": true,
|
||||
|
||||
"groups": [
|
||||
{
|
||||
"label": "Group",
|
||||
"span": 2
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide User Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users in specific groups can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users in specific groups can change the “locked” property of an entity (either from on to off or off to on).</li><li><strong>Rez</strong><br />Sets whether users in specific groups can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users in specific groups can create new entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users in specific groups can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether user in specific groups can connect even if the domain has reached or exceeded its maximum allowed agents.</li></ul><p>Permissions granted to a specific user will be a union of the permissions granted to the groups they are in. Group permissions are only granted if the user doesn’t have their own row in the previous section.</p>'>?</a>",
|
||||
"span": 6
|
||||
}
|
||||
],
|
||||
|
||||
"columns": [
|
||||
{
|
||||
"name": "permissions_id",
|
||||
|
|
|
@ -149,15 +149,21 @@ NodePermissions DomainGatekeeper::applyPermissionsForUser(bool isLocalUser,
|
|||
}
|
||||
|
||||
// if this user is a known member of a group, give them the implied permissions
|
||||
foreach (QUuid groupID, _server->_settingsManager.getKnownGroupIDs()) {
|
||||
if (groupID.isNull()) {
|
||||
continue;
|
||||
}
|
||||
foreach (QUuid groupID, _server->_settingsManager.getGroupIDs()) {
|
||||
if (_server->_settingsManager.isGroupMember(verifiedUsername, groupID)) {
|
||||
userPerms |= _server->_settingsManager.getPermissionsForGroup(groupID);
|
||||
qDebug() << "user-permissions: user is in group:" << groupID << "so:" << userPerms;
|
||||
}
|
||||
}
|
||||
|
||||
// if this user is a known member of a blacklist group, remove the implied permissions
|
||||
foreach (QUuid groupID, _server->_settingsManager.getBlacklistGroupIDs()) {
|
||||
if (_server->_settingsManager.isGroupMember(verifiedUsername, groupID)) {
|
||||
userPerms &= ~_server->_settingsManager.getForbiddensForGroup(groupID);
|
||||
qDebug() << "user-permissions: user is in blacklist group:" << groupID << "so:" << userPerms;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -689,7 +695,7 @@ void DomainGatekeeper::processICEPingReplyPacket(QSharedPointer<ReceivedMessage>
|
|||
void DomainGatekeeper::getGroupMemberships(const QString& username) {
|
||||
// loop through the groups mentioned on the settings page and ask if this user is in each. The replies
|
||||
// will be received asynchronously and permissions will be updated as the answers come in.
|
||||
QList<QUuid> groupIDs = _server->_settingsManager.getKnownGroupIDs();
|
||||
QList<QUuid> groupIDs = _server->_settingsManager.getGroupIDs() + _server->_settingsManager.getBlacklistGroupIDs();
|
||||
foreach (QUuid groupID, groupIDs) {
|
||||
if (groupID.isNull()) {
|
||||
continue;
|
||||
|
|
|
@ -328,6 +328,9 @@ void DomainServerSettingsManager::packPermissions() {
|
|||
// save settings for groups
|
||||
packPermissionsForMap("permissions", _groupPermissions, GROUP_PERMISSIONS_KEYPATH);
|
||||
|
||||
// save settings for blacklist groups
|
||||
packPermissionsForMap("permissions", _groupForbiddens, GROUP_FORBIDDENS_KEYPATH);
|
||||
|
||||
persistToFile();
|
||||
_configMap.loadMasterAndUserConfig(_argumentList);
|
||||
}
|
||||
|
@ -338,6 +341,7 @@ void DomainServerSettingsManager::unpackPermissions() {
|
|||
_standardAgentPermissions.clear();
|
||||
_agentPermissions.clear();
|
||||
_groupPermissions.clear();
|
||||
_groupForbiddens.clear();
|
||||
|
||||
bool foundLocalhost = false;
|
||||
bool foundAnonymous = false;
|
||||
|
@ -363,6 +367,12 @@ void DomainServerSettingsManager::unpackPermissions() {
|
|||
groupPermissions = valueForKeyPath(_configMap.getUserConfig(), GROUP_PERMISSIONS_KEYPATH, true);
|
||||
(*groupPermissions) = QVariantList();
|
||||
}
|
||||
QVariant* groupForbiddens = valueForKeyPath(_configMap.getUserConfig(), GROUP_FORBIDDENS_KEYPATH);
|
||||
if (!groupForbiddens || !groupForbiddens->canConvert(QMetaType::QVariantList)) {
|
||||
qDebug() << "failed to extract group forbiddens from settings.";
|
||||
groupForbiddens = valueForKeyPath(_configMap.getUserConfig(), GROUP_FORBIDDENS_KEYPATH, true);
|
||||
(*groupForbiddens) = QVariantList();
|
||||
}
|
||||
|
||||
QList<QVariant> standardPermissionsList = standardPermissions->toList();
|
||||
foreach (QVariant permsHash, standardPermissionsList) {
|
||||
|
@ -411,6 +421,23 @@ void DomainServerSettingsManager::unpackPermissions() {
|
|||
}
|
||||
}
|
||||
|
||||
QList<QVariant> groupForbiddensList = groupForbiddens->toList();
|
||||
foreach (QVariant permsHash, groupForbiddensList) {
|
||||
NodePermissionsPointer perms { new NodePermissions(permsHash.toMap()) };
|
||||
QString id = perms->getID();
|
||||
if (_groupForbiddens.contains(id)) {
|
||||
qDebug() << "duplicate name in group forbiddens table: " << id;
|
||||
_groupForbiddens[id] |= perms;
|
||||
needPack = true;
|
||||
} else {
|
||||
_groupForbiddens[id] = perms;
|
||||
}
|
||||
if (perms->isGroup()) {
|
||||
// the group-id was cached. hook-up the id in the id->group hash
|
||||
_groupByID[perms->getGroupID()] = _groupForbiddens[id];
|
||||
}
|
||||
}
|
||||
|
||||
// if any of the standard names are missing, add them
|
||||
if (!foundLocalhost) {
|
||||
NodePermissionsPointer perms { new NodePermissions(NodePermissions::standardNameLocalhost) };
|
||||
|
@ -445,7 +472,8 @@ void DomainServerSettingsManager::unpackPermissions() {
|
|||
#ifdef WANT_DEBUG
|
||||
qDebug() << "--------------- permissions ---------------------";
|
||||
QList<QHash<QString, NodePermissionsPointer>> permissionsSets;
|
||||
permissionsSets << _standardAgentPermissions.get() << _agentPermissions.get() << _groupPermissions.get();
|
||||
permissionsSets << _standardAgentPermissions.get() << _agentPermissions.get()
|
||||
<< _groupPermissions.get() << _groupForbiddens.get();
|
||||
foreach (auto permissionSet, permissionsSets) {
|
||||
QHashIterator<QString, NodePermissionsPointer> i(permissionSet);
|
||||
while (i.hasNext()) {
|
||||
|
@ -499,6 +527,27 @@ NodePermissions DomainServerSettingsManager::getPermissionsForGroup(const QUuid&
|
|||
}
|
||||
|
||||
|
||||
NodePermissions DomainServerSettingsManager::getForbiddensForGroup(const QString& groupname) const {
|
||||
if (_groupForbiddens.contains(groupname)) {
|
||||
return *(_groupForbiddens[groupname].get());
|
||||
}
|
||||
NodePermissions nullForbiddens;
|
||||
nullForbiddens.setAll(false);
|
||||
return nullForbiddens;
|
||||
}
|
||||
|
||||
NodePermissions DomainServerSettingsManager::getForbiddensForGroup(const QUuid& groupID) const {
|
||||
if (!_groupByID.contains(groupID)) {
|
||||
NodePermissions nullForbiddens;
|
||||
nullForbiddens.setAll(false);
|
||||
return nullForbiddens;
|
||||
}
|
||||
QString groupName = _groupByID[groupID]->getID();
|
||||
return getForbiddensForGroup(groupName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
QVariant DomainServerSettingsManager::valueOrDefaultValueForKeyPath(const QString& keyPath) {
|
||||
const QVariant* foundValue = valueForKeyPath(_configMap.getMergedConfig(), keyPath);
|
||||
|
||||
|
@ -920,10 +969,22 @@ void DomainServerSettingsManager::persistToFile() {
|
|||
}
|
||||
|
||||
void DomainServerSettingsManager::requestMissingGroupIDs() {
|
||||
QHashIterator<QString, NodePermissionsPointer> i(_groupPermissions.get());
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
NodePermissionsPointer perms = i.value();
|
||||
QHashIterator<QString, NodePermissionsPointer> i_permissions(_groupPermissions.get());
|
||||
while (i_permissions.hasNext()) {
|
||||
i_permissions.next();
|
||||
NodePermissionsPointer perms = i_permissions.value();
|
||||
if (!perms->getGroupID().isNull()) {
|
||||
// we already know this group's ID
|
||||
continue;
|
||||
}
|
||||
|
||||
// make a call to metaverse api to turn the group name into a group ID
|
||||
getGroupID(perms->getID());
|
||||
}
|
||||
QHashIterator<QString, NodePermissionsPointer> i_forbiddens(_groupForbiddens.get());
|
||||
while (i_forbiddens.hasNext()) {
|
||||
i_forbiddens.next();
|
||||
NodePermissionsPointer perms = i_forbiddens.value();
|
||||
if (!perms->getGroupID().isNull()) {
|
||||
// we already know this group's ID
|
||||
continue;
|
||||
|
@ -964,10 +1025,21 @@ void DomainServerSettingsManager::getGroupIDJSONCallback(QNetworkReply& requestR
|
|||
QString groupName = jsonObject["group_name"].toString();
|
||||
QUuid groupID = QUuid(jsonObject["group_id"].toString());
|
||||
|
||||
bool found = false;
|
||||
if (_groupPermissions.contains(groupName)) {
|
||||
qDebug() << "ID for group:" << groupName << "is" << groupID;
|
||||
_groupPermissions[groupName]->setGroupID(groupID);
|
||||
_groupByID[groupID] = _groupPermissions[groupName];
|
||||
found = true;
|
||||
}
|
||||
if (_groupForbiddens.contains(groupName)) {
|
||||
qDebug() << "ID for group:" << groupName << "is" << groupID;
|
||||
_groupForbiddens[groupName]->setGroupID(groupID);
|
||||
_groupByID[groupID] = _groupForbiddens[groupName];
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
packPermissions();
|
||||
} else {
|
||||
qDebug() << "DomainServerSettingsManager::getGroupIDJSONCallback got response for unknown group:" << groupName;
|
||||
|
@ -988,3 +1060,23 @@ void DomainServerSettingsManager::recordGroupMembership(const QString& name, con
|
|||
bool DomainServerSettingsManager::isGroupMember(const QString& name, const QUuid& groupID) {
|
||||
return _groupMembership[name][groupID];
|
||||
}
|
||||
|
||||
QList<QUuid> DomainServerSettingsManager::getGroupIDs() {
|
||||
QList<QUuid> result;
|
||||
foreach (QString groupName, _groupPermissions.keys()) {
|
||||
if (_groupPermissions[groupName]->isGroup()) {
|
||||
result << _groupPermissions[groupName]->getGroupID();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<QUuid> DomainServerSettingsManager::getBlacklistGroupIDs() {
|
||||
QList<QUuid> result;
|
||||
foreach (QString groupName, _groupForbiddens.keys()) {
|
||||
if (_groupForbiddens[groupName]->isGroup()) {
|
||||
result << _groupForbiddens[groupName]->getGroupID();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ const QString SETTINGS_PATH_JSON = SETTINGS_PATH + ".json";
|
|||
const QString AGENT_STANDARD_PERMISSIONS_KEYPATH = "security.standard_permissions";
|
||||
const QString AGENT_PERMISSIONS_KEYPATH = "security.permissions";
|
||||
const QString GROUP_PERMISSIONS_KEYPATH = "security.group_permissions";
|
||||
const QString GROUP_FORBIDDENS_KEYPATH = "security.group_forbiddens";
|
||||
|
||||
class DomainServerSettingsManager : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -55,7 +56,14 @@ public:
|
|||
bool havePermissionsForGroup(const QString& groupname) const { return _groupPermissions.contains(groupname); }
|
||||
NodePermissions getPermissionsForGroup(const QString& groupname) const;
|
||||
NodePermissions getPermissionsForGroup(const QUuid& groupID) const;
|
||||
QList<QUuid> getKnownGroupIDs() { return _groupByID.keys(); }
|
||||
|
||||
// these remove permissions from users in certain groups
|
||||
bool haveForbiddensForGroup(const QString& groupname) const { return _groupForbiddens.contains(groupname); }
|
||||
NodePermissions getForbiddensForGroup(const QString& groupname) const;
|
||||
NodePermissions getForbiddensForGroup(const QUuid& groupID) const;
|
||||
|
||||
QList<QUuid> getGroupIDs();
|
||||
QList<QUuid> getBlacklistGroupIDs();
|
||||
|
||||
// these are used to locally cache the result of calling "api/v1/groups/.../is_member/..." on metaverse's api
|
||||
void recordGroupMembership(const QString& name, const QUuid groupID, bool isMember);
|
||||
|
@ -100,7 +108,8 @@ private:
|
|||
|
||||
NodePermissionsMap _standardAgentPermissions; // anonymous, logged-in, localhost
|
||||
NodePermissionsMap _agentPermissions; // specific account-names
|
||||
NodePermissionsMap _groupPermissions; // permissions granted by membershipt to specific groups
|
||||
NodePermissionsMap _groupPermissions; // permissions granted by membership to specific groups
|
||||
NodePermissionsMap _groupForbiddens; // permissions denied due to membership in a specific group
|
||||
QHash<QUuid, NodePermissionsPointer> _groupByID; // similar to _groupPermissions but key is group-id rather than name
|
||||
|
||||
// keep track of answers to api queries about which users are in which groups
|
||||
|
|
|
@ -85,6 +85,48 @@ NodePermissionsPointer& operator|=(NodePermissionsPointer& lhs, const NodePermis
|
|||
return lhs;
|
||||
}
|
||||
|
||||
NodePermissions& NodePermissions::operator&=(const NodePermissions& rhs) {
|
||||
this->canConnectToDomain &= rhs.canConnectToDomain;
|
||||
this->canAdjustLocks &= rhs.canAdjustLocks;
|
||||
this->canRezPermanentEntities &= rhs.canRezPermanentEntities;
|
||||
this->canRezTemporaryEntities &= rhs.canRezTemporaryEntities;
|
||||
this->canWriteToAssetServer &= rhs.canWriteToAssetServer;
|
||||
this->canConnectPastMaxCapacity &= rhs.canConnectPastMaxCapacity;
|
||||
return *this;
|
||||
}
|
||||
NodePermissions& NodePermissions::operator&=(const NodePermissionsPointer& rhs) {
|
||||
if (rhs) {
|
||||
*this &= *rhs.get();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
NodePermissionsPointer& operator&=(NodePermissionsPointer& lhs, const NodePermissionsPointer& rhs) {
|
||||
if (lhs && rhs) {
|
||||
*lhs.get() &= rhs;
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
NodePermissions NodePermissions::operator~() {
|
||||
NodePermissions result = *this;
|
||||
result.canConnectToDomain = !result.canConnectToDomain;
|
||||
result.canAdjustLocks = !result.canAdjustLocks;
|
||||
result.canRezPermanentEntities = !result.canRezPermanentEntities;
|
||||
result.canRezTemporaryEntities = !result.canRezTemporaryEntities;
|
||||
result.canWriteToAssetServer = !result.canWriteToAssetServer;
|
||||
result.canConnectPastMaxCapacity = !result.canConnectPastMaxCapacity;
|
||||
return result;
|
||||
}
|
||||
|
||||
NodePermissionsPointer operator~(NodePermissionsPointer& lhs) {
|
||||
if (lhs) {
|
||||
NodePermissionsPointer result { new NodePermissions };
|
||||
(*result.get()) = ~(*lhs.get());
|
||||
return result;
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
QDataStream& operator<<(QDataStream& out, const NodePermissions& perms) {
|
||||
out << perms.canConnectToDomain;
|
||||
out << perms.canAdjustLocks;
|
||||
|
|
|
@ -60,6 +60,9 @@ public:
|
|||
|
||||
NodePermissions& operator|=(const NodePermissions& rhs);
|
||||
NodePermissions& operator|=(const NodePermissionsPointer& rhs);
|
||||
NodePermissions& operator&=(const NodePermissions& rhs);
|
||||
NodePermissions& operator&=(const NodePermissionsPointer& rhs);
|
||||
NodePermissions operator~();
|
||||
friend QDataStream& operator<<(QDataStream& out, const NodePermissions& perms);
|
||||
friend QDataStream& operator>>(QDataStream& in, NodePermissions& perms);
|
||||
|
||||
|
@ -93,5 +96,7 @@ const NodePermissions DEFAULT_AGENT_PERMISSIONS;
|
|||
QDebug operator<<(QDebug debug, const NodePermissions& perms);
|
||||
QDebug operator<<(QDebug debug, const NodePermissionsPointer& perms);
|
||||
NodePermissionsPointer& operator|=(NodePermissionsPointer& lhs, const NodePermissionsPointer& rhs);
|
||||
NodePermissionsPointer& operator&=(NodePermissionsPointer& lhs, const NodePermissionsPointer& rhs);
|
||||
NodePermissionsPointer operator~(NodePermissionsPointer& lhs);
|
||||
|
||||
#endif // hifi_NodePermissions_h
|
||||
|
|
Loading…
Reference in a new issue