$treeview $search $mathjax $extrastylesheet
otsdaq
v2_03_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #ifndef _ots_Utilities_WebUsers_h_ 00002 #define _ots_Utilities_WebUsers_h_ 00003 00004 #include "otsdaq-core/Macros/CoutMacros.h" 00005 #include "otsdaq-core/Macros/StringMacros.h" 00006 #include "otsdaq-core/MessageFacility/MessageFacility.h" 00007 #include "otsdaq-core/SOAPUtilities/SOAPMessenger.h" 00008 #include "xgi/Method.h" //for cgicc::Cgicc 00009 00010 #include <iostream> 00011 #include <string> 00012 #include <unordered_map> 00013 #include <vector> 00014 00015 #define WEB_LOGIN_DB_PATH std::string(getenv("SERVICE_DATA_PATH")) + "/LoginData/" 00016 #define WEB_LOGIN_CERTDATA_PATH std::string(getenv("CERT_DATA_PATH")) 00017 #define HASHES_DB_PATH "HashesData/" 00018 #define USERS_DB_PATH "UsersData/" 00019 #define USERS_LOGIN_HISTORY_PATH USERS_DB_PATH + "UserLoginHistoryData/" 00020 #define USERS_PREFERENCES_PATH USERS_DB_PATH + "UserPreferencesData/" 00021 #define TOOLTIP_DB_PATH USERS_DB_PATH + "/TooltipData/" 00022 00023 namespace ots 00024 { 00025 class HttpXmlDocument; 00026 00027 // WebUsers 00028 // This class provides the functionality for managing all otsdaq user account preferences 00029 // and permissions. 00030 class WebUsers 00031 { 00032 public: 00033 WebUsers(); 00034 00035 enum 00036 { 00037 SESSION_ID_LENGTH = 512, 00038 COOKIE_CODE_LENGTH = 512, 00039 NOT_FOUND_IN_DATABASE = uint64_t(-1), 00040 USERNAME_LENGTH = 4, 00041 DISPLAY_NAME_LENGTH = 4, 00042 }; 00043 00044 using permissionLevel_t = uint8_t; 00045 enum 00046 { 00047 PERMISSION_LEVEL_ADMIN = 00048 WebUsers::permissionLevel_t(-1), // max permission level! 00049 PERMISSION_LEVEL_EXPERT = 100, 00050 PERMISSION_LEVEL_USER = 10, 00051 PERMISSION_LEVEL_NOVICE = 1, 00052 PERMISSION_LEVEL_INACTIVE = 0, 00053 }; 00054 00055 static const std::string DEFAULT_ADMIN_USERNAME; 00056 static const std::string DEFAULT_ADMIN_DISPLAY_NAME; 00057 static const std::string DEFAULT_ADMIN_EMAIL; 00058 static const std::string DEFAULT_ITERATOR_USERNAME; 00059 static const std::string DEFAULT_STATECHANGER_USERNAME; 00060 static const std::string DEFAULT_USER_GROUP; 00061 00062 static const std::string REQ_NO_LOGIN_RESPONSE; 00063 static const std::string REQ_NO_PERMISSION_RESPONSE; 00064 static const std::string REQ_USER_LOCKOUT_RESPONSE; 00065 static const std::string REQ_LOCK_REQUIRED_RESPONSE; 00066 static const std::string REQ_ALLOW_NO_USER; 00067 00068 static const std::string SECURITY_TYPE_NONE; 00069 static const std::string SECURITY_TYPE_DIGEST_ACCESS; 00070 00071 struct RequestUserInfo 00072 { 00073 // WebUsers is a "Friend" class of RequestUserInfo so has access to private 00074 // members. 00075 friend class WebUsers; 00076 00077 RequestUserInfo(const std::string& requestType, const std::string& cookieCode) 00078 : requestType_(requestType) 00079 , cookieCode_(cookieCode) 00080 , uid_(-1) // init to invalid user, since only WebUser owner will have access 00081 // to uid. RemoteWebUsers will see invalid uid. 00082 { 00083 } 00084 00085 //------- setters --------// 00086 //=========================================== 00087 // setGroupPermissionLevels 00088 bool setGroupPermissionLevels(const std::string& groupPermissionLevelsString) 00089 { 00090 //__COUTV__(groupPermissionLevelsString); 00091 permissionLevel_ = 0; // default to inactive, i.e. no access 00092 00093 StringMacros::getMapFromString( // re-factor membership string to set 00094 groupPermissionLevelsString, 00095 groupPermissionLevelMap_); 00096 getGroupPermissionLevel(); // setup permissionLevel_ 00097 00098 //__COUTV__((unsigned int)permissionLevel_); 00099 return true; // was fully setup 00100 } // end setGroupPermissionLevels() 00101 00102 //------- getters --------// 00103 const std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>& 00104 getGroupPermissionLevels() const 00105 { 00106 return groupPermissionLevelMap_; 00107 } 00108 //=========================================== 00109 // getGroupPermissionLevel 00110 // sets up permissionLevel based on already prepared RequestUserInfo members 00111 const WebUsers::permissionLevel_t& getGroupPermissionLevel() 00112 { 00113 permissionLevel_ = 0; // default to inactive, i.e. no access 00114 00115 // check groups allowed 00116 // i.e. if user is a member of one of the groups allowed 00117 // then consider for highest permission level 00118 bool matchedAcceptGroup = false; 00119 for(const auto& userGroupPair : groupPermissionLevelMap_) 00120 if(StringMacros::inWildCardSet( // if group is in allowed groups 00121 userGroupPair.first, 00122 groupsAllowed_) && // AND... 00123 userGroupPair.second > 00124 permissionLevel_) // if is a new high level, then... 00125 { 00126 permissionLevel_ = 00127 userGroupPair.second; // take as new permission level 00128 matchedAcceptGroup = true; 00129 } 00130 00131 // if no group match in groups allowed, then failed 00132 if(!matchedAcceptGroup && groupsAllowed_.size()) 00133 { 00134 __COUT_INFO__ 00135 << "User (@" << ip_ 00136 << ") has insufficient group permissions: user is in these groups... " 00137 << StringMacros::mapToString(groupPermissionLevelMap_) 00138 << " and the allowed groups are... " 00139 << StringMacros::setToString(groupsAllowed_) << std::endl; 00140 return permissionLevel_; 00141 } 00142 00143 // if no access groups specified, then check groups disallowed 00144 if(!groupsAllowed_.size()) 00145 { 00146 for(const auto& userGroupPair : groupPermissionLevelMap_) 00147 if(StringMacros::inWildCardSet(userGroupPair.first, 00148 groupsDisallowed_)) 00149 { 00150 __COUT_INFO__ 00151 << "User (@" << ip_ 00152 << ") is in a disallowed group: user is in these groups... " 00153 << StringMacros::mapToString(groupPermissionLevelMap_) 00154 << " and the disallowed groups are... " 00155 << StringMacros::setToString(groupsDisallowed_) << std::endl; 00156 return permissionLevel_; 00157 } 00158 } 00159 00160 // if no groups have been explicitly allowed nor disallowed 00161 // then permission level should come from WebUsers::DEFAULT_USER_GROUP 00162 auto findIt = groupPermissionLevelMap_.find(WebUsers::DEFAULT_USER_GROUP); 00163 if(findIt != groupPermissionLevelMap_.end()) 00164 { 00165 // found default group, take permission level 00166 permissionLevel_ = findIt->second; 00167 } 00168 00169 return permissionLevel_; 00170 } // end getGroupPermissionLevel() 00171 00172 inline bool isInactive() 00173 { 00174 return permissionLevel_ == WebUsers::PERMISSION_LEVEL_INACTIVE; 00175 } 00176 inline bool isAdmin() 00177 { 00178 return permissionLevel_ == WebUsers::PERMISSION_LEVEL_ADMIN; 00179 } 00180 00181 // members extracted from supervisor properties on a per request type basis 00182 const std::string& requestType_; 00183 std::string cookieCode_; 00184 00185 bool automatedCommand_, NonXMLRequestType_, NoXmlWhiteSpace_; 00186 bool checkLock_, requireLock_, allowNoUser_; 00187 00188 std::set<std::string> groupsAllowed_, groupsDisallowed_; 00189 00190 WebUsers::permissionLevel_t permissionLevel_, permissionsThreshold_; 00191 std::string ip_; 00192 uint64_t uid_ /*only WebUser owner has access to uid, RemoteWebUsers do not*/; 00193 std::string username_, displayName_, usernameWithLock_; 00194 uint64_t activeUserSessionIndex_; 00195 00196 private: 00197 std::map<std::string /*groupName*/, WebUsers::permissionLevel_t> 00198 groupPermissionLevelMap_; 00199 }; 00200 00201 // for the gateway supervisor to check request access 00202 // if false, gateway request handling code should just return.. out is handled on 00203 // false; on true, out is untouched 00204 bool xmlRequestOnGateway(cgicc::Cgicc& cgi, 00205 std::ostringstream* out, 00206 HttpXmlDocument* xmldoc, 00207 WebUsers::RequestUserInfo& userInfo); 00208 00209 public: 00210 // used by gateway and other supervisors to verify requests consistently 00211 static void initializeRequestUserInfo(cgicc::Cgicc& cgi, 00212 WebUsers::RequestUserInfo& userInfo); 00213 static bool checkRequestAccess(cgicc::Cgicc& cgi, 00214 std::ostringstream* out, 00215 HttpXmlDocument* xmldoc, 00216 WebUsers::RequestUserInfo& userInfo, 00217 bool isWizardMode = false); 00218 00219 bool createNewAccount(const std::string& username, 00220 const std::string& displayName, 00221 const std::string& email); 00222 void cleanupExpiredEntries(std::vector<std::string>* loggedOutUsernames = 0); 00223 std::string createNewLoginSession(const std::string& uuid, const std::string& ip); 00224 00225 uint64_t attemptActiveSession(const std::string& uuid, 00226 std::string& jumbledUser, 00227 const std::string& jumbledPw, 00228 std::string& newAccountCode, 00229 const std::string& ip); 00230 uint64_t attemptActiveSessionWithCert(const std::string& uuid, 00231 std::string& jumbledEmail, 00232 std::string& cookieCode, 00233 std::string& username, 00234 const std::string& ip); 00235 uint64_t isCookieCodeActiveForLogin(const std::string& uuid, 00236 std::string& cookieCode, 00237 std::string& username); 00238 bool cookieCodeIsActiveForRequest( 00239 std::string& cookieCode, 00240 std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>* 00241 userPermissions = 0, 00242 uint64_t* uid = 0, 00243 const std::string& ip = "0", 00244 bool refresh = true, 00245 std::string* userWithLock = 0, 00246 uint64_t* activeUserSessionIndex = 0); 00247 uint64_t cookieCodeLogout(const std::string& cookieCode, 00248 bool logoutOtherUserSessions, 00249 uint64_t* uid = 0, 00250 const std::string& ip = "0"); 00251 bool checkIpAccess(const std::string& ip); 00252 00253 std::string getUsersDisplayName(uint64_t uid); 00254 std::string getUsersUsername(uint64_t uid); 00255 uint64_t getActiveSessionCountForUser(uint64_t uid); 00256 std::map<std::string /*groupName*/, WebUsers::permissionLevel_t> 00257 getPermissionsForUser(uint64_t uid); 00258 void insertSettingsForUser(uint64_t uid, 00259 HttpXmlDocument* xmldoc, 00260 bool includeAccounts = false); 00261 std::string getGenericPreference(uint64_t uid, 00262 const std::string& preferenceName, 00263 HttpXmlDocument* xmldoc = 0) const; 00264 00265 void changeSettingsForUser(uint64_t uid, 00266 const std::string& bgcolor, 00267 const std::string& dbcolor, 00268 const std::string& wincolor, 00269 const std::string& layout, 00270 const std::string& syslayout); 00271 void setGenericPreference(uint64_t uid, 00272 const std::string& preferenceName, 00273 const std::string& preferenceValue); 00274 static void tooltipCheckForUsername(const std::string& username, 00275 HttpXmlDocument* xmldoc, 00276 const std::string& srcFile, 00277 const std::string& srcFunc, 00278 const std::string& srcId); 00279 static void tooltipSetNeverShowForUsername(const std::string& username, 00280 HttpXmlDocument* xmldoc, 00281 const std::string& srcFile, 00282 const std::string& srcFunc, 00283 const std::string& srcId, 00284 bool doNeverShow, 00285 bool temporarySilence); 00286 00287 void modifyAccountSettings(uint64_t actingUid, 00288 uint8_t cmd_type, 00289 const std::string& username, 00290 const std::string& displayname, 00291 const std::string& email, 00292 const std::string& permissions); 00293 bool setUserWithLock(uint64_t actingUid, bool lock, const std::string& username); 00294 std::string getUserWithLock(void) { return usersUsernameWithLock_; } 00295 00296 std::string getActiveUsersString(void); 00297 00298 bool getUserInfoForCookie(std::string& cookieCode, 00299 std::string* userName, 00300 std::string* displayName = 0, 00301 uint64_t* activeSessionIndex = 0); 00302 00303 bool isUsernameActive(const std::string& username) const; 00304 bool isUserIdActive(uint64_t uid) const; 00305 uint64_t getAdminUserID(void); 00306 std::string getSecurity(void); 00307 00308 static void deleteUserData(void); 00309 static void resetAllUserTooltips(const std::string& userNeedle = "*"); 00310 00311 static void NACDisplayThread(const std::string& nac, const std::string& user); 00312 00313 void saveActiveSessions(void); 00314 void loadActiveSessions(void); 00315 00316 private: 00317 inline WebUsers::permissionLevel_t getPermissionLevelForGroup( 00318 std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>& permissionMap, 00319 const std::string& groupName = WebUsers::DEFAULT_USER_GROUP); 00320 inline bool isInactiveForGroup( 00321 std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>& permissionMap, 00322 const std::string& groupName = WebUsers::DEFAULT_USER_GROUP); 00323 inline bool isAdminForGroup( 00324 std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>& permissionMap, 00325 const std::string& groupName = WebUsers::DEFAULT_USER_GROUP); 00326 00327 void loadSecuritySelection(void); 00328 void loadUserWithLock(void); 00329 unsigned int hexByteStrToInt(const char* h); 00330 void intToHexStr(uint8_t i, char* h); 00331 std::string sha512(const std::string& user, 00332 const std::string& password, 00333 std::string& salt); 00334 std::string dejumble(const std::string& jumbledUser, const std::string& sessionId); 00335 std::string createNewActiveSession(uint64_t uid, 00336 const std::string& ip = "0", 00337 uint64_t asIndex = 0); 00338 bool addToHashesDatabase(const std::string& hash); 00339 std::string genCookieCode(void); 00340 std::string refreshCookieCode(unsigned int i, bool enableRefresh = true); 00341 void removeActiveSessionEntry(unsigned int i); 00342 void removeLoginSessionEntry(unsigned int i); 00343 bool deleteAccount(const std::string& username, const std::string& displayName); 00344 void incrementIpBlacklistCount(const std::string& ip); 00345 00346 void saveToDatabase(FILE* fp, 00347 const std::string& field, 00348 const std::string& value, 00349 uint8_t type = DB_SAVE_OPEN_AND_CLOSE, 00350 bool addNewLine = true); 00351 bool saveDatabaseToFile(uint8_t db); 00352 bool loadDatabases(void); 00353 00354 uint64_t searchUsersDatabaseForUsername(const std::string& username) const; 00355 uint64_t searchUsersDatabaseForUserEmail(const std::string& useremail) const; 00356 uint64_t searchUsersDatabaseForUserId(uint64_t uid) const; 00357 uint64_t searchLoginSessionDatabaseForUUID(const std::string& uuid) const; 00358 uint64_t searchHashesDatabaseForHash(const std::string& hash); 00359 uint64_t searchActiveSessionDatabaseForCookie(const std::string& cookieCode) const; 00360 00361 static std::string getTooltipFilename(const std::string& username, 00362 const std::string& srcFile, 00363 const std::string& srcFunc, 00364 const std::string& srcId); 00365 std::string getUserEmailFromFingerprint(const std::string& fingerprint); 00366 00367 enum 00368 { 00369 DB_USERS, 00370 DB_HASHES 00371 }; 00372 00373 enum 00374 { 00375 MOD_TYPE_UPDATE, 00376 MOD_TYPE_ADD, 00377 MOD_TYPE_DELETE 00378 }; 00379 00380 enum 00381 { 00382 DB_SAVE_OPEN_AND_CLOSE, 00383 DB_SAVE_OPEN, 00384 DB_SAVE_CLOSE 00385 }; 00386 00387 std::unordered_map<std::string, std::string> certFingerprints_; 00388 00389 std::vector<std::string> UsersDatabaseEntryFields, HashesDatabaseEntryFields; 00390 bool CareAboutCookieCodes_; 00391 std::string securityType_; 00392 00393 //"Login Session" database associations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00394 // Generate random sessionId when receive a unique user ID (UUID) 00395 // reject UUID that have been used recently (e.g. last 5 minutes) 00396 // Maintain list of active sessionIds and associated UUID 00397 // remove from list if been idle after some time or login attempts (e.g. 5 minutes or 00398 // 3 login attempts) maybe track IP address, to block multiple failed login attempts 00399 // from same IP. Use sessionId to un-jumble login attempts, lookup using UUID 00400 std::vector<std::string> LoginSessionIdVector, LoginSessionUUIDVector, 00401 LoginSessionIpVector; 00402 std::vector<time_t> LoginSessionStartTimeVector; 00403 std::vector<uint8_t> LoginSessionAttemptsVector; 00404 enum 00405 { 00406 LOGIN_SESSION_EXPIRATION_TIME = 5 * 60, // 5 minutes 00407 LOGIN_SESSION_ATTEMPTS_MAX = 5, // 5 attempts on same session, forces new session 00408 }; 00409 00410 //"Active Session" database associations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00411 // Maintain list of valid cookieCodes and associated user 00412 // all request must come with a valid cookieCode, else server fails request 00413 // On logout request, invalidate cookieCode 00414 // cookieCode expires after some idle time (e.g. 5 minutes) and 00415 // is renewed and possibly changed each request 00416 //"single user - multiple locations" issue resolved using ActiveSessionIndex 00417 // where each independent login starts a new thread of cookieCodes tagged with 00418 // ActiveSessionIndex if cookieCode not refreshed, then return most recent cookie 00419 // code 00420 std::vector<std::string> ActiveSessionCookieCodeVector, ActiveSessionIpVector; 00421 std::vector<uint64_t> ActiveSessionUserIdVector, ActiveSessionIndex; 00422 std::vector<time_t> ActiveSessionStartTimeVector; 00423 enum 00424 { 00425 ACTIVE_SESSION_EXPIRATION_TIME = 120 * 60, // 120 minutes, cookie is changed 00426 // every half period of 00427 // ACTIVE_SESSION_EXPIRATION_TIME 00428 ACTIVE_SESSION_COOKIE_OVERLAP_TIME = 00429 10 * 60, // 10 minutes of overlap when new cookie is generated 00430 ACTIVE_SESSION_STALE_COOKIE_LIMIT = 00431 10, // 10 stale cookies allowed for each active user 00432 }; 00433 00434 //"Users" database associations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00435 // Maintain list of acceptable Usernames and associate: 00436 // permissions 00437 // map of group name to permission level (e.g. users, experts, masters) 0 to 255 00438 // note: all users are at least in group WebUsers::DEFAULT_USER_GROUP 00439 // 0 := account inactive, not allowed to login (e.g. could be due to too many 00440 // failed login attempts) 1 := normal user 255 := admin for things in group 00441 // permission level is determined by finding the highest permission level number (0 to 00442 // 255) for an allowed group.. then that permission level is compared to the 00443 // threshold 00444 // 00445 // Last Login attempt time, and last USERS_LOGIN_HISTORY_SIZE successful logins 00446 // Name to display 00447 // random salt, before first login salt is empty string "" 00448 // Keep count of login attempt failures. Limit failures per unit time (e.g. 5 per 00449 // hour) Preferences (e.g. color scheme, etc) Username appends to preferences file, 00450 // and login history file UsersLastModifierUsernameVector - is username of last 00451 // master user to modify something about account UsersLastModifierTimeVector - is 00452 // time of last modify by a master user 00453 std::vector<std::string> UsersUsernameVector, UsersUserEmailVector, 00454 UsersDisplayNameVector, UsersSaltVector, UsersLastModifierUsernameVector; 00455 std::vector<std::map<std::string /*groupName*/, WebUsers::permissionLevel_t> > 00456 UsersPermissionsVector; 00457 std::vector<uint64_t> UsersUserIdVector; 00458 std::vector<time_t> UsersLastLoginAttemptVector, UsersAccountCreatedTimeVector, 00459 UsersLastModifiedTimeVector; 00460 std::vector<uint8_t> UsersLoginFailureCountVector; 00461 uint64_t usersNextUserId_; 00462 enum 00463 { 00464 USERS_LOGIN_HISTORY_SIZE = 20, 00465 USERS_GLOBAL_HISTORY_SIZE = 1000, 00466 USERS_MAX_LOGIN_FAILURES = 20, 00467 }; 00468 std::string usersUsernameWithLock_; 00469 00470 std::vector<std::string> UsersLoggedOutUsernames_; 00471 00472 //"Hashes" database associations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00473 // Maintain list of acceptable encoded (SHA-512) salt+user+pw's 00474 std::vector<std::string> HashesVector; 00475 std::vector<time_t> HashesAccessTimeVector; 00476 00477 enum 00478 { 00479 IP_BLACKLIST_COUNT_THRESHOLD = 200, 00480 }; 00481 std::map<std::string /*ip*/, uint32_t /*errorCount*/> ipBlacklistCounts_; 00482 }; 00483 00484 } // namespace ots 00485 00486 #endif