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