Overte C++ Documentation
DomainServerSettingsManager.h
1 //
2 // DomainServerSettingsManager.h
3 // domain-server/src
4 //
5 // Created by Stephen Birarda on 2014-06-24.
6 // Copyright 2014 High Fidelity, Inc.
7 // Copyright 2020 Vircadia contributors.
8 //
9 // Distributed under the Apache License, Version 2.0.
10 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
11 //
12 
13 #ifndef hifi_DomainServerSettingsManager_h
14 #define hifi_DomainServerSettingsManager_h
15 
16 #include <QtCore/QJsonArray>
17 #include <QtCore/QJsonObject>
18 #include <QtCore/QJsonDocument>
19 #include <QtNetwork/QNetworkReply>
20 #include <QtCore/QSharedPointer>
21 
22 #include <HifiConfigVariantMap.h>
23 #include <HTTPManager.h>
24 #include <Node.h>
25 #include <ReceivedMessage.h>
26 
27 #include "DomainGatekeeper.h"
28 #include "NodePermissions.h"
29 
30 const QString SETTINGS_PATHS_KEY = "paths";
31 
32 const QString AGENT_STANDARD_PERMISSIONS_KEYPATH = "security.standard_permissions";
33 const QString AGENT_PERMISSIONS_KEYPATH = "security.permissions";
34 const QString IP_PERMISSIONS_KEYPATH = "security.ip_permissions";
35 const QString MAC_PERMISSIONS_KEYPATH = "security.mac_permissions";
36 const QString MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH = "security.machine_fingerprint_permissions";
37 const QString GROUP_PERMISSIONS_KEYPATH = "security.group_permissions";
38 const QString GROUP_FORBIDDENS_KEYPATH = "security.group_forbiddens";
39 const QString AUTOMATIC_CONTENT_ARCHIVES_GROUP = "automatic_content_archives";
40 const QString CONTENT_SETTINGS_INSTALLED_CONTENT_FILENAME = "installed_content.filename";
41 const QString CONTENT_SETTINGS_INSTALLED_CONTENT_NAME = "installed_content.name";
42 const QString CONTENT_SETTINGS_INSTALLED_CONTENT_CREATION_TIME = "installed_content.creation_time";
43 const QString CONTENT_SETTINGS_INSTALLED_CONTENT_INSTALL_TIME = "installed_content.install_time";
44 const QString CONTENT_SETTINGS_INSTALLED_CONTENT_INSTALLED_BY = "installed_content.installed_by";
45 
46 using GroupByUUIDKey = QPair<QUuid, QUuid>; // groupID, rankID
47 
48 enum SettingsType {
49  DomainSettings,
50  ContentSettings
51 };
52 
75 class DomainServerSettingsManager : public QObject {
76  Q_OBJECT
77 public:
79  bool handleAuthenticatedHTTPRequest(HTTPConnection* connection, const QUrl& url);
80 
81 
89  void setupConfigMap(const QString& userConfigFilename);
90 
91  // each of the three methods in this group takes a read lock of _settingsLock
92  // and cannot be called when the a write lock is held by the same thread
93  QVariant valueOrDefaultValueForKeyPath(const QString& keyPath);
94  QVariant valueForKeyPath(const QString& keyPath);
95  bool containsKeyPath(const QString& keyPath) { return valueForKeyPath(keyPath).isValid(); }
96 
97  // these give access to anonymous/localhost/logged-in settings from the domain-server settings page
98  bool haveStandardPermissionsForName(const QString& name) const { return _standardAgentPermissions.contains(name, 0); }
99  NodePermissions getStandardPermissionsForName(const NodePermissionsKey& name) const;
100 
101  // these give access to permissions for specific user-names from the domain-server settings page
102  bool havePermissionsForName(const QString& name) const { return _agentPermissions.contains(name, 0); }
103  NodePermissions getPermissionsForName(const QString& name) const;
104  NodePermissions getPermissionsForName(const NodePermissionsKey& key) const { return getPermissionsForName(key.first); }
105  QStringList getAllNames() const;
106 
107  // these give access to permissions for specific IPs from the domain-server settings page
108  bool hasPermissionsForIP(const QHostAddress& address) const { return _ipPermissions.contains(address.toString(), 0); }
109  NodePermissions getPermissionsForIP(const QHostAddress& address) const;
110 
111  // these give access to permissions for specific MACs from the domain-server settings page
112  bool hasPermissionsForMAC(const QString& macAddress) const { return _macPermissions.contains(macAddress, 0); }
113  NodePermissions getPermissionsForMAC(const QString& macAddress) const;
114 
115  // these give access to permissions for specific machine fingerprints from the domain-server settings page
116  bool hasPermissionsForMachineFingerprint(const QUuid& machineFingerprint) { return _machineFingerprintPermissions.contains(machineFingerprint.toString(), 0); }
117  NodePermissions getPermissionsForMachineFingerprint(const QUuid& machineFingerprint) const;
118 
119  // these give access to permissions for specific groups from the domain-server settings page
120  bool havePermissionsForGroup(const QString& groupName, QUuid rankID) const {
121  return _groupPermissions.contains(groupName, rankID);
122  }
123  NodePermissions getPermissionsForGroup(const QString& groupName, QUuid rankID) const;
124  NodePermissions getPermissionsForGroup(const QUuid& groupID, QUuid rankID) const;
125 
126  // these remove permissions from users in certain groups
127  bool haveForbiddensForGroup(const QString& groupName, QUuid rankID) const {
128  return _groupForbiddens.contains(groupName, rankID);
129  }
130  NodePermissions getForbiddensForGroup(const QString& groupName, QUuid rankID) const;
131  NodePermissions getForbiddensForGroup(const QUuid& groupID, QUuid rankID) const;
132 
133  QStringList getAllKnownGroupNames();
134  bool setGroupID(const QString& groupName, const QUuid& groupID);
135  GroupRank getGroupRank(QUuid groupID, QUuid rankID) { return _groupRanks[groupID][rankID]; }
136 
137  QList<QUuid> getGroupIDs();
138  QList<QUuid> getBlacklistGroupIDs();
139 
140  QStringList getDomainServerGroupNames();
141  QStringList getDomainServerBlacklistGroupNames();
142 
143  // these are used to locally cache the result of calling "/api/v1/groups/.../is_member/..." on Directory Services api
144  void clearGroupMemberships(const QString& name) { _groupMembership[name.toLower()].clear(); }
145  void recordGroupMembership(const QString& name, const QUuid groupID, QUuid rankID);
146  QUuid isGroupMember(const QString& name, const QUuid& groupID); // returns rank or -1 if not a member
147 
148  // calls http api to refresh group information
149  void apiRefreshGroupInformation();
150 
151  void debugDumpGroupsState();
152 
153  enum SettingsRequestAuthentication { NotAuthenticated, Authenticated };
154  enum DomainSettingsInclusion { NoDomainSettings, IncludeDomainSettings };
155  enum ContentSettingsInclusion { NoContentSettings, IncludeContentSettings };
156  enum DefaultSettingsInclusion { NoDefaultSettings, IncludeDefaultSettings };
157  enum SettingsBackupFlag { NotForBackup, ForBackup };
158 
174  QJsonObject settingsResponseObjectForType(const QString& typeValue,
175  SettingsRequestAuthentication authentication = NotAuthenticated,
176  DomainSettingsInclusion domainSettingsInclusion = IncludeDomainSettings,
177  ContentSettingsInclusion contentSettingsInclusion = IncludeContentSettings,
178  DefaultSettingsInclusion defaultSettingsInclusion = IncludeDefaultSettings,
179  SettingsBackupFlag settingsBackupFlag = NotForBackup);
181  Q_INVOKABLE bool restoreSettingsFromObject(QJsonObject settingsToRestore, SettingsType settingsType);
182 
183  bool recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, SettingsType settingsType);
184 
185 signals:
186  void updateNodePermissions();
187  void settingsUpdated();
188 
189 public slots:
190  void apiGetGroupIDJSONCallback(QNetworkReply* requestReply);
191  void apiGetGroupIDErrorCallback(QNetworkReply* requestReply);
192  void apiGetGroupRanksJSONCallback(QNetworkReply* requestReply);
193  void apiGetGroupRanksErrorCallback(QNetworkReply* requestReply);
194 
195 private slots:
196  void processSettingsRequestPacket(QSharedPointer<ReceivedMessage> message);
197  void processNodeKickRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
198  void processUsernameFromIDRequestPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
199 
200 private:
201  QJsonArray filteredDescriptionArray(bool isContentSettings);
202  void updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap,
203  const QJsonObject& settingDescription);
204  QJsonObject settingDescriptionFromGroup(const QJsonObject& groupObject, const QString& settingName);
205  void sortPermissions();
206 
207  // you cannot be holding the _settingsLock when persisting to file from the same thread
208  // since it may take either a read lock or write lock and recursive locking doesn't allow a change in type
209  void persistToFile();
210 
211  void splitSettingsDescription();
212 
213  double _descriptionVersion;
214 
215  QJsonArray _descriptionArray;
216  QJsonArray _domainSettingsDescription;
217  QJsonArray _contentSettingsDescription;
218  QJsonObject _settingsMenuGroups;
219 
220  // any method that calls valueForKeyPath on this _configMap must get a write lock it keeps until it
221  // is done with the returned QVariant*
222  HifiConfigVariantMap _configMap;
223 
224  // these cause calls to directory services group api
225  void apiGetGroupID(const QString& groupName);
226  void apiGetGroupRanks(const QUuid& groupID);
227 
228  void initializeGroupPermissions(NodePermissionsMap& permissionsRows, QString groupName, NodePermissionsPointer perms);
229  void packPermissionsForMap(QString mapName, NodePermissionsMap& permissionsRows, QString keyPath);
230  void packPermissions();
231  void unpackPermissions();
232  bool unpackPermissionsForKeypath(const QString& keyPath, NodePermissionsMap* destinationMapPointer,
233  std::function<void(NodePermissionsPointer)> customUnpacker = {});
234  bool ensurePermissionsForGroupRanks();
235 
236  NodePermissionsMap _standardAgentPermissions; // anonymous, logged-in, localhost, friend-of-domain-owner
237  NodePermissionsMap _agentPermissions; // specific account-names
238 
239  NodePermissionsMap _ipPermissions; // permissions granted by node IP address
240  NodePermissionsMap _macPermissions; // permissions granted by node MAC address
241  NodePermissionsMap _machineFingerprintPermissions; // permissions granted by Machine Fingerprint
242 
243  NodePermissionsMap _groupPermissions; // permissions granted by membership to specific groups
244  NodePermissionsMap _groupForbiddens; // permissions denied due to membership in a specific group
245  // these are like _groupPermissions and _groupForbiddens but with uuids rather than group-names in the keys
246  QHash<GroupByUUIDKey, NodePermissionsPointer> _groupPermissionsByUUID;
247  QHash<GroupByUUIDKey, NodePermissionsPointer> _groupForbiddensByUUID;
248 
249  QHash<QString, QUuid> _groupIDs; // keep track of group-name to group-id mappings
250  QHash<QUuid, QString> _groupNames; // keep track of group-id to group-name mappings
251 
252  // remember the responses to api/v1/groups/%1/ranks
253  QHash<QUuid, QHash<QUuid, GroupRank>> _groupRanks; // QHash<group-id, QHash<rankID, rank>>
254 
255  // keep track of answers to api queries about which users are in which groups
256  QHash<QString, QHash<QUuid, QUuid>> _groupMembership; // QHash<user-name, QHash<group-id, rank-id>>
257 
259  QReadWriteLock _settingsLock { QReadWriteLock::Recursive };
260 
261  friend class DomainServer;
262 };
263 
264 #endif // hifi_DomainServerSettingsManager_h
Manages the domain-wide settings.
Definition: DomainServerSettingsManager.h:75
void setupConfigMap(const QString &userConfigFilename)
Loads the configuration from the specified file.
Definition: DomainServerSettingsManager.cpp:206
QJsonObject settingsResponseObjectForType(const QString &typeValue, SettingsRequestAuthentication authentication=NotAuthenticated, DomainSettingsInclusion domainSettingsInclusion=IncludeDomainSettings, ContentSettingsInclusion contentSettingsInclusion=IncludeContentSettings, DefaultSettingsInclusion defaultSettingsInclusion=IncludeDefaultSettings, SettingsBackupFlag settingsBackupFlag=NotForBackup)
Generates a JSON representation of settings.
Definition: DomainServerSettingsManager.cpp:1506
Q_INVOKABLE bool restoreSettingsFromObject(QJsonObject settingsToRestore, SettingsType settingsType)
thread safe method to restore settings from a JSON object
Definition: DomainServerSettingsManager.cpp:1375
Handles a single HTTP connection.
Definition: HTTPConnection.h:43