mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
Merge pull request #9221 from davidkelly/dk/machineFingerprintToDS
Adding Machine Fingerprint to Domain Server permissions
This commit is contained in:
commit
c0d7c06d4a
13 changed files with 180 additions and 15 deletions
|
@ -845,6 +845,78 @@
|
|||
}
|
||||
],
|
||||
|
||||
"columns": [
|
||||
{
|
||||
"name": "permissions_id",
|
||||
"label": ""
|
||||
},
|
||||
{
|
||||
"name": "id_can_connect",
|
||||
"label": "Connect",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"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": "id_can_kick",
|
||||
"label": "Kick Users",
|
||||
"type": "checkbox",
|
||||
"editable": true,
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "machine_fingerprint_permissions",
|
||||
"type": "table",
|
||||
"caption": "Permissions for Users with Machine Fingerprints",
|
||||
"can_add_new_rows": true,
|
||||
"groups": [
|
||||
{
|
||||
"label": "Machine Fingerprint",
|
||||
"span": 1
|
||||
},
|
||||
{
|
||||
"label": "Permissions <a data-toggle='tooltip' data-html='true' title='<p><strong>Domain-Wide Machine Fingerprint Permissions</strong></p><ul><li><strong>Connect</strong><br />Sets whether users with specific Machine Fingerprints can connect to the domain.</li><li><strong>Lock / Unlock</strong><br />Sets whether users from specific Machine Fingerprints 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 with specific Machine Fingerprints can create new entities.</li><li><strong>Rez Temporary</strong><br />Sets whether users with specific Machine Fingerprints can create new entities with a finite lifetime.</li><li><strong>Write Assets</strong><br />Sets whether users with specific Machine Fingerprints can make changes to the domain’s asset-server assets.</li><li><strong>Ignore Max Capacity</strong><br />Sets whether users with specific Machine Fingerprints can connect even if the domain has reached or exceeded its maximum allowed agents.</li></ul><p>Note that permissions assigned to a specific Machine Fingerprint will supersede any parameter-level permissions that might otherwise apply to that user (from groups or standard permissions above). Machine Fingerprint address permissions are overriden if the user has their own row in the users section.</p>'>?</a>",
|
||||
"span": 7
|
||||
}
|
||||
],
|
||||
|
||||
"columns": [
|
||||
{
|
||||
"name": "permissions_id",
|
||||
|
|
|
@ -120,19 +120,21 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer<ReceivedMessag
|
|||
nodeData->setPlaceName(nodeConnection.placeName);
|
||||
|
||||
qDebug() << "Allowed connection from node" << uuidStringWithoutCurlyBraces(node->getUUID())
|
||||
<< "on" << message->getSenderSockAddr() << "with MAC" << nodeConnection.hardwareAddress;
|
||||
<< "on" << message->getSenderSockAddr() << "with MAC" << nodeConnection.hardwareAddress
|
||||
<< "and machine fingerprint" << nodeConnection.machineFingerprint;
|
||||
|
||||
// signal that we just connected a node so the DomainServer can get it a list
|
||||
// and broadcast its presence right away
|
||||
emit connectedNode(node);
|
||||
} else {
|
||||
qDebug() << "Refusing connection from node at" << message->getSenderSockAddr()
|
||||
<< "with hardware address" << nodeConnection.hardwareAddress;
|
||||
<< "with hardware address" << nodeConnection.hardwareAddress
|
||||
<< "and machine fingerprint" << nodeConnection.machineFingerprint;
|
||||
}
|
||||
}
|
||||
|
||||
NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QString verifiedUsername,
|
||||
const QHostAddress& senderAddress, const QString& hardwareAddress) {
|
||||
NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QString verifiedUsername, const QHostAddress& senderAddress,
|
||||
const QString& hardwareAddress, const QUuid& machineFingerprint) {
|
||||
NodePermissions userPerms;
|
||||
|
||||
userPerms.setAll(false);
|
||||
|
@ -155,6 +157,11 @@ NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QStrin
|
|||
|
||||
#ifdef WANT_DEBUG
|
||||
qDebug() << "| user-permissions: specific MAC matches, so:" << userPerms;
|
||||
#endif
|
||||
} else if (_server->_settingsManager.hasPermissionsForMachineFingerprint(machineFingerprint)) {
|
||||
userPerms = _server->_settingsManager.getPermissionsForMachineFingerprint(machineFingerprint);
|
||||
#ifdef WANT_DEBUG
|
||||
qDebug(() << "| user-permissions: specific Machine Fingerprint matches, so: " << userPerms;
|
||||
#endif
|
||||
} else if (_server->_settingsManager.hasPermissionsForIP(senderAddress)) {
|
||||
// this user comes from an IP we have in our permissions table, apply those permissions
|
||||
|
@ -274,13 +281,15 @@ void DomainGatekeeper::updateNodePermissions() {
|
|||
HifiSockAddr connectingAddr = node->getActiveSocket() ? *node->getActiveSocket() : node->getPublicSocket();
|
||||
|
||||
QString hardwareAddress;
|
||||
QUuid machineFingerprint;
|
||||
|
||||
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
|
||||
if (nodeData) {
|
||||
hardwareAddress = nodeData->getHardwareAddress();
|
||||
machineFingerprint = nodeData->getMachineFingerprint();
|
||||
}
|
||||
|
||||
userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, connectingAddr.getAddress(), hardwareAddress);
|
||||
userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, connectingAddr.getAddress(), hardwareAddress, machineFingerprint);
|
||||
}
|
||||
|
||||
node->setPermissions(userPerms);
|
||||
|
@ -334,6 +343,8 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo
|
|||
nodeData->setWalletUUID(it->second.getWalletUUID());
|
||||
nodeData->setNodeVersion(it->second.getNodeVersion());
|
||||
nodeData->setHardwareAddress(nodeConnection.hardwareAddress);
|
||||
nodeData->setMachineFingerprint(nodeConnection.machineFingerprint);
|
||||
|
||||
nodeData->setWasAssigned(true);
|
||||
|
||||
// cleanup the PendingAssignedNodeData for this assignment now that it's connecting
|
||||
|
@ -396,7 +407,7 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
|
|||
}
|
||||
|
||||
userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, nodeConnection.senderSockAddr.getAddress(),
|
||||
nodeConnection.hardwareAddress);
|
||||
nodeConnection.hardwareAddress, nodeConnection.machineFingerprint);
|
||||
|
||||
if (!userPerms.can(NodePermissions::Permission::canConnectToDomain)) {
|
||||
sendConnectionDeniedPacket("You lack the required permissions to connect to this domain.",
|
||||
|
@ -455,6 +466,9 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
|
|||
// set the hardware address passed in the connect request
|
||||
nodeData->setHardwareAddress(nodeConnection.hardwareAddress);
|
||||
|
||||
// set the machine fingerprint passed in the connect request
|
||||
nodeData->setMachineFingerprint(nodeConnection.machineFingerprint);
|
||||
|
||||
// also add an interpolation to DomainServerNodeData so that servers can get username in stats
|
||||
nodeData->addOverrideForKey(USERNAME_UUID_REPLACEMENT_STATS_KEY,
|
||||
uuidStringWithoutCurlyBraces(newNode->getUUID()), username);
|
||||
|
|
|
@ -107,8 +107,8 @@ private:
|
|||
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);
|
||||
NodePermissions setPermissionsForUser(bool isLocalUser, QString verifiedUsername, const QHostAddress& senderAddress,
|
||||
const QString& hardwareAddress, const QUuid& machineFingerprint);
|
||||
|
||||
void getGroupMemberships(const QString& username);
|
||||
// void getIsGroupMember(const QString& username, const QUuid groupID);
|
||||
|
|
|
@ -56,7 +56,10 @@ public:
|
|||
|
||||
void setHardwareAddress(const QString& hardwareAddress) { _hardwareAddress = hardwareAddress; }
|
||||
const QString& getHardwareAddress() { return _hardwareAddress; }
|
||||
|
||||
|
||||
void setMachineFingerprint(const QUuid& machineFingerprint) { _machineFingerprint = machineFingerprint; }
|
||||
const QUuid& getMachineFingerprint() { return _machineFingerprint; }
|
||||
|
||||
void addOverrideForKey(const QString& key, const QString& value, const QString& overrideValue);
|
||||
void removeOverrideForKey(const QString& key, const QString& value);
|
||||
|
||||
|
@ -85,6 +88,7 @@ private:
|
|||
NodeSet _nodeInterestSet;
|
||||
QString _nodeVersion;
|
||||
QString _hardwareAddress;
|
||||
QUuid _machineFingerprint;
|
||||
|
||||
QString _placeName;
|
||||
|
||||
|
|
|
@ -444,6 +444,9 @@ void DomainServerSettingsManager::packPermissions() {
|
|||
// save settings for MAC addresses
|
||||
packPermissionsForMap("permissions", _macPermissions, MAC_PERMISSIONS_KEYPATH);
|
||||
|
||||
// save settings for Machine Fingerprint
|
||||
packPermissionsForMap("permissions", _machineFingerprintPermissions, MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH);
|
||||
|
||||
// save settings for groups
|
||||
packPermissionsForMap("permissions", _groupPermissions, GROUP_PERMISSIONS_KEYPATH);
|
||||
|
||||
|
@ -522,6 +525,18 @@ void DomainServerSettingsManager::unpackPermissions() {
|
|||
}
|
||||
});
|
||||
|
||||
needPack |= unpackPermissionsForKeypath(MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH, &_machineFingerprintPermissions,
|
||||
[&](NodePermissionsPointer perms){
|
||||
// make sure that this permission row has valid machine fingerprint
|
||||
if (QUuid(perms->getKey().first) == QUuid()) {
|
||||
_machineFingerprintPermissions.remove(perms->getKey());
|
||||
|
||||
// we removed a row, so we'll need a re-pack
|
||||
needPack = true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
needPack |= unpackPermissionsForKeypath(GROUP_PERMISSIONS_KEYPATH, &_groupPermissions,
|
||||
[&](NodePermissionsPointer perms){
|
||||
|
@ -575,7 +590,9 @@ void DomainServerSettingsManager::unpackPermissions() {
|
|||
QList<QHash<NodePermissionsKey, NodePermissionsPointer>> permissionsSets;
|
||||
permissionsSets << _standardAgentPermissions.get() << _agentPermissions.get()
|
||||
<< _groupPermissions.get() << _groupForbiddens.get()
|
||||
<< _ipPermissions.get() << _macPermissions.get();
|
||||
<< _ipPermissions.get() << _macPermissions.get()
|
||||
<< _machineFingerprintPermissions.get();
|
||||
|
||||
foreach (auto permissionSet, permissionsSets) {
|
||||
QHashIterator<NodePermissionsKey, NodePermissionsPointer> i(permissionSet);
|
||||
while (i.hasNext()) {
|
||||
|
@ -707,9 +724,10 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer<Re
|
|||
ipPermissions->clear(NodePermissions::Permission::canConnectToDomain);
|
||||
}
|
||||
|
||||
// potentially remove connect permissions for the MAC address
|
||||
// potentially remove connect permissions for the MAC address and machine fingerprint
|
||||
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(matchingNode->getLinkedData());
|
||||
if (nodeData) {
|
||||
// mac address first
|
||||
NodePermissionsKey macAddressKey(nodeData->getHardwareAddress(), 0);
|
||||
|
||||
bool hadMACPermissions = hasPermissionsForMAC(nodeData->getHardwareAddress());
|
||||
|
@ -721,6 +739,18 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer<Re
|
|||
|
||||
macPermissions->clear(NodePermissions::Permission::canConnectToDomain);
|
||||
}
|
||||
|
||||
// now for machine fingerprint
|
||||
NodePermissionsKey machineFingerprintKey(nodeData->getMachineFingerprint().toString(), 0);
|
||||
|
||||
bool hadFingerprintPermissions = hasPermissionsForMachineFingerprint(nodeData->getMachineFingerprint());
|
||||
|
||||
auto fingerprintPermissions = _machineFingerprintPermissions[machineFingerprintKey];
|
||||
|
||||
if (!hadFingerprintPermissions || fingerprintPermissions->can(NodePermissions::Permission::canConnectToDomain)) {
|
||||
newPermissions = true;
|
||||
fingerprintPermissions->clear(NodePermissions::Permission::canConnectToDomain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -834,6 +864,16 @@ NodePermissions DomainServerSettingsManager::getPermissionsForMAC(const QString&
|
|||
return nullPermissions;
|
||||
}
|
||||
|
||||
NodePermissions DomainServerSettingsManager::getPermissionsForMachineFingerprint(const QUuid& machineFingerprint) const {
|
||||
NodePermissionsKey fingerprintKey = NodePermissionsKey(machineFingerprint.toString(), 0);
|
||||
if (_machineFingerprintPermissions.contains(fingerprintKey)) {
|
||||
return *(_machineFingerprintPermissions[fingerprintKey].get());
|
||||
}
|
||||
NodePermissions nullPermissions;
|
||||
nullPermissions.setAll(false);
|
||||
return nullPermissions;
|
||||
}
|
||||
|
||||
NodePermissions DomainServerSettingsManager::getPermissionsForGroup(const QString& groupName, QUuid rankID) const {
|
||||
NodePermissionsKey groupRankKey = NodePermissionsKey(groupName, rankID);
|
||||
if (_groupPermissions.contains(groupRankKey)) {
|
||||
|
|
|
@ -32,6 +32,7 @@ const QString AGENT_STANDARD_PERMISSIONS_KEYPATH = "security.standard_permission
|
|||
const QString AGENT_PERMISSIONS_KEYPATH = "security.permissions";
|
||||
const QString IP_PERMISSIONS_KEYPATH = "security.ip_permissions";
|
||||
const QString MAC_PERMISSIONS_KEYPATH = "security.mac_permissions";
|
||||
const QString MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH = "security.machine_fingerprint_permissions";
|
||||
const QString GROUP_PERMISSIONS_KEYPATH = "security.group_permissions";
|
||||
const QString GROUP_FORBIDDENS_KEYPATH = "security.group_forbiddens";
|
||||
|
||||
|
@ -70,6 +71,10 @@ public:
|
|||
bool hasPermissionsForMAC(const QString& macAddress) const { return _macPermissions.contains(macAddress, 0); }
|
||||
NodePermissions getPermissionsForMAC(const QString& macAddress) const;
|
||||
|
||||
// these give access to permissions for specific machine fingerprints from the domain-server settings page
|
||||
bool hasPermissionsForMachineFingerprint(const QUuid& machineFingerprint) { return _machineFingerprintPermissions.contains(machineFingerprint.toString(), 0); }
|
||||
NodePermissions getPermissionsForMachineFingerprint(const QUuid& machineFingerprint) const;
|
||||
|
||||
// these give access to permissions for specific groups from the domain-server settings page
|
||||
bool havePermissionsForGroup(const QString& groupName, QUuid rankID) const {
|
||||
return _groupPermissions.contains(groupName, rankID);
|
||||
|
@ -152,6 +157,7 @@ private:
|
|||
|
||||
NodePermissionsMap _ipPermissions; // permissions granted by node IP address
|
||||
NodePermissionsMap _macPermissions; // permissions granted by node MAC address
|
||||
NodePermissionsMap _machineFingerprintPermissions; // permissions granted by Machine Fingerprint
|
||||
|
||||
NodePermissionsMap _groupPermissions; // permissions granted by membership to specific groups
|
||||
NodePermissionsMap _groupForbiddens; // permissions denied due to membership in a specific group
|
||||
|
|
|
@ -32,6 +32,9 @@ NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, c
|
|||
|
||||
// read the hardware address sent by the client
|
||||
dataStream >> newHeader.hardwareAddress;
|
||||
|
||||
// now the machine fingerprint
|
||||
dataStream >> newHeader.machineFingerprint;
|
||||
}
|
||||
|
||||
dataStream >> newHeader.nodeType
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
QList<NodeType_t> interestList;
|
||||
QString placeName;
|
||||
QString hardwareAddress;
|
||||
QUuid machineFingerprint;
|
||||
|
||||
QByteArray protocolVersion;
|
||||
};
|
||||
|
|
|
@ -17,6 +17,7 @@ find_package(TBB REQUIRED)
|
|||
|
||||
if (APPLE)
|
||||
find_library(FRAMEWORK_IOKIT IOKit)
|
||||
find_library(CORE_FOUNDATION CoreFoundation)
|
||||
endif ()
|
||||
|
||||
if (APPLE AND ${OPENSSL_INCLUDE_DIR} STREQUAL "/usr/include")
|
||||
|
@ -32,7 +33,7 @@ target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES} ${TBB_LIBRARIES})
|
|||
|
||||
# IOKit is needed for getting machine fingerprint
|
||||
if (APPLE)
|
||||
target_link_libraries(${TARGET_NAME} ${FRAMEWORK_IOKIT})
|
||||
target_link_libraries(${TARGET_NAME} ${FRAMEWORK_IOKIT} ${CORE_FOUNDATION})
|
||||
endif (APPLE)
|
||||
|
||||
# libcrypto uses dlopen in libdl
|
||||
|
|
|
@ -10,8 +10,13 @@
|
|||
//
|
||||
|
||||
#include "FingerprintUtils.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <SettingHandle.h>
|
||||
#include <SettingManager.h>
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <comdef.h>
|
||||
#include <Wbemidl.h>
|
||||
|
@ -44,7 +49,15 @@ QString FingerprintUtils::getMachineFingerprintString() {
|
|||
HRESULT hres;
|
||||
IWbemLocator *pLoc = NULL;
|
||||
|
||||
// initialize com
|
||||
// initialize com. Interface already does, but other
|
||||
// users of this lib don't necessarily do so.
|
||||
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
if (FAILED(hres)) {
|
||||
qDebug() << "Failed to initialize COM library!";
|
||||
return uuidString;
|
||||
}
|
||||
|
||||
// initialize WbemLocator
|
||||
hres = CoCreateInstance(
|
||||
CLSID_WbemLocator,
|
||||
0,
|
||||
|
@ -164,6 +177,11 @@ QUuid FingerprintUtils::getMachineFingerprint() {
|
|||
// any errors in getting the string
|
||||
QUuid uuid(uuidString);
|
||||
if (uuid == QUuid()) {
|
||||
// if you cannot read a fallback key cuz we aren't saving them, just generate one for
|
||||
// this session and move on
|
||||
if (DependencyManager::get<Setting::Manager>().isNull()) {
|
||||
return QUuid::createUuid();
|
||||
}
|
||||
// read fallback key (if any)
|
||||
Settings settings;
|
||||
uuid = QUuid(settings.value(FALLBACK_FINGERPRINT_KEY).toString());
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "AddressManager.h"
|
||||
#include "Assignment.h"
|
||||
#include "HifiSockAddr.h"
|
||||
#include "FingerprintUtils.h"
|
||||
|
||||
#include "NetworkLogging.h"
|
||||
#include "udt/PacketHeaders.h"
|
||||
|
@ -371,6 +372,10 @@ void NodeList::sendDomainServerCheckIn() {
|
|||
}
|
||||
|
||||
packetStream << hardwareAddress;
|
||||
|
||||
// add in machine fingerprint
|
||||
QUuid machineFingerprint = FingerprintUtils::getMachineFingerprint();
|
||||
packetStream << machineFingerprint;
|
||||
}
|
||||
|
||||
// pack our data to send to the domain-server including
|
||||
|
|
|
@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
return static_cast<PacketVersion>(DomainConnectionDeniedVersion::IncludesExtraInfo);
|
||||
|
||||
case PacketType::DomainConnectRequest:
|
||||
return static_cast<PacketVersion>(DomainConnectRequestVersion::HasMACAddress);
|
||||
return static_cast<PacketVersion>(DomainConnectRequestVersion::HasMachineFingerprint);
|
||||
|
||||
case PacketType::DomainServerAddedNode:
|
||||
return static_cast<PacketVersion>(DomainServerAddedNodeVersion::PermissionsGrid);
|
||||
|
|
|
@ -212,7 +212,8 @@ enum class DomainConnectRequestVersion : PacketVersion {
|
|||
NoHostname = 17,
|
||||
HasHostname,
|
||||
HasProtocolVersions,
|
||||
HasMACAddress
|
||||
HasMACAddress,
|
||||
HasMachineFingerprint
|
||||
};
|
||||
|
||||
enum class DomainConnectionDeniedVersion : PacketVersion {
|
||||
|
|
Loading…
Reference in a new issue