otsdaq  v2_05_02_indev
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 <vector>
12 
13 #include "otsdaq/SupervisorInfo/AllSupervisorInfo.h"
14 
15 using namespace ots;
16 
17 #undef __MF_SUBJECT__
18 #define __MF_SUBJECT__ "RemoteWebUsers"
19 
20 // clang-format off
21 //==============================================================================
22 // User Notes:
23 // - use xmlRequestGateway to check security from outside the Supervisor and Wizard
24 //
25 // Example usage:
26 //
27 //
28 //
29 // void exampleClass::exampleRequestHandler(xgi::Input * in, xgi::Output * out)
30 //
31 // {
32 // cgicc::Cgicc cgi(in);
33 //
34 // //...
35 //
36 // HttpXmlDocument xmldoc;
37 // std::string userWithLock, userName, displayName;
38 // uint64_t activeSessionIndex;
39 // uint8_t userPermissions;
40 //
41 // //**** start LOGIN GATEWAY CODE ***//
42 // //check cookieCode, sequence, userWithLock, and permissions access all in
43 // one shot!
44 // {
45 // bool automaticCommand = 0; //automatic commands should not refresh
46 // cookie code.. only user initiated commands should! bool checkLock =
47 // true; bool lockRequired = true;
48 //
49 // if(!theRemoteWebUsers_.xmlRequestToGateway(
50 // cgi,out,&xmldoc,theSupervisorsConfiguration_
51 // ,&userPermissions //acquire user's access level
52 //(optionally null pointer)//
53 // ,!automaticCommand //true/false refresh cookie code
54 // ,USER_PERMISSIONS_THRESHOLD //set access level requirement to
55 // pass gateway
56 // ,checkLock //true/false enable check that
57 // system is unlocked or this user has the lock ,lockRequired
59 // ,&userWithLock //acquire username with lock
60 //(optionally null pointer)
61 // ,&userName //acquire username of this user
62 //(optionally
63 // null pointer) ,0//,&displayName //acquire user's
64 // Display Name
65 // ,0//,&activeSessionIndex //acquire user's session index
66 // associated with the cookieCode
67 // ))
68 // { //failure
69 // //std::cout << out->str() << std::endl; //could print out return
70 // string on failure return;
71 // }
72 // }
73 // //done checking cookieCode, sequence, userWithLock, and permissions access
74 // all in one shot!
75 // //**** end LOGIN GATEWAY CODE ***//
76 //
77 // //Success! if here.
78 // //
79 // //... use acquired values below
80 // //...
81 //
82 // //add to xml document, for example:
83 // //DOMElement* parentEl;
84 // //parentEl = xmldoc.addTextElementToData("ExampleTag", "parent-data");
85 // //xmldoc.addTextElementToParent("ExampleChild", "child-data", parentEl);
86 //
87 // //return xml doc holding server response
88 // //xmldoc.outputXmlDocument((std::ostringstream*) out, true); //true to
89 // also print to std::cout
90 // }
91 //
92 //
93 // clang-format on
94 
95 //==============================================================================
96 RemoteWebUsers::RemoteWebUsers(xdaq::Application* application,
97  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* gatewaySupervisorDescriptor)
98 : SOAPMessenger(application)
99 , gatewaySupervisorDescriptor_(gatewaySupervisorDescriptor)
100 {
101  ActiveUserLastUpdateTime_ = 0; // init to never
102  ActiveUserList_ = ""; // init to empty
103 } //end constructor()
104 
105 //==============================================================================
106 // xmlRequestGateway
107 // if false, user code should just return.. out is handled on false; on true, out is
108 // untouched
109 bool RemoteWebUsers::xmlRequestToGateway(
110  cgicc::Cgicc& cgi, std::ostringstream* out, HttpXmlDocument* xmldoc, const AllSupervisorInfo& allSupervisorInfo, WebUsers::RequestUserInfo& userInfo)
111 {
112  //__COUT__ << std::endl;
113  // initialize user info parameters to failed results
114  WebUsers::initializeRequestUserInfo(cgi, userInfo);
115 
116  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* gatewaySupervisor;
117 
118  SOAPParameters parameters;
119  xoap::MessageReference retMsg;
120 
121  //**** start LOGIN GATEWAY CODE ***//
122  // If TRUE, cookie code is good, and refreshed code is in cookieCode
123  // Else, error message is returned in cookieCode
124  // tmpCookieCode_ = CgiDataUtilities::getOrPostData(cgi,"CookieCode"); //from GET or
125  // POST
126 
127  // __COUT__ << cookieCode.length() << std::endl;
128  // __COUT__ << "cookieCode=" << cookieCode << std::endl;
129  //__COUT__ << std::endl;
130 
132  // have CookieCode, try it out
133  if(allSupervisorInfo.isWizardMode())
134  {
135  // if missing CookieCode... check if in Wizard mode and using sequence
136  std::string sequence = CgiDataUtilities::getOrPostData(cgi, "sequence"); // from GET or POST
137  //__COUT__ << "sequence=" << sequence << std::endl;
138  if(!sequence.length())
139  {
140  __COUT_ERR__ << "Invalid access attempt (@" << userInfo.ip_ << ")." << std::endl;
141  *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
142  // invalid cookie and also invalid sequence
143  goto HANDLE_ACCESS_FAILURE; // return false, access failed
144  }
145 
146  // have sequence, try it out
147 
148  gatewaySupervisor = allSupervisorInfo.getWizardInfo().getDescriptor();
149  if(!gatewaySupervisor)
150  {
151  __COUT_ERR__ << "Missing wizard supervisor." << std::endl;
152  *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
153  // sequence code present, but no wizard supervisor
154  goto HANDLE_ACCESS_FAILURE; // return false, access failed
155  }
156 
157  parameters.addParameter("sequence", sequence);
158  parameters.addParameter("IPAddress", userInfo.ip_);
159  retMsg = SOAPMessenger::sendWithSOAPReply(gatewaySupervisor, "SupervisorSequenceCheck", parameters);
160  parameters.clear();
161  parameters.addParameter("Permissions");
162  SOAPUtilities::receive(retMsg, parameters);
163 
164  userInfo.setGroupPermissionLevels(parameters.getValue("Permissions"));
165 
166  if(WebUsers::checkRequestAccess(cgi, out, xmldoc, userInfo, true /*isWizardMode*/, sequence))
167  return true;
168  else
169  goto HANDLE_ACCESS_FAILURE; // return false, access failed
170 
171  // if(userInfo.permissionLevel_ < userInfo.permissionsThreshold_)
172  // {
173  // *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
174  // __COUT__ << "User (@" << userInfo.ip_ << ") has insufficient
175  // permissions: " << userInfo.permissionLevel_ << "<" <<
176  // userInfo.permissionsThreshold_ << std::endl;
177  // return false; //invalid cookie and present sequence, but not correct
178  // sequence
179  // }
180  //
181  // userInfo.setUsername("admin");
182  // userInfo.setDisplayName("Admin");
183  // userInfo.setUsernameWithLock("admin");
184  // userInfo.setActiveUserSessionIndex(0);
185  // userInfo.setGroupMemebership("admin");
186  //
187  // return true; //successful sequence login!
188  }
189 
190  // else proceed with inquiry to Gateway Supervisor
191 
192  gatewaySupervisor = allSupervisorInfo.getGatewayInfo().getDescriptor();
193 
194  if(!gatewaySupervisor)
195  {
196  __COUT_ERR__ << "Missing gateway supervisor." << std::endl;
197  *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
198  goto HANDLE_ACCESS_FAILURE; // return false, access failed
199  }
200 
201  //__COUT__ << std::endl;
202 
203  parameters.clear();
204  parameters.addParameter("CookieCode", userInfo.cookieCode_);
205  parameters.addParameter("RefreshOption", userInfo.automatedCommand_ ? "0" : "1");
206  parameters.addParameter("IPAddress", userInfo.ip_);
207 
208  retMsg = SOAPMessenger::sendWithSOAPReply(gatewaySupervisor, "SupervisorCookieCheck", parameters);
209 
210  parameters.clear();
211  parameters.addParameter("CookieCode");
212  parameters.addParameter("Permissions");
213  parameters.addParameter("UserGroups");
214  parameters.addParameter("UserWithLock");
215  parameters.addParameter("Username");
216  parameters.addParameter("DisplayName");
217  parameters.addParameter("ActiveSessionIndex");
218  SOAPUtilities::receive(retMsg, parameters);
219 
220  //__COUT__ << std::endl;
221 
222  // first extract a few things always from parameters
223  // like permissionLevel for this request... must consider allowed groups!!
224  userInfo.setGroupPermissionLevels(parameters.getValue("Permissions"));
225  userInfo.cookieCode_ = parameters.getValue("CookieCode");
226  userInfo.username_ = parameters.getValue("Username");
227  userInfo.displayName_ = parameters.getValue("DisplayName");
228  userInfo.usernameWithLock_ = parameters.getValue("UserWithLock");
229  userInfo.activeUserSessionIndex_ = strtoul(parameters.getValue("ActiveSessionIndex").c_str(), 0, 0);
230 
231  if(!WebUsers::checkRequestAccess(cgi, out, xmldoc, userInfo))
232  goto HANDLE_ACCESS_FAILURE; // return false, access failed
233  // else successful access request!
234 
235  return true; // request granted
236 
238 
239 HANDLE_ACCESS_FAILURE:
240 
241  // print out return string on failure
242  if(!userInfo.automatedCommand_)
243  __COUT_ERR__ << "Failed request (requestType = " << userInfo.requestType_ << "): " << out->str() << __E__;
244  return false; // access failed
245 } // end xmlRequestToGateway()
246 
247 //==============================================================================
248 // getActiveUserList
249 // if lastUpdateTime is not too recent as spec'd by ACTIVE_USERS_UPDATE_THRESHOLD
250 // if server responds with
251 std::string RemoteWebUsers::getActiveUserList()
252 {
253  if(time(0) - ActiveUserLastUpdateTime_ > ACTIVE_USERS_UPDATE_THRESHOLD) // need to update
254  {
255  __COUT__ << "Need to update " << std::endl;
256 
257  xoap::MessageReference retMsg = ots::SOAPMessenger::sendWithSOAPReply(
258  gatewaySupervisorDescriptor_, "SupervisorGetActiveUsers");
259 
260  SOAPParameters retParameters("UserList");
261  SOAPUtilities::receive(retMsg, retParameters);
262 
263  ActiveUserLastUpdateTime_ = time(0);
264  return (ActiveUserList_ = retParameters.getValue("UserList"));
265  }
266  else
267  return ActiveUserList_;
268 } //end getActiveUserList()
269 
270 //==============================================================================
271 // getLastTableGroup
272 // request last "Configured" or "Started" group, for example
273 // returns empty "" for actionTimeString on failure
274 // returns "Wed Dec 31 18:00:01 1969 CST" for actionTimeString (in CST) if action never
275 // has occurred
276 std::pair<std::string /*group name*/, TableGroupKey> RemoteWebUsers::getLastTableGroup( const std::string& actionOfLastGroup,
277  std::string& actionTimeString)
278 {
279  actionTimeString = "";
280  xoap::MessageReference retMsg =
281  ots::SOAPMessenger::sendWithSOAPReply(
282  gatewaySupervisorDescriptor_,
283  "SupervisorLastTableGroupRequest",
284  SOAPParameters("ActionOfLastGroup",
285  actionOfLastGroup));
286 
287  SOAPParameters retParameters;
288  retParameters.addParameter("GroupName");
289  retParameters.addParameter("GroupKey");
290  retParameters.addParameter("GroupAction");
291  retParameters.addParameter("GroupActionTime");
292  SOAPUtilities::receive(retMsg, retParameters);
293 
294  std::pair<std::string /*group name*/, TableGroupKey> theGroup;
295  if(retParameters.getValue("GroupAction") != actionOfLastGroup) // if action doesn't match.. weird
296  {
297  __COUT_WARN__ << "Returned group action '" << retParameters.getValue("GroupAction") << "' does not match requested group action '" << actionOfLastGroup
298  << ".'" << std::endl;
299  return theGroup; // return empty and invalid
300  }
301  // else we have an action match
302 
303  theGroup.first = retParameters.getValue("GroupName");
304  theGroup.second = strtol(retParameters.getValue("GroupKey").c_str(), 0, 0);
305  actionTimeString = retParameters.getValue("GroupActionTime");
306  return theGroup;
307 } //end getLastTableGroup()
308 
309 //==============================================================================
310 // sendSystemMessage
311 // send system message to toUser through Supervisor
312 // toUser wild card * is to all users
313 void RemoteWebUsers::sendSystemMessage(const std::string& toUser, const std::string& message, bool doEmail /*=false*/)
314 {
315  sendSystemMessage(toUser, "" /*subject*/, message, doEmail);
316 } //end sendSystemMessage)
317 
318 //==============================================================================
319 // sendSystemMessage
320 // send system message to toUser comma separate variable (CSV) list through Supervisor
321 // toUser wild card * is to all users
322 void RemoteWebUsers::sendSystemMessage(const std::string& toUser, const std::string& subject, const std::string& message, bool doEmail /*=false*/)
323 {
324  SOAPParameters parameters;
325  parameters.addParameter("ToUser", toUser); // CSV list or *
326  parameters.addParameter("Subject", subject);
327  parameters.addParameter("Message", message);
328  parameters.addParameter("DoEmail", doEmail?"1":"0");
329 
330  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
331  gatewaySupervisorDescriptor_, "SupervisorSystemMessage", parameters);
332 
333  //__COUT__ << SOAPUtilities::translate(retMsg) << __E__;
334 } //end sendSystemMessage)
335 
336 //==============================================================================
337 // makeSystemLogbookEntry
338 // make system logbook through Supervisor
339 void RemoteWebUsers::makeSystemLogbookEntry(const std::string& entryText)
340 {
341  SOAPParameters parameters;
342  parameters.addParameter("EntryText", entryText);
343 
344  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
345  gatewaySupervisorDescriptor_, "SupervisorSystemLogbookEntry", parameters);
346 
347  //__COUT__ << SOAPUtilities::translate(retMsg) << __E__;
348 } //end makeSystemLogbookEntry()