otsdaq  v2_05_02_indev
WebUsers.h
1 #ifndef _ots_Utilities_WebUsers_h_
2 #define _ots_Utilities_WebUsers_h_
3 
4 #include "otsdaq/Macros/CoutMacros.h"
5 #include "otsdaq/Macros/StringMacros.h"
6 #include "otsdaq/MessageFacility/MessageFacility.h"
7 #include "otsdaq/SOAPUtilities/SOAPMessenger.h"
8 #pragma GCC diagnostic push
9 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
10 #include <xgi/Method.h> //for cgicc::Cgicc
11 #pragma GCC diagnostic pop
12 
13 #include <iostream>
14 #include <mutex>
15 #include <string>
16 #include <unordered_map>
17 #include <vector>
18 
19 #define WEB_LOGIN_DB_PATH std::string(__ENV__("SERVICE_DATA_PATH")) + "/LoginData/"
20 #define WEB_LOGIN_CERTDATA_PATH std::string(__ENV__("CERT_DATA_PATH"))
21 #define HASHES_DB_PATH "HashesData/"
22 #define USERS_DB_PATH "UsersData/"
23 #define USERS_LOGIN_HISTORY_PATH USERS_DB_PATH + "UserLoginHistoryData/"
24 #define USERS_PREFERENCES_PATH USERS_DB_PATH + "UserPreferencesData/"
25 #define TOOLTIP_DB_PATH USERS_DB_PATH + "/TooltipData/"
26 
27 namespace ots
28 {
29 class HttpXmlDocument;
30 
31 // WebUsers
32 // This class provides the functionality for managing all otsdaq user account preferences
33 // and permissions.
34 class WebUsers
35 {
36  // clang-format off
37  public:
38  WebUsers();
39 
40  enum
41  {
42  SESSION_ID_LENGTH = 512,
43  COOKIE_CODE_LENGTH = 512,
44  NOT_FOUND_IN_DATABASE = uint64_t(-1),
45  ACCOUNT_INACTIVE = uint64_t(-2),
46  ACCOUNT_BLACKLISTED = uint64_t(-3),
47  ACCOUNT_ERROR_THRESHOLD = uint64_t(-5),
48  USERNAME_LENGTH = 4,
49  DISPLAY_NAME_LENGTH = 4,
50  };
51 
52  enum
53  {
54  MOD_TYPE_UPDATE,
55  MOD_TYPE_ADD,
56  MOD_TYPE_DELETE
57  };
58 
59  using permissionLevel_t = uint8_t;
60  enum
61  {
62  PERMISSION_LEVEL_ADMIN = WebUsers::permissionLevel_t(-1), // max permission level!
63  PERMISSION_LEVEL_EXPERT = 100,
64  PERMISSION_LEVEL_USER = 10,
65  PERMISSION_LEVEL_NOVICE = 1,
66  PERMISSION_LEVEL_INACTIVE = 0,
67  };
68 
69  static const std::string OTS_OWNER; //defined by environment variable, e.g. experiment name
70 
71  static const std::string DEFAULT_ADMIN_USERNAME;
72  static const std::string DEFAULT_ADMIN_DISPLAY_NAME;
73  static const std::string DEFAULT_ADMIN_EMAIL;
74  static const std::string DEFAULT_ITERATOR_USERNAME;
75  static const std::string DEFAULT_STATECHANGER_USERNAME;
76  static const std::string DEFAULT_USER_GROUP;
77 
78  static const std::string REQ_NO_LOGIN_RESPONSE;
79  static const std::string REQ_NO_PERMISSION_RESPONSE;
80  static const std::string REQ_USER_LOCKOUT_RESPONSE;
81  static const std::string REQ_LOCK_REQUIRED_RESPONSE;
82  static const std::string REQ_ALLOW_NO_USER;
83 
84  static const std::string SECURITY_TYPE_NONE;
85  static const std::string SECURITY_TYPE_DIGEST_ACCESS;
86  static const std::string SECURITY_TYPE_DEFAULT;
87 
88  struct User
89  {
90  //"Users" database associations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
91  //
92  // Maintain list of existing Usernames and associate the following:
93  // - permissions map of group name to permission level (e.g. users, experts, masters) 0 to 255
94  // note: all users are at least in group WebUsers::DEFAULT_USER_GROUP
95  // 0 := account inactive, not allowed to login (e.g. could be due to too many failed login attempts)
96  // 1 := normal user
97  // 255 := admin for things in group
98  // permission level is determined by finding the highest permission level number (0 to
99  // 255) for an allowed group.. then that permission level is compared to the threshold.
100  //
101  // - Last Login attempt time, and last USERS_LOGIN_HISTORY_SIZE successful logins
102  // - Name to display
103  // - random salt, before first login salt is empty string ""
104  // - Keep count of login attempt failures. Limit failures per unit time (e.g. 5 per hour)
105  // - Preferences (e.g. color scheme, etc) Username appends to preferences file, and login history file
106  // - UsersLastModifierUsernameVector - is username of last admin user to modify something about account
107  // - UsersLastModifierTimeVector - is time of last modify by an admin user
108  User():lastLoginAttempt_(0),accountCreationTime_(0),loginFailureCount_(0),
109  lastModifierTime_(time(0)*100000 + (clock()%100000)) {}
110 
111  void setModifier(const std::string& modifierUsername)
112  {
113  lastModifierUsername_ = modifierUsername;
114  lastModifierTime_ = time(0)*100000 + (clock()%100000); //clock used for NAC randomness
115  }
116 
117  void loadModifierUsername(const std::string& modifierUsername)
118  {
119  lastModifierUsername_ = modifierUsername;
120  }
121 
122  time_t& accessModifierTime() { return lastModifierTime_; }
123 
124  time_t getModifierTime(bool convertToRealTime = false) const { return (convertToRealTime?lastModifierTime_/100000:lastModifierTime_); }
125  const std::string& getModifierUsername() const { return lastModifierUsername_; }
126  std::string getNewAccountCode() const {
127 
128  if(salt_ != "") // only give nac if account has not been activated yet with password
129  return "";
130 
131  char charTimeStr[10];
132  sprintf(charTimeStr, "%5.5d", int(lastModifierTime_ & 0xffff));
133  return charTimeStr;
134  } //end getNewAccountCode()
135 
136  std::string username_, email_, displayName_, salt_;
137  std::map<std::string /*groupName*/, WebUsers::permissionLevel_t> permissions_;
138  uint64_t userId_;
139  time_t lastLoginAttempt_, accountCreationTime_;
140  uint8_t loginFailureCount_;
141 
142  private:
143  std::string lastModifierUsername_;
144  time_t lastModifierTime_;
145  }; //end User struct
146 
148  {
149  //"Login Session" database associations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
150  // Generate random sessionId when receive a unique user ID (UUID)
151  // reject UUID that have been used recently (e.g. last 5 minutes)
152  // Maintain list of active sessionIds and associated UUID
153  // remove from list if been idle after some time or login attempts (e.g. 5 minutes or
154  // 3 login attempts) maybe track IP address, to block multiple failed login attempts
155  // from same IP. Use sessionId to un-jumble login attempts, lookup using UUID
156 
157  std::string id_, uuid_, ip_;
158  time_t startTime_;
159  uint8_t loginAttempts_;
160  }; //end LoginSession struct
161 
163  {
164  //"Active Session" database associations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
165  // Maintain list of valid cookieCodes and associated user - all requests
166  // must come with a valid cookieCode, else server fails request.
167  // On logout request, invalidate cookieCode.
168  // cookieCode expires after some idle time (e.g. 5 minutes) and
169  // is renewed and possibly changed each request.
170  // "single user - multiple locations" issue resolved using ActiveSessionIndex
171  // where each independent login starts a new thread of cookieCodes tagged with
172  // ActiveSessionIndex if cookieCode not refreshed, then return most recent cookie code
173 
174  std::string cookieCode_, ip_;
175  uint64_t userId_, sessionIndex_;
176  time_t startTime_;
177  }; //end ActiveSession struct
178 
179  struct Hash
180  {
181  //"Hashes" database associations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
182  // Maintain list of acceptable encoded (SHA-512) salt+user+pw's
183 
184  std::string hash_;
185  time_t accessTime_; // last login month resolution, blurred by 1/2 month
186  }; //end Hash struct
187 
188  enum
189  {
190  SYS_CLEANUP_WILDCARD_TIME = 30, // 30 seconds
191  };
192 
194  {
195  // Members for system messages ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
196  // Set of vectors to delivers system messages to active users of the Web Gui
197  // When a message is generated, systemMessageLock is set,
198  // message is added and the vector set deliveredFlag = false,
199  // and systemMessageLock is unset.
200  // When a message is delivered deliveredFlag = true,
201  // During systemMessageCleanup(), systemMessageLock is set, delivered messages are removed,
202  // and systemMessageLock is unset.
203  //"SystemMessage" database associations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
204  // Maintain list of user system messages:
205  // time, message, deliveredFlag
206 
207  SystemMessage(const std::string& message)
208  : message_ (message)
209  , creationTime_ (time(0))
210  , delivered_ (false)
211  {} //end constructor
212 
213  std::string message_;
214  time_t creationTime_;
215  bool delivered_; //flag
216  }; //end SystemMessage struct
217 
218  void addSystemMessage (const std::string& targetUsersCSV, const std::string& message);
219  void addSystemMessage (const std::string& targetUsersCSV, const std::string& subject, const std::string& message, bool doEmail);
220  void addSystemMessage (const std::vector<std::string>& targetUsers, const std::string& subject, const std::string& message, bool doEmail);
221  std::string getSystemMessage (const std::string& targetUser);
222 
223  private:
224  void addSystemMessageToMap (const std::string& targetUser, const std::string& fullMessage); //private because target already vetted
225  void systemMessageCleanup (void);
226  std::mutex systemMessageLock_;
227  std::map<std::string /*toUserDisplayName*/,std::vector<SystemMessage>> systemMessages_;
228 
229 
230  public:
231 
232 
234  {
235  // WebUsers is a "Friend" class of RequestUserInfo so has access to private
236  // members.
237  friend class WebUsers;
238 
239  RequestUserInfo(const std::string& requestType, const std::string& cookieCode)
240  : requestType_(requestType)
241  , cookieCode_(cookieCode)
242  , uid_(-1) // init to invalid user, since only WebUser owner will have access
243  // to uid. RemoteWebUsers will see invalid uid.
244  {
245  }
246 
247  //------- setters --------//
248  //===========================================
249  // setGroupPermissionLevels
250  bool setGroupPermissionLevels(const std::string& groupPermissionLevelsString)
251  {
252  //__COUTV__(groupPermissionLevelsString);
253  permissionLevel_ = 0; // default to inactive, i.e. no access
254 
255  StringMacros::getMapFromString( // re-factor membership string to set
256  groupPermissionLevelsString,
257  groupPermissionLevelMap_);
258  getGroupPermissionLevel(); // setup permissionLevel_
259 
260  //__COUTV__((unsigned int)permissionLevel_);
261  return true; // was fully setup
262  } // end setGroupPermissionLevels()
263 
264  //------- getters --------//
265  const std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>&
266  getGroupPermissionLevels() const
267  {
268  return groupPermissionLevelMap_;
269  }
270  //===========================================
271  // getGroupPermissionLevel
272  // sets up permissionLevel based on already prepared RequestUserInfo members
273  const WebUsers::permissionLevel_t& getGroupPermissionLevel()
274  {
275  permissionLevel_ = 0; // default to inactive, i.e. no access
276 
277  // check groups allowed
278  // i.e. if user is a member of one of the groups allowed
279  // then consider for highest permission level
280  bool matchedAcceptGroup = false;
281  for(const auto& userGroupPair : groupPermissionLevelMap_)
282  if(StringMacros::inWildCardSet( // if group is in allowed groups
283  userGroupPair.first,
284  groupsAllowed_) && // AND...
285  userGroupPair.second >
286  permissionLevel_) // if is a new high level, then...
287  {
288  permissionLevel_ =
289  userGroupPair.second; // take as new permission level
290  matchedAcceptGroup = true;
291  }
292 
293  // if no group match in groups allowed, then failed
294  if(!matchedAcceptGroup && groupsAllowed_.size())
295  {
296  __COUT_INFO__
297  << "User (@" << ip_
298  << ") has insufficient group permissions: user is in these groups... "
299  << StringMacros::mapToString(groupPermissionLevelMap_)
300  << " and the allowed groups are... "
301  << StringMacros::setToString(groupsAllowed_) << std::endl;
302  return permissionLevel_;
303  }
304 
305  // if no access groups specified, then check groups disallowed
306  if(!groupsAllowed_.size())
307  {
308  for(const auto& userGroupPair : groupPermissionLevelMap_)
309  if(StringMacros::inWildCardSet(userGroupPair.first,
310  groupsDisallowed_))
311  {
312  __COUT_INFO__
313  << "User (@" << ip_
314  << ") is in a disallowed group: user is in these groups... "
315  << StringMacros::mapToString(groupPermissionLevelMap_)
316  << " and the disallowed groups are... "
317  << StringMacros::setToString(groupsDisallowed_) << std::endl;
318  return permissionLevel_;
319  }
320  }
321 
322  // if no groups have been explicitly allowed nor disallowed
323  // then permission level should come from WebUsers::DEFAULT_USER_GROUP
324  auto findIt = groupPermissionLevelMap_.find(WebUsers::DEFAULT_USER_GROUP);
325  if(findIt != groupPermissionLevelMap_.end())
326  {
327  // found default group, take permission level
328  permissionLevel_ = findIt->second;
329  }
330 
331  return permissionLevel_;
332  } // end getGroupPermissionLevel()
333 
334  inline bool isInactive() const
335  {
336  return permissionLevel_ == WebUsers::PERMISSION_LEVEL_INACTIVE;
337  }
338  inline bool isAdmin() const
339  {
340  return permissionLevel_ == WebUsers::PERMISSION_LEVEL_ADMIN;
341  }
342 
343  // members extracted from supervisor properties on a per request type basis
344  const std::string& requestType_;
345  std::string cookieCode_;
346 
347  bool automatedCommand_, NonXMLRequestType_, NoXmlWhiteSpace_;
348  bool checkLock_, requireLock_, allowNoUser_, requireSecurity_;
349 
350  std::set<std::string> groupsAllowed_, groupsDisallowed_;
351 
352  WebUsers::permissionLevel_t permissionLevel_, permissionsThreshold_;
353  std::string ip_;
354  uint64_t uid_ /*only WebUser owner has access to uid, RemoteWebUsers do not*/;
355  std::string username_, displayName_, usernameWithLock_;
356  uint64_t activeUserSessionIndex_;
357 
358  private:
359  std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>
360  groupPermissionLevelMap_;
361  }; //end RequestUserInfo struct
362 
363  // for the gateway supervisor to check request access
364  // if false, gateway request handling code should just return.. out is handled on
365  // false; on true, out is untouched
366  bool xmlRequestOnGateway(cgicc::Cgicc& cgi,
367  std::ostringstream* out,
368  HttpXmlDocument* xmldoc,
369  WebUsers::RequestUserInfo& userInfo);
370 
371  public:
372 
373  // used by gateway and other supervisors to verify requests consistently
374  static void initializeRequestUserInfo(cgicc::Cgicc& cgi,
375  WebUsers::RequestUserInfo& userInfo);
376  static bool checkRequestAccess(cgicc::Cgicc& cgi,
377  std::ostringstream* out,
378  HttpXmlDocument* xmldoc,
379  WebUsers::RequestUserInfo& userInfo,
380  bool isWizardMode = false,
381  const std::string& wizardModeSequence = "");
382 
383  void createNewAccount(const std::string& username,
384  const std::string& displayName,
385  const std::string& email);
386  void cleanupExpiredEntries(std::vector<std::string>* loggedOutUsernames = 0);
387  std::string createNewLoginSession(const std::string& uuid, const std::string& ip);
388 
389  uint64_t attemptActiveSession(const std::string& uuid,
390  std::string& jumbledUser,
391  const std::string& jumbledPw,
392  std::string& newAccountCode,
393  const std::string& ip);
394  uint64_t attemptActiveSessionWithCert(const std::string& uuid,
395  std::string& jumbledEmail,
396  std::string& cookieCode,
397  std::string& username,
398  const std::string& ip);
399  uint64_t isCookieCodeActiveForLogin(const std::string& uuid,
400  std::string& cookieCode,
401  std::string& username);
402  bool cookieCodeIsActiveForRequest(
403  std::string& cookieCode,
404  std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>*
405  userPermissions = 0,
406  uint64_t* uid = 0,
407  const std::string& ip = "0",
408  bool refresh = true,
409  std::string* userWithLock = 0,
410  uint64_t* activeUserSessionIndex = 0);
411  uint64_t cookieCodeLogout(const std::string& cookieCode,
412  bool logoutOtherUserSessions,
413  uint64_t* uid = 0,
414  const std::string& ip = "0");
415  bool checkIpAccess(const std::string& ip);
416 
417  std::string getUsersDisplayName(uint64_t uid);
418  std::string getUsersUsername(uint64_t uid);
419  uint64_t getActiveSessionCountForUser(uint64_t uid);
420  std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>
421  getPermissionsForUser(uint64_t uid);
422  void insertSettingsForUser(uint64_t uid,
423  HttpXmlDocument* xmldoc,
424  bool includeAccounts = false);
425  std::string getGenericPreference(uint64_t uid,
426  const std::string& preferenceName,
427  HttpXmlDocument* xmldoc = 0) const;
428 
429  void changeSettingsForUser(uint64_t uid,
430  const std::string& bgcolor,
431  const std::string& dbcolor,
432  const std::string& wincolor,
433  const std::string& layout,
434  const std::string& syslayout);
435  void setGenericPreference(uint64_t uid,
436  const std::string& preferenceName,
437  const std::string& preferenceValue);
438  static void tooltipCheckForUsername(const std::string& username,
439  HttpXmlDocument* xmldoc,
440  const std::string& srcFile,
441  const std::string& srcFunc,
442  const std::string& srcId);
443  static void tooltipSetNeverShowForUsername(const std::string& username,
444  HttpXmlDocument* xmldoc,
445  const std::string& srcFile,
446  const std::string& srcFunc,
447  const std::string& srcId,
448  bool doNeverShow,
449  bool temporarySilence);
450 
451  void modifyAccountSettings(uint64_t actingUid,
452  uint8_t cmd_type,
453  const std::string& username,
454  const std::string& displayname,
455  const std::string& email,
456  const std::string& permissions);
457  bool setUserWithLock(uint64_t actingUid, bool lock, const std::string& username);
458  std::string getUserWithLock(void) { return usersUsernameWithLock_; }
459 
460  std::string getActiveUsersString(void);
461 
462  bool getUserInfoForCookie(std::string& cookieCode,
463  std::string* userName,
464  std::string* displayName = 0,
465  uint64_t* activeSessionIndex = 0);
466 
467  bool isUsernameActive(const std::string& username) const;
468  bool isUserIdActive(uint64_t uid) const;
469  uint64_t getAdminUserID(void);
470  std::string getSecurity(void);
471 
472  static void deleteUserData(void);
473 
474  static void resetAllUserTooltips(const std::string& userNeedle = "*");
475  static void silenceAllUserTooltips(const std::string& username);
476 
477  static void NACDisplayThread(const std::string& nac, const std::string& user);
478 
479  void saveActiveSessions(void);
480  void loadActiveSessions(void);
481 
482  private:
483  inline WebUsers::permissionLevel_t getPermissionLevelForGroup(
484  const std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>& permissionMap,
485  const std::string& groupName = WebUsers::DEFAULT_USER_GROUP);
486  inline bool isInactiveForGroup(
487  const std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>& permissionMap,
488  const std::string& groupName = WebUsers::DEFAULT_USER_GROUP);
489  inline bool isAdminForGroup(
490  const std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>& permissionMap,
491  const std::string& groupName = WebUsers::DEFAULT_USER_GROUP);
492 
493  void loadSecuritySelection(void);
494  void loadUserWithLock(void);
495  unsigned int hexByteStrToInt(const char* h);
496  void intToHexStr(uint8_t i, char* h);
497  std::string sha512(const std::string& user,
498  const std::string& password,
499  std::string& salt);
500  std::string dejumble(const std::string& jumbledUser, const std::string& sessionId);
501  std::string createNewActiveSession(uint64_t uid,
502  const std::string& ip = "0",
503  uint64_t asIndex = 0);
504  bool addToHashesDatabase(const std::string& hash);
505  std::string genCookieCode(void);
506  std::string refreshCookieCode(unsigned int i, bool enableRefresh = true);
507  bool deleteAccount(const std::string& username, const std::string& displayName);
508  void incrementIpBlacklistCount(const std::string& ip);
509 
510  void saveToDatabase(FILE* fp,
511  const std::string& field,
512  const std::string& value,
513  uint8_t type = DB_SAVE_OPEN_AND_CLOSE,
514  bool addNewLine = true);
515  bool saveDatabaseToFile(uint8_t db);
516  bool loadDatabases(void);
517 
518  uint64_t searchUsersDatabaseForUsername (const std::string& username) const;
519  uint64_t searchUsersDatabaseForDisplayName (const std::string& displayName) const;
520  uint64_t searchUsersDatabaseForUserEmail (const std::string& useremail) const;
521  uint64_t searchUsersDatabaseForUserId (uint64_t uid) const;
522  uint64_t searchLoginSessionDatabaseForUUID (const std::string& uuid) const;
523  uint64_t searchHashesDatabaseForHash (const std::string& hash);
524  uint64_t searchActiveSessionDatabaseForCookie (const std::string& cookieCode) const;
525 
526  static std::string getTooltipFilename(const std::string& username,
527  const std::string& srcFile,
528  const std::string& srcFunc,
529  const std::string& srcId);
530  std::string getUserEmailFromFingerprint(const std::string& fingerprint);
531 
532  enum
533  {
534  DB_USERS,
535  DB_HASHES
536  };
537 
538  enum
539  {
540  DB_SAVE_OPEN_AND_CLOSE,
541  DB_SAVE_OPEN,
542  DB_SAVE_CLOSE
543  };
544 
545  std::unordered_map<std::string, std::string> certFingerprints_;
546 
547  static const std::vector<std::string> UsersDatabaseEntryFields_, HashesDatabaseEntryFields_;
548  bool CareAboutCookieCodes_;
549  std::string securityType_;
550 
551  //"Login Session" database associations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
552  std::vector<LoginSession> LoginSessions_;
553 
554  // Generate random sessionId when receive a unique user ID (UUID)
555  // reject UUID that have been used recently (e.g. last 5 minutes)
556  // Maintain list of active sessionIds and associated UUID
557  // remove from list if been idle after some time or login attempts (e.g. 5 minutes or
558  // 3 login attempts) maybe track IP address, to block multiple failed login attempts
559  // from same IP. Use sessionId to un-jumble login attempts, lookup using UUID
560 // std::vector<std::string> LoginSessionIdVector, LoginSessionUUIDVector,
561 // LoginSessionIpVector;
562 // std::vector<time_t> LoginSessionStartTimeVector;
563 // std::vector<uint8_t> LoginSessionAttemptsVector;
564  enum
565  {
566  LOGIN_SESSION_EXPIRATION_TIME = 5 * 60, // 5 minutes
567  LOGIN_SESSION_ATTEMPTS_MAX = 5, // 5 attempts on same session, forces new session
568  };
569 
570  //"Active Session" database associations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
571  std::vector<ActiveSession> ActiveSessions_;
572 
573  // Maintain list of valid cookieCodes and associated user
574  // all request must come with a valid cookieCode, else server fails request
575  // On logout request, invalidate cookieCode
576  // cookieCode expires after some idle time (e.g. 5 minutes) and
577  // is renewed and possibly changed each request
578  //"single user - multiple locations" issue resolved using ActiveSessionIndex
579  // where each independent login starts a new thread of cookieCodes tagged with
580  // ActiveSessionIndex if cookieCode not refreshed, then return most recent cookie
581  // code
582 // std::vector<std::string> ActiveSessionCookieCodeVector, ActiveSessionIpVector;
583 // std::vector<uint64_t> ActiveSessionUserIdVector, ActiveSessionIndex;
584 // std::vector<time_t> ActiveSessionStartTimeVector;
585  enum
586  {
587  ACTIVE_SESSION_EXPIRATION_TIME = 120 * 60, // 120 minutes, cookie is changed
588  // every half period of
589  // ACTIVE_SESSION_EXPIRATION_TIME
590  ACTIVE_SESSION_COOKIE_OVERLAP_TIME =
591  10 * 60, // 10 minutes of overlap when new cookie is generated
592  ACTIVE_SESSION_STALE_COOKIE_LIMIT =
593  10, // 10 stale cookies allowed for each active user
594  };
595 
596  //"Users" database associations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
597  std::vector<User> Users_;
598  // Maintain list of acceptable Usernames and associate:
599  // permissions
600  // map of group name to permission level (e.g. users, experts, masters) 0 to 255
601  // note: all users are at least in group WebUsers::DEFAULT_USER_GROUP
602  // 0 := account inactive, not allowed to login (e.g. could be due to too many
603  // failed login attempts) 1 := normal user 255 := admin for things in group
604  // permission level is determined by finding the highest permission level number (0 to
605  // 255) for an allowed group.. then that permission level is compared to the
606  // threshold
607  //
608  // Last Login attempt time, and last USERS_LOGIN_HISTORY_SIZE successful logins
609  // Name to display
610  // random salt, before first login salt is empty string ""
611  // Keep count of login attempt failures. Limit failures per unit time (e.g. 5 per
612  // hour) Preferences (e.g. color scheme, etc) Username appends to preferences file,
613  // and login history file UsersLastModifierUsernameVector - is username of last
614  // master user to modify something about account UsersLastModifierTimeVector - is
615  // time of last modify by a master user
616 // std::vector<std::string> UsersUsernameVector, UsersUserEmailVector,
617 // UsersDisplayNameVector, UsersSaltVector, UsersLastModifierUsernameVector;
618 // std::vector<std::map<std::string /*groupName*/, WebUsers::permissionLevel_t> >
619 // UsersPermissionsVector;
620 // std::vector<uint64_t> UsersUserIdVector;
621 // std::vector<time_t> UsersLastLoginAttemptVector, UsersAccountCreatedTimeVector,
622 // UsersLastModifiedTimeVector;
623 // std::vector<uint8_t> UsersLoginFailureCountVector;
624  uint64_t usersNextUserId_;
625  enum
626  {
627  USERS_LOGIN_HISTORY_SIZE = 20,
628  USERS_GLOBAL_HISTORY_SIZE = 1000,
629  USERS_MAX_LOGIN_FAILURES = 20,
630  };
631  std::string usersUsernameWithLock_;
632 
633  std::vector<std::string> UsersLoggedOutUsernames_;
634 
635  //"Hashes" database associations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
636  std::vector<Hash> Hashes_;
637 
638  // Maintain list of acceptable encoded (SHA-512) salt+user+pw's
639 // std::vector<std::string> HashesVector;
640 // std::vector<time_t> HashesAccessTimeVector;
641 
642  enum
643  {
644  IP_BLACKLIST_COUNT_THRESHOLD = 200,
645  };
646  std::map<std::string /*ip*/, uint32_t /*errorCount*/> ipBlacklistCounts_;
647 
648  std::mutex webUserMutex_;
649 };
650 // clang-format on
651 } // namespace ots
652 
653 #endif