otsdaq  v2_04_02
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 //========================================================================================================================
21 // User Notes:
22 // - use xmlRequestGateway to check security from outside the Supervisor and Wizard
23 //
24 // Example usage:
25 //
26 //
27 //
28 // void exampleClass::exampleRequestHandler(xgi::Input * in, xgi::Output * out)
29 //
30 // {
31 // cgicc::Cgicc cgi(in);
32 //
33 // //...
34 //
35 // HttpXmlDocument xmldoc;
36 // std::string userWithLock, userName, displayName;
37 // uint64_t activeSessionIndex;
38 // uint8_t userPermissions;
39 //
40 // //**** start LOGIN GATEWAY CODE ***//
41 // //check cookieCode, sequence, userWithLock, and permissions access all in
42 // one shot!
43 // {
44 // bool automaticCommand = 0; //automatic commands should not refresh
45 // cookie code.. only user initiated commands should! bool checkLock =
46 // true; bool lockRequired = true;
47 //
48 // if(!theRemoteWebUsers_.xmlRequestToGateway(
49 // cgi,out,&xmldoc,theSupervisorsConfiguration_
50 // ,&userPermissions //acquire user's access level
51 //(optionally null pointer)//
52 // ,!automaticCommand //true/false refresh cookie code
53 // ,USER_PERMISSIONS_THRESHOLD //set access level requirement to
54 // pass gateway
55 // ,checkLock //true/false enable check that
56 // system is unlocked or this user has the lock ,lockRequired
58 // ,&userWithLock //acquire username with lock
59 //(optionally null pointer)
60 // ,&userName //acquire username of this user
61 //(optionally
62 // null pointer) ,0//,&displayName //acquire user's
63 // Display Name
64 // ,0//,&activeSessionIndex //acquire user's session index
65 // associated with the cookieCode
66 // ))
67 // { //failure
68 // //std::cout << out->str() << std::endl; //could print out return
69 // string on failure return;
70 // }
71 // }
72 // //done checking cookieCode, sequence, userWithLock, and permissions access
73 // all in one shot!
74 // //**** end LOGIN GATEWAY CODE ***//
75 //
76 // //Success! if here.
77 // //
78 // //... use acquired values below
79 // //...
80 //
81 // //add to xml document, for example:
82 // //DOMElement* parentEl;
83 // //parentEl = xmldoc.addTextElementToData("ExampleTag", "parent-data");
84 // //xmldoc.addTextElementToParent("ExampleChild", "child-data", parentEl);
85 //
86 // //return xml doc holding server response
87 // //xmldoc.outputXmlDocument((std::ostringstream*) out, true); //true to
88 // also print to std::cout
89 // }
90 //
91 //
92 //========================================================================================================================
93 
94 RemoteWebUsers::RemoteWebUsers(xdaq::Application* application)
95  : SOAPMessenger(application)
96 {
97  ActiveUserLastUpdateTime_ = 0; // init to never
98  ActiveUserList_ = ""; // init to empty
99 }
100 
101 //========================================================================================================================
102 // xmlRequestGateway
103 // if false, user code should just return.. out is handled on false; on true, out is
104 // untouched
105 bool RemoteWebUsers::xmlRequestToGateway(cgicc::Cgicc& cgi,
106  std::ostringstream* out,
107  HttpXmlDocument* xmldoc,
108  const AllSupervisorInfo& allSupervisorInfo,
109  WebUsers::RequestUserInfo& userInfo)
110 {
111  //__COUT__ << std::endl;
112  // initialize user info parameters to failed results
113  WebUsers::initializeRequestUserInfo(cgi, userInfo);
114 
115  // const_cast away the const
116  // so that this line is compatible with slf6 and slf7 versions of xdaq
117  // where they changed to XDAQ_CONST_CALL xdaq::ApplicationDescriptor* in slf7
118  //
119  // XDAQ_CONST_CALL is defined in "otsdaq/Macros/CoutMacros.h"
120  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* gatewaySupervisor;
121 
122  SOAPParameters parameters;
123  xoap::MessageReference retMsg;
124 
125  //**** start LOGIN GATEWAY CODE ***//
126  // If TRUE, cookie code is good, and refreshed code is in cookieCode
127  // Else, error message is returned in cookieCode
128  // tmpCookieCode_ = CgiDataUtilities::getOrPostData(cgi,"CookieCode"); //from GET or
129  // POST
130 
131  // __COUT__ << cookieCode.length() << std::endl;
132  // __COUT__ << "cookieCode=" << cookieCode << std::endl;
133  //__COUT__ << std::endl;
134 
136  // have CookieCode, try it out
137  if(allSupervisorInfo.isWizardMode())
138  {
139  // if missing CookieCode... check if in Wizard mode and using sequence
140  std::string sequence =
141  CgiDataUtilities::getOrPostData(cgi, "sequence"); // from GET or POST
142  //__COUT__ << "sequence=" << sequence << std::endl;
143  if(!sequence.length())
144  {
145  __COUT_ERR__ << "Invalid access attempt (@" << userInfo.ip_ << ")."
146  << std::endl;
147  *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
148  // invalid cookie and also invalid sequence
149  goto HANDLE_ACCESS_FAILURE; // return false, access failed
150  }
151 
152  // have sequence, try it out
153 
154  gatewaySupervisor = allSupervisorInfo.getWizardInfo().getDescriptor();
155  if(!gatewaySupervisor)
156  {
157  __COUT_ERR__ << "Missing wizard supervisor." << std::endl;
158  *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
159  // sequence code present, but no wizard supervisor
160  goto HANDLE_ACCESS_FAILURE; // return false, access failed
161  }
162 
163  parameters.addParameter("sequence", sequence);
164  parameters.addParameter("IPAddress", userInfo.ip_);
165  retMsg = SOAPMessenger::sendWithSOAPReply(
166  gatewaySupervisor, "SupervisorSequenceCheck", parameters);
167  parameters.clear();
168  parameters.addParameter("Permissions");
169  SOAPUtilities::receive(retMsg, parameters);
170 
171  userInfo.setGroupPermissionLevels(parameters.getValue("Permissions"));
172 
173  if(WebUsers::checkRequestAccess(
174  cgi, out, xmldoc, userInfo, true /*isWizardMode*/, sequence))
175  return true;
176  else
177  goto HANDLE_ACCESS_FAILURE; // return false, access failed
178 
179  // if(userInfo.permissionLevel_ < userInfo.permissionsThreshold_)
180  // {
181  // *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
182  // __COUT__ << "User (@" << userInfo.ip_ << ") has insufficient
183  // permissions: " << userInfo.permissionLevel_ << "<" <<
184  // userInfo.permissionsThreshold_ << std::endl;
185  // return false; //invalid cookie and present sequence, but not correct
186  // sequence
187  // }
188  //
189  // userInfo.setUsername("admin");
190  // userInfo.setDisplayName("Admin");
191  // userInfo.setUsernameWithLock("admin");
192  // userInfo.setActiveUserSessionIndex(0);
193  // userInfo.setGroupMemebership("admin");
194  //
195  // return true; //successful sequence login!
196  }
197 
198  // else proceed with inquiry to Gateway Supervisor
199 
200  gatewaySupervisor = allSupervisorInfo.getGatewayInfo().getDescriptor();
201 
202  if(!gatewaySupervisor)
203  {
204  __COUT_ERR__ << "Missing gateway supervisor." << std::endl;
205  *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
206  goto HANDLE_ACCESS_FAILURE; // return false, access failed
207  }
208 
209  //__COUT__ << std::endl;
210 
211  parameters.clear();
212  parameters.addParameter("CookieCode", userInfo.cookieCode_);
213  parameters.addParameter("RefreshOption", userInfo.automatedCommand_ ? "0" : "1");
214  parameters.addParameter("IPAddress", userInfo.ip_);
215 
216  retMsg = SOAPMessenger::sendWithSOAPReply(
217  gatewaySupervisor, "SupervisorCookieCheck", parameters);
218 
219  parameters.clear();
220  parameters.addParameter("CookieCode");
221  parameters.addParameter("Permissions");
222  parameters.addParameter("UserGroups");
223  parameters.addParameter("UserWithLock");
224  parameters.addParameter("Username");
225  parameters.addParameter("DisplayName");
226  parameters.addParameter("ActiveSessionIndex");
227  SOAPUtilities::receive(retMsg, parameters);
228 
229  //__COUT__ << std::endl;
230 
231  // first extract a few things always from parameters
232  // like permissionLevel for this request... must consider allowed groups!!
233  userInfo.setGroupPermissionLevels(parameters.getValue("Permissions"));
234  userInfo.cookieCode_ = parameters.getValue("CookieCode");
235  userInfo.username_ = parameters.getValue("Username");
236  userInfo.displayName_ = parameters.getValue("DisplayName");
237  userInfo.usernameWithLock_ = parameters.getValue("UserWithLock");
238  userInfo.activeUserSessionIndex_ =
239  strtoul(parameters.getValue("ActiveSessionIndex").c_str(), 0, 0);
240 
241  if(!WebUsers::checkRequestAccess(cgi, out, xmldoc, userInfo))
242  goto HANDLE_ACCESS_FAILURE; // return false, access failed
243  // else successful access request!
244 
245  return true; // request granted
246 
248 
249 HANDLE_ACCESS_FAILURE:
250 
251  // print out return string on failure
252  if(!userInfo.automatedCommand_)
253  __COUT_ERR__ << "Failed request (requestType = " << userInfo.requestType_
254  << "): " << out->str() << __E__;
255  return false; // access failed
256 } // end xmlRequestToGateway()
257 
258 //========================================================================================================================
259 // getActiveUserList
260 // if lastUpdateTime is not too recent as spec'd by ACTIVE_USERS_UPDATE_THRESHOLD
261 // if server responds with
262 std::string RemoteWebUsers::getActiveUserList(
263  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* supervisorDescriptor)
264 {
265  if(1 || time(0) - ActiveUserLastUpdateTime_ >
266  ACTIVE_USERS_UPDATE_THRESHOLD) // need to update
267  {
268  __COUT__ << "Need to update " << std::endl;
269 
270  xoap::MessageReference retMsg = ots::SOAPMessenger::sendWithSOAPReply(
271  supervisorDescriptor, "SupervisorGetActiveUsers");
272 
273  SOAPParameters retParameters("UserList");
274  SOAPUtilities::receive(retMsg, retParameters);
275 
276  ActiveUserLastUpdateTime_ = time(0);
277  return (ActiveUserList_ = retParameters.getValue("UserList"));
278  }
279  else
280  return ActiveUserList_;
281 }
282 
283 //========================================================================================================================
284 // getLastConfigGroup
285 // request last "Configured" or "Started" group, for example
286 // returns empty "" for actionTimeString on failure
287 // returns "Wed Dec 31 18:00:01 1969 CST" for actionTimeString (in CST) if action never
288 // has occurred
289 std::pair<std::string /*group name*/, TableGroupKey> RemoteWebUsers::getLastConfigGroup(
290  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* supervisorDescriptor,
291  const std::string& actionOfLastGroup,
292  std::string& actionTimeString)
293 {
294  actionTimeString = "";
295  xoap::MessageReference retMsg = ots::SOAPMessenger::sendWithSOAPReply(
296  supervisorDescriptor,
297  "SupervisorLastConfigGroupRequest",
298  SOAPParameters("ActionOfLastGroup", actionOfLastGroup));
299 
300  SOAPParameters retParameters;
301  retParameters.addParameter("GroupName");
302  retParameters.addParameter("GroupKey");
303  retParameters.addParameter("GroupAction");
304  retParameters.addParameter("GroupActionTime");
305  SOAPUtilities::receive(retMsg, retParameters);
306 
307  std::pair<std::string /*group name*/, TableGroupKey> theGroup;
308  if(retParameters.getValue("GroupAction") !=
309  actionOfLastGroup) // if action doesn't match.. weird
310  {
311  __COUT_WARN__ << "Returned group action '"
312  << retParameters.getValue("GroupAction")
313  << "' does not match requested group action '" << actionOfLastGroup
314  << ".'" << std::endl;
315  return theGroup; // return empty and invalid
316  }
317  // else we have an action match
318 
319  theGroup.first = retParameters.getValue("GroupName");
320  theGroup.second = strtol(retParameters.getValue("GroupKey").c_str(), 0, 0);
321  actionTimeString = retParameters.getValue("GroupActionTime");
322  return theGroup;
323 }
324 
325 //========================================================================================================================
326 // getUserInfoForCookie
327 // get username and display name for user based on cookie code
328 // return true, if user info gotten successfully
329 // else false
330 bool RemoteWebUsers::getUserInfoForCookie(
331  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* supervisorDescriptor,
332  std::string& cookieCode,
333  std::string* userName,
334  std::string* displayName,
335  uint64_t* activeSessionIndex)
336 {
337  __COUT__ << std::endl;
338  if(cookieCode.length() != WebUsers::COOKIE_CODE_LENGTH)
339  return false; // return if invalid cookie code
340 
341  // SOAPParametersV parameters(1);
342  // parameters[0].setName("CookieCode"); parameters[0].setValue(cookieCode);
343  xoap::MessageReference retMsg =
344  SOAPMessenger::sendWithSOAPReply(supervisorDescriptor,
345  "SupervisorGetUserInfo",
346  SOAPParameters("CookieCode", cookieCode));
347 
348  SOAPParameters retParameters;
349  retParameters.addParameter("Username");
350  retParameters.addParameter("DisplayName");
351  retParameters.addParameter("ActiveSessionIndex");
352  SOAPUtilities::receive(retMsg, retParameters);
353  if(userName)
354  *userName = retParameters.getValue("Username");
355  if(displayName)
356  *displayName = retParameters.getValue("DisplayName");
357  if(activeSessionIndex)
358  *activeSessionIndex =
359  strtoul(retParameters.getValue("ActiveSessionIndex").c_str(), 0, 0);
360 
361  __COUT__ << "userName " << *userName << std::endl;
362 
363  return true;
364 }
365 
366 //========================================================================================================================
367 // cookieCodeIsActiveForRequest
368 // for external supervisors to check with Supervisor for login
369 bool RemoteWebUsers::cookieCodeIsActiveForRequest(
370  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* supervisorDescriptor,
371  std::string& cookieCode,
372  uint8_t* userPermissions,
373  std::string ip,
374  bool refreshCookie,
375  std::string* userWithLock)
376 {
377  //__COUT__ << "CookieCode: " << cookieCode << " " << cookieCode.length() << std::endl;
378  if(cookieCode.length() != WebUsers::COOKIE_CODE_LENGTH)
379  return false; // return if invalid cookie code
380 
381  //
382 
383  SOAPParameters parameters;
384  parameters.addParameter("CookieCode", cookieCode);
385  parameters.addParameter("RefreshOption", refreshCookie ? "1" : "0");
386 
387  //__COUT__ << "CookieCode: " << cookieCode << std::endl;
388  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
389  supervisorDescriptor, "SupervisorCookieCheck", parameters);
390 
391  SOAPParameters retParameters;
392  retParameters.addParameter("CookieCode");
393  retParameters.addParameter("Permissions");
394  retParameters.addParameter("UserWithLock");
395  SOAPUtilities::receive(retMsg, retParameters);
396 
397  if(userWithLock)
398  *userWithLock = retParameters.getValue("UserWithLock");
399  if(userPermissions)
400  sscanf(retParameters.getValue("Permissions").c_str(),
401  "%hhu",
402  userPermissions); // unsigned char
403 
404  cookieCode = retParameters.getValue("CookieCode");
405 
406  return cookieCode.length() ==
407  WebUsers::COOKIE_CODE_LENGTH; // proper cookieCode has length
408  // WebUsers::COOKIE_CODE_LENGTH
409 }
410 //========================================================================================================================
411 // sendSystemMessage
412 // send system message to toUser through Supervisor
413 // toUser wild card * is to all users
414 void RemoteWebUsers::sendSystemMessage(
415  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* supervisorDescriptor,
416  const std::string& toUser,
417  const std::string& msg)
418 {
419  SOAPParameters parameters;
420  parameters.addParameter("ToUser", toUser);
421  parameters.addParameter("Message", msg);
422 
423  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
424  supervisorDescriptor, "SupervisorSystemMessage", parameters);
425 }
426 
427 //========================================================================================================================
428 // makeSystemLogbookEntry
429 // make system logbook through Supervisor
430 void RemoteWebUsers::makeSystemLogbookEntry(
431  XDAQ_CONST_CALL xdaq::ApplicationDescriptor* supervisorDescriptor,
432  const std::string& entryText)
433 {
434  SOAPParameters parameters;
435  parameters.addParameter("EntryText", entryText);
436 
437  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
438  supervisorDescriptor, "SupervisorSystemLogbookEntry", parameters);
439 }