tdaq-develop-2025-02-12
RemoteWebUsers.cc
1 #include "otsdaq/WebUsersUtilities/RemoteWebUsers.h"
2 
3 #include "otsdaq/CgiDataUtilities/CgiDataUtilities.h"
4 #include "otsdaq/SOAPUtilities/SOAPCommand.h"
5 #include "otsdaq/SOAPUtilities/SOAPParameters.h" //must include in .h for static function
6 #include "otsdaq/SOAPUtilities/SOAPUtilities.h"
7 #include "otsdaq/XmlUtilities/HttpXmlDocument.h"
8 
9 #include <cstdio>
10 #include <cstdlib>
11 #include <tuple>
12 #include <vector>
13 
14 #include "otsdaq/SupervisorInfo/AllSupervisorInfo.h"
15 
16 using namespace ots;
17 
18 #undef __MF_SUBJECT__
19 #define __MF_SUBJECT__ "RemoteWebUsers"
20 
21 //==============================================================================
29 //==============================================================================
31  xdaq::Application* application,
32  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* gatewaySupervisorDescriptor)
33  : SOAPMessenger(application)
34  , gatewaySupervisorDescriptor_(gatewaySupervisorDescriptor)
35 {
36  ActiveUserLastUpdateTime_ = 0; // init to never
37  ActiveUserList_ = ""; // init to empty
38 } // end constructor()
39 
40 //==============================================================================
44 bool RemoteWebUsers::xmlRequestToGateway(cgicc::Cgicc& cgi,
45  std::ostringstream* out,
46  HttpXmlDocument* xmldoc,
47  const AllSupervisorInfo& allSupervisorInfo,
48  WebUsers::RequestUserInfo& userInfo)
49 {
50  //__COUT__ << std::endl;
51  // initialize user info parameters to failed results
53 
54  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* gatewaySupervisor;
55 
56  SOAPParameters parameters;
57  xoap::MessageReference retMsg;
58 
59  //**** start LOGIN GATEWAY CODE ***//
60  // If TRUE, cookie code is good, and refreshed code is in cookieCode
61  // Else, error message is returned in cookieCode
62 
64  // if Wiz or Macormaker mode, use sequence instead of cookieCode
65  if(allSupervisorInfo.isWizardMode() || allSupervisorInfo.isMacroMakerMode())
66  {
67  // if missing CookieCode... check if in Wizard mode and using sequence
68  std::string sequence =
69  CgiDataUtilities::getOrPostData(cgi, "sequence"); // from GET or POST
70  //__COUT__ << "sequence=" << sequence << std::endl;
71  if(!sequence.length())
72  {
73  __COUT_ERR__ << "Invalid access attempt (@" << userInfo.ip_ << ")."
74  << std::endl;
75  *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
76  // invalid cookie and also invalid sequence
77  goto HANDLE_ACCESS_FAILURE; // return false, access failed
78  }
79 
80  // have sequence, try it out
81 
82  if(allSupervisorInfo.isWizardMode())
83  gatewaySupervisor = allSupervisorInfo.getWizardInfo().getDescriptor();
84  else //is MacroMaker mode
85  gatewaySupervisor = allSupervisorInfo.getAllMacroMakerTypeSupervisorInfo()
86  .begin()
87  ->second.getDescriptor();
88 
89  if(!gatewaySupervisor)
90  {
91  __COUT_ERR__ << "Missing gateway supervisor." << std::endl;
92  *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
93  // sequence code present, but no wizard supervisor
94  goto HANDLE_ACCESS_FAILURE; // return false, access failed
95  }
96 
97  parameters.addParameter("sequence", sequence);
98  parameters.addParameter("IPAddress", userInfo.ip_);
99  retMsg = SOAPMessenger::sendWithSOAPReply(
100  gatewaySupervisor, "SupervisorSequenceCheck", parameters);
101  parameters.clear();
102  parameters.addParameter("Permissions");
103  SOAPUtilities::receive(retMsg, parameters);
104 
105  userInfo.setGroupPermissionLevels(parameters.getValue("Permissions"));
106 
108  cgi, out, xmldoc, userInfo, true /*isWizardMode*/, sequence))
109  return true; //successful sequence login!
110  else
111  goto HANDLE_ACCESS_FAILURE; // return false, access failed
112  } //end Wiz or Macormaker mode
113 
114  // else proceed with inquiry to Gateway Supervisor
115 
116  gatewaySupervisor = allSupervisorInfo.getGatewayInfo().getDescriptor();
117 
118  if(!gatewaySupervisor)
119  {
120  __COUT_ERR__ << "Missing gateway supervisor." << std::endl;
121  *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
122  goto HANDLE_ACCESS_FAILURE; // return false, access failed
123  }
124 
125  parameters.clear();
126  parameters.addParameter("CookieCode", userInfo.cookieCode_);
127  parameters.addParameter("RefreshOption", userInfo.automatedCommand_ ? "0" : "1");
128  parameters.addParameter("IPAddress", userInfo.ip_);
129 
130  retMsg = SOAPMessenger::sendWithSOAPReply(
131  gatewaySupervisor, "SupervisorCookieCheck", parameters);
132 
133  parameters.clear();
134  parameters.addParameter("CookieCode");
135  parameters.addParameter("Permissions");
136  parameters.addParameter("UserGroups");
137  parameters.addParameter("UserWithLock");
138  parameters.addParameter("Username");
139  parameters.addParameter("DisplayName");
140  // parameters.addParameter("ActiveSessionIndex");
141  SOAPUtilities::receive(retMsg, parameters);
142 
143  // first extract a few things always from parameters
144  // like permissionLevel for this request... must consider allowed groups!!
145  userInfo.setGroupPermissionLevels(parameters.getValue("Permissions"));
146  userInfo.cookieCode_ = parameters.getValue("CookieCode");
147  userInfo.username_ = parameters.getValue("Username");
148  userInfo.displayName_ = parameters.getValue("DisplayName");
149  userInfo.usernameWithLock_ = parameters.getValue("UserWithLock");
150  // userInfo.activeUserSessionIndex_ = strtoul(parameters.getValue("ActiveSessionIndex").c_str(), 0, 0);
151 
152  if(!WebUsers::checkRequestAccess(cgi, out, xmldoc, userInfo))
153  goto HANDLE_ACCESS_FAILURE; // return false, access failed
154  // else successful access request!
155 
156  return true; // request granted
157 
159 
160 HANDLE_ACCESS_FAILURE:
161 
162  // print out return string on failure
163  if(!userInfo.automatedCommand_)
164  __COUT_ERR__ << "Failed request (requestType = " << userInfo.requestType_
165  << "): " << out->str() << __E__;
166  return false; // access failed
167 } // end xmlRequestToGateway()
168 
169 //==============================================================================
174 {
175  if(time(0) - ActiveUserLastUpdateTime_ >
176  ACTIVE_USERS_UPDATE_THRESHOLD) // need to update
177  {
178  __COUT_TYPE__(TLVL_DEBUG + 2)
179  << __COUT_HDR__ << "Need to update active user list" << std::endl;
180 
181  xoap::MessageReference retMsg = ots::SOAPMessenger::sendWithSOAPReply(
182  gatewaySupervisorDescriptor_, "SupervisorGetActiveUsers");
183 
184  SOAPParameters retParameters("UserList");
185  SOAPUtilities::receive(retMsg, retParameters);
186 
187  ActiveUserLastUpdateTime_ = time(0);
188  return (ActiveUserList_ = retParameters.getValue("UserList"));
189  }
190  else
191  return ActiveUserList_;
192 } // end getActiveUserList()
193 
194 //==============================================================================
201  std::map<std::string /* group type */,
202  std::tuple<std::string /*group name*/,
204  std::string /* time string*/>>& theGroups)
205 {
206  xoap::MessageReference retMsg =
207  ots::SOAPMessenger::sendWithSOAPReply(gatewaySupervisorDescriptor_,
208  "SupervisorLastTableGroupRequest",
209  SOAPParameters("ActionOfLastGroup", "ALL"));
210 
211  SOAPParameters retParameters;
212  retParameters.addParameter("GroupName");
213  retParameters.addParameter("GroupKey");
214  retParameters.addParameter("GroupAction");
215  retParameters.addParameter("GroupActionTime");
216  SOAPUtilities::receive(retMsg, retParameters);
217 
218  //parse as CSV
219  std::vector<std::string> groupNames =
220  StringMacros::getVectorFromString(retParameters.getValue("GroupName"), {','});
221  std::vector<std::string> groupKeys =
222  StringMacros::getVectorFromString(retParameters.getValue("GroupKey"), {','});
223  std::vector<std::string> groupActions =
224  StringMacros::getVectorFromString(retParameters.getValue("GroupAction"), {','});
225  std::vector<std::string> groupTimes = StringMacros::getVectorFromString(
226  retParameters.getValue("GroupActionTime"), {','});
227 
228  if(groupNames.size() < 2)
229  {
230  //expecting something like 7?
231  __SS__ << "Failure in handling request for recent config group activity. "
232  "Response received was this: \n"
233  << SOAPUtilities::translate(retMsg) << __E__;
234  __SS_THROW__;
235  }
236 
237  if(groupNames.size() != groupKeys.size() ||
238  groupNames.size() != groupActions.size() || groupNames.size() != groupTimes.size())
239  {
240  __SS__ << "Illegal list size mismatch while retrieving recent config group info. "
241  "Should not be possible! Notify admins."
242  << __E__;
243  __SS_THROW__;
244  }
245 
246  for(size_t i = 0; i < groupNames.size(); ++i)
247  {
248  theGroups[groupActions[i]] = std::make_tuple(
249  groupNames[i], strtol(groupKeys[i].c_str(), 0, 0), groupTimes[i]);
250  }
251 
252  __COUTT__ << "Done with getLastTableGroups()" << __E__;
253 } // end getLastTableGroup()
254 
255 //==============================================================================
261 std::pair<std::string /*group name*/, TableGroupKey> RemoteWebUsers::getLastTableGroup(
262  const std::string& actionOfLastGroup, std::string& actionTimeString)
263 {
264  actionTimeString = "";
265  xoap::MessageReference retMsg = ots::SOAPMessenger::sendWithSOAPReply(
267  "SupervisorLastTableGroupRequest",
268  SOAPParameters("ActionOfLastGroup", actionOfLastGroup));
269 
270  SOAPParameters retParameters;
271  retParameters.addParameter("GroupName");
272  retParameters.addParameter("GroupKey");
273  retParameters.addParameter("GroupAction");
274  retParameters.addParameter("GroupActionTime");
275  SOAPUtilities::receive(retMsg, retParameters);
276 
277  std::pair<std::string /*group name*/, TableGroupKey> theGroup;
278  if(retParameters.getValue("GroupAction") !=
279  actionOfLastGroup) // if action doesn't match.. weird
280  {
281  __SS__ << "Returned group action '" << retParameters.getValue("GroupAction")
282  << "' does not match requested group action '" << actionOfLastGroup << ".'"
283  << std::endl;
284  __SS_THROW__;
285  }
286  // else we have an action match
287 
288  theGroup.first = retParameters.getValue("GroupName");
289  theGroup.second = strtol(retParameters.getValue("GroupKey").c_str(), 0, 0);
290  actionTimeString = retParameters.getValue("GroupActionTime");
291  return theGroup;
292 } // end getLastTableGroup()
293 
294 //==============================================================================
298 void RemoteWebUsers::sendSystemMessage(const std::string& toUser,
299  const std::string& message,
300  bool doEmail /*=false*/)
301 {
302  sendSystemMessage(toUser, "" /*subject*/, message, doEmail);
303 } // end sendSystemMessage)
304 
305 //==============================================================================
309 void RemoteWebUsers::sendSystemMessage(const std::string& toUser,
310  const std::string& subject,
311  const std::string& message,
312  bool doEmail /*=false*/)
313 {
314  SOAPParameters parameters;
315  parameters.addParameter("ToUser", toUser); // CSV list or *
316  parameters.addParameter("Subject", subject);
317  parameters.addParameter("Message", message);
318  parameters.addParameter("DoEmail", doEmail ? "1" : "0");
319 
320  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
321  gatewaySupervisorDescriptor_, "SupervisorSystemMessage", parameters);
322 
323  //__COUT__ << SOAPUtilities::translate(retMsg) << __E__;
324 } // end sendSystemMessage)
325 
326 //==============================================================================
329 void RemoteWebUsers::makeSystemLogEntry(const std::string& entryText)
330 {
331  SOAPParameters parameters;
332  parameters.addParameter("EntryText", entryText);
333 
334  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
335  gatewaySupervisorDescriptor_, "SupervisorSystemLogbookEntry", parameters);
336 
337  //__COUT__ << SOAPUtilities::translate(retMsg) << __E__;
338 } // end makeSystemLogEntry()
bool isWizardMode(void) const
BOOLs.
static std::string getOrPostData(cgicc::Cgicc &cgi, const std::string &needle)
XDAQ_CONST_CALL xdaq::ApplicationDescriptor * gatewaySupervisorDescriptor_
void getLastTableGroups(std::map< std::string, std::tuple< std::string, TableGroupKey, std::string >> &theGroups)
RemoteWebUsers(xdaq::Application *application, XDAQ_CONST_CALL xdaq::ApplicationDescriptor *gatewaySupervisorDescriptor)
std::pair< std::string, TableGroupKey > getLastTableGroup(const std::string &actionOfLastGroup, std::string &returnedActionTimeString)
actionOfLastGroup = "Configured" or "Started", for example
std::string getActiveUserList(void)
void sendSystemMessage(const std::string &toUser, const std::string &message, bool doEmail=false)
void makeSystemLogEntry(const std::string &entryText)
bool xmlRequestToGateway(cgicc::Cgicc &cgi, std::ostringstream *out, HttpXmlDocument *xmldoc, const AllSupervisorInfo &allSupervisorInfo, WebUsers::RequestUserInfo &userInfo)
XDAQ_CONST_CALL xdaq::ApplicationDescriptor * getDescriptor(void) const
Getters ----------------—.
static bool checkRequestAccess(cgicc::Cgicc &cgi, std::ostringstream *out, HttpXmlDocument *xmldoc, WebUsers::RequestUserInfo &userInfo, bool isWizardMode=false, const std::string &wizardModeSequence="")
Definition: WebUsers.cc:255
static void initializeRequestUserInfo(cgicc::Cgicc &cgi, WebUsers::RequestUserInfo &userInfo)
used by gateway and other supervisors to verify requests consistently
Definition: WebUsers.cc:234
static void getVectorFromString(const std::string &inputString, std::vector< std::string > &listToReturn, const std::set< char > &delimiter={',', '|', '&'}, const std::set< char > &whitespace={' ', '\t', '\n', '\r'}, std::vector< char > *listOfDelimiters=0, bool decodeURIComponents=false)
bool setGroupPermissionLevels(const std::string &groupPermissionLevelsString)
end setGroupPermissionLevels()
Definition: WebUsers.h:256