otsdaq  v1_01_04
 All Classes Namespaces Functions
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 "otsdaq-core/SupervisorDescriptorInfo/SupervisorDescriptorInfo.h"
11 
12 #include <cstdlib>
13 #include <cstdio>
14 #include <vector>
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 
89 RemoteWebUsers::RemoteWebUsers(xdaq::Application* application)
90 : SOAPMessenger (application)
91 {
92  ActiveUserLastUpdateTime_ = 0; //init to never
93  ActiveUserList_ = ""; //init to empty
94 }
95 
96 //========================================================================================================================
97 //xmlLoginGateway
98 // if false, user code should just return.. out is handled on false; on true, out is untouched
99 bool RemoteWebUsers::xmlLoginGateway(
100  cgicc::Cgicc &cgi,
101  std::ostringstream *out,
102  HttpXmlDocument *xmldoc,
103  const SupervisorDescriptorInfo &theSupervisorsDescriptorInfo,
104  uint8_t *userPermissions,
105  const bool refresh,
106  const uint8_t permissionsThreshold,
107  const bool checkLock,
108  const bool lockRequired,
109  std::string *userWithLock,
110  std::string *userName,
111  std::string *displayName,
112  uint64_t *activeSessionIndex)
113 {
114  //initialized optional acquisition parameters to failed results
115  if(userPermissions) *userPermissions = 0;
116  if(userWithLock) *userWithLock = "";
117  if(userName) *userName = "";
118  if(displayName) *displayName = "";
119  if(activeSessionIndex) *activeSessionIndex = -1;
120 
121  const std::string ip = cgi.getEnvironment().getRemoteAddr();
122 
123 
124  //const_cast away the const
125  // so that this line is compatible with slf6 and slf7 versions of xdaq
126  // where they changed to const xdaq::ApplicationDescriptor* in slf7
127  //
128  // XDAQ_CONST_CALL is defined in "otsdaq-core/Macros/CoutHeaderMacros.h"
129  const xdaq::ApplicationDescriptor* gatewaySupervisor;
130 
131  SOAPParameters parameters;
132  xoap::MessageReference retMsg;
133 
134  //**** start LOGIN GATEWAY CODE ***//
135  //If TRUE, cookie code is good, and refreshed code is in cookieCode, also pointers optionally for uint8_t userPermissions
136  //Else, error message is returned in cookieCode
137  std::string cookieCode = CgiDataUtilities::getOrPostData(cgi,"CookieCode"); //from GET or POST
138 
139  // __COUT__ << cookieCode.length() << std::endl;
140  // __COUT__ << "cookieCode=" << cookieCode << std::endl;
141  // __COUT__ << std::endl;
142 
144  //have CookieCode, try it out
145  gatewaySupervisor = theSupervisorsDescriptorInfo.getSupervisorDescriptor();
146  if(!gatewaySupervisor) //assume using wizard mode
147  {
148  //if missing CookieCode... check if in Wizard mode and using sequence
149  std::string sequence = CgiDataUtilities::getOrPostData(cgi,"sequence"); //from GET or POST
150  //__COUT__ << "sequence=" << sequence << std::endl;
151  if(!sequence.length())
152  {
153  __COUT__ << "Invalid attempt." << std::endl;
154  *out << RemoteWebUsers::REQ_NO_LOGIN_RESPONSE;
155  return false; //invalid cookie and also invalid sequence
156  }
157 
158  //have sequence, try it out
159 
160  gatewaySupervisor = theSupervisorsDescriptorInfo.getWizardDescriptor();
161  if(!gatewaySupervisor)
162  {
163  *out << RemoteWebUsers::REQ_NO_LOGIN_RESPONSE;
164  return false; //invalid cookie and present sequence, but no wizard supervisor
165  }
166 
167  parameters.addParameter("sequence",sequence);
168  retMsg = SOAPMessenger::sendWithSOAPReply(gatewaySupervisor,
169  "SupervisorSequenceCheck", parameters);
170  parameters.clear();
171  parameters.addParameter("Permissions");
172  receive(retMsg, parameters);
173 
174  uint8_t tmpUserPermissions_;
175  sscanf(parameters.getValue("Permissions").c_str(),"%hhu",&tmpUserPermissions_); //unsigned char
176 
177  if(userPermissions) *userPermissions = tmpUserPermissions_;
178 
179  if(tmpUserPermissions_ < permissionsThreshold)
180  {
181  *out << RemoteWebUsers::REQ_NO_LOGIN_RESPONSE;
182  __COUT__ << "User has insufficient permissions: " << tmpUserPermissions_ << "<" <<
183  permissionsThreshold << std::endl;
184  return false; //invalid cookie and present sequence, but not correct sequence
185  }
186 
187  if(userWithLock) *userWithLock = "admin";
188  if(userName) *userName = "admin";
189  if(displayName) *displayName = "Admin";
190  if(activeSessionIndex) *activeSessionIndex = 0;
191 
192  return true; //successful sequence login!
193  }
194 
195  //__COUT__ << std::endl;
196 
197  parameters.clear();
198  parameters.addParameter("CookieCode",cookieCode);
199  parameters.addParameter("RefreshOption",refresh?"1":"0");
200 
201  retMsg = SOAPMessenger::sendWithSOAPReply(gatewaySupervisor,
202  "SupervisorCookieCheck", parameters);
203 
204  parameters.clear();
205  parameters.addParameter("CookieCode");
206  parameters.addParameter("Permissions");
207  parameters.addParameter("UserWithLock");
208  receive(retMsg, parameters);
209  tmpUserWithLock_ = parameters.getValue("UserWithLock");
210  sscanf(parameters.getValue("Permissions").c_str(),"%hhu",&tmpUserPermissions_); //unsigned char
211  if(userWithLock) *userWithLock = tmpUserWithLock_;
212  if(userPermissions) *userPermissions = tmpUserPermissions_;
213 
214  cookieCode = parameters.getValue("CookieCode");
215 
216  //__COUT__ << "cookieCode=" << cookieCode << std::endl;
217 
218  if(cookieCode.length() != COOKIE_CODE_LENGTH)
219  {
220  *out << RemoteWebUsers::REQ_NO_LOGIN_RESPONSE;
221  return false; //invalid cookie and present sequence, but not correct sequence
222  }
223 
224  if(tmpUserPermissions_ < permissionsThreshold)
225  {
226  *out << RemoteWebUsers::REQ_NO_PERMISSION_RESPONSE;
227  __COUT__ << "User has insufficient permissions: " << tmpUserPermissions_ << "<" <<
228  permissionsThreshold << std::endl;
229  return false;
230  }
231 
232  if(xmldoc) //fill with cookie code tag
233  xmldoc->setHeader(cookieCode);
234 
235  if(!userName && !displayName && !activeSessionIndex && !checkLock && !lockRequired)
236  return true; //done, no need to get user info for cookie
237 
238  //__COUT__ << "User with Lock: " << tmpUserWithLock_ << std::endl;
239 
240 
242  //get user info
243  parameters.clear();
244  parameters.addParameter("CookieCode",cookieCode);
245  retMsg = SOAPMessenger::sendWithSOAPReply(gatewaySupervisor,
246  "SupervisorGetUserInfo", parameters);
247 
248  parameters.clear();
249  parameters.addParameter("Username");
250  parameters.addParameter("DisplayName");
251  parameters.addParameter("ActiveSessionIndex");
252  receive(retMsg, parameters);
253  std::string tmpUserName = parameters.getValue("Username");
254  if(userName) *userName = tmpUserName;
255  if(displayName) *displayName = parameters.getValue("DisplayName");
256  if(activeSessionIndex) *activeSessionIndex = strtoul(parameters.getValue("ActiveSessionIndex").c_str(),0,0);
257 
258  if(checkLock && tmpUserWithLock_ != "" && tmpUserWithLock_ != tmpUserName)
259  {
260  *out << RemoteWebUsers::REQ_USER_LOCKOUT_RESPONSE;
261  __COUT__ << "User " << tmpUserName << " is locked out. " << tmpUserWithLock_ << " has lock." << std::endl;
262  return false;
263  }
264 
265  if(lockRequired && tmpUserWithLock_ != tmpUserName)
266  {
267  *out << RemoteWebUsers::REQ_LOCK_REQUIRED_RESPONSE;
268  __COUT__ << "User " << tmpUserName << " must have lock to proceed. (" << tmpUserWithLock_ << " has lock.)" << std::endl;
269  return false;
270  }
271 
272  return true;
273 }
274 
275 //========================================================================================================================
276 //isWizardMode
277 // return true if in wizard configuration mode
278 bool RemoteWebUsers::isWizardMode(const SupervisorDescriptorInfo& theSupervisorsDescriptorInfo)
279 {
280  return theSupervisorsDescriptorInfo.getWizardDescriptor()?true:false;
281 }
282 
283 //========================================================================================================================
284 //getActiveUserList
285 // if lastUpdateTime is not too recent as spec'd by ACTIVE_USERS_UPDATE_THRESHOLD
286 // if server responds with
287 std::string RemoteWebUsers::getActiveUserList(const xdaq::ApplicationDescriptor* supervisorDescriptor)
288 {
289 
290  if(1 || time(0) - ActiveUserLastUpdateTime_ > ACTIVE_USERS_UPDATE_THRESHOLD) //need to update
291  {
292 
293  __COUT__ << "Need to update " << std::endl;
294 
295  xoap::MessageReference retMsg = ots::SOAPMessenger::sendWithSOAPReply(supervisorDescriptor,"SupervisorGetActiveUsers");
296 
297 
298  SOAPParameters retParameters("UserList");
299  receive(retMsg, retParameters);
300 
301  ActiveUserLastUpdateTime_ = time(0);
302  return (ActiveUserList_ = retParameters.getValue("UserList"));
303  }
304  else
305  return ActiveUserList_;
306 }
307 
308 //========================================================================================================================
309 //getLastConfigGroup
310 // request last "Configured" or "Started" group, for example
311 // returns empty "" for actionTimeString on failure
312 // returns "Wed Dec 31 18:00:01 1969 CST" for actionTimeString (in CST) if action never has occurred
313 std::pair<std::string /*group name*/, ConfigurationGroupKey> RemoteWebUsers::getLastConfigGroup(
314  const xdaq::ApplicationDescriptor* supervisorDescriptor,
315  const std::string &actionOfLastGroup,
316  std::string &actionTimeString)
317 {
318  actionTimeString = "";
319  xoap::MessageReference retMsg = ots::SOAPMessenger::sendWithSOAPReply(
320  supervisorDescriptor,"SupervisorLastConfigGroupRequest",
321  SOAPParameters("ActionOfLastGroup",actionOfLastGroup));
322 
323 
324  SOAPParameters retParameters;
325  retParameters.addParameter("GroupName");
326  retParameters.addParameter("GroupKey");
327  retParameters.addParameter("GroupAction");
328  retParameters.addParameter("GroupActionTime");
329  receive(retMsg, retParameters);
330 
331  std::pair<std::string /*group name*/, ConfigurationGroupKey> theGroup;
332  if(retParameters.getValue("GroupAction") != actionOfLastGroup) //if action doesn't match.. weird
333  {
334  __COUT_WARN__ << "Returned group action '" << retParameters.getValue("GroupAction") <<
335  "' does not match requested group action '" << actionOfLastGroup << ".'" << std::endl;
336  return theGroup; //return empty and invalid
337  }
338  //else we have an action match
339 
340  theGroup.first = retParameters.getValue("GroupName");
341  theGroup.second = strtol(retParameters.getValue("GroupKey").c_str(),0,0);
342  actionTimeString = retParameters.getValue("GroupActionTime");
343  return theGroup;
344 }
345 
346 //========================================================================================================================
347 //getUserInfoForCookie
348 // get username and display name for user based on cookie code
349 // return true, if user info gotten successfully
350 // else false
351 bool RemoteWebUsers::getUserInfoForCookie(const xdaq::ApplicationDescriptor* supervisorDescriptor,
352  std::string &cookieCode, std::string *userName, std::string *displayName, uint64_t *activeSessionIndex)
353 {
354  __COUT__ << std::endl;
355  if(cookieCode.length() != COOKIE_CODE_LENGTH) return false; //return if invalid cookie code
356 
357  // SOAPParametersV parameters(1);
358  // parameters[0].setName("CookieCode"); parameters[0].setValue(cookieCode);
359  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(supervisorDescriptor, "SupervisorGetUserInfo", SOAPParameters("CookieCode",cookieCode));
360 
361  SOAPParameters retParameters;
362  retParameters.addParameter("Username");
363  retParameters.addParameter("DisplayName");
364  retParameters.addParameter("ActiveSessionIndex");
365  receive(retMsg, retParameters);
366  if(userName) *userName = retParameters.getValue("Username");
367  if(displayName) *displayName = retParameters.getValue("DisplayName");
368  if(activeSessionIndex) *activeSessionIndex = strtoul(retParameters.getValue("ActiveSessionIndex").c_str(),0,0);
369 
370  __COUT__ << "userName " << *userName << std::endl;
371 
372  return true;
373 }
374 
375 //========================================================================================================================
376 //cookieCodeIsActiveForRequest
377 // for external supervisors to check with Supervisor for login
378 bool RemoteWebUsers::cookieCodeIsActiveForRequest(const xdaq::ApplicationDescriptor* supervisorDescriptor,
379  std::string &cookieCode, uint8_t *userPermissions, std::string ip, bool refresh, std::string *userWithLock)
380 {
381  //__COUT__ << "CookieCode: " << cookieCode << " " << cookieCode.length() << std::endl;
382  if(cookieCode.length() != COOKIE_CODE_LENGTH) return false; //return if invalid cookie code
383 
384  //
385 
386  SOAPParameters parameters;
387  parameters.addParameter("CookieCode",cookieCode);
388  parameters.addParameter("RefreshOption",refresh?"1":"0");
389 
390  //__COUT__ << "CookieCode: " << cookieCode << std::endl;
391  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(supervisorDescriptor, "SupervisorCookieCheck", parameters);
392 
393 
394  SOAPParameters retParameters;
395  retParameters.addParameter("CookieCode");
396  retParameters.addParameter("Permissions");
397  retParameters.addParameter("UserWithLock");
398  receive(retMsg, retParameters);
399 
400 
401 
402  if(userWithLock) *userWithLock = retParameters.getValue("UserWithLock");
403  if(userPermissions) sscanf(retParameters.getValue("Permissions").c_str(),"%hhu",userPermissions); //unsigned char
404 
405  cookieCode = retParameters.getValue("CookieCode");
406 
407  return cookieCode.length() == COOKIE_CODE_LENGTH; //proper cookieCode has length COOKIE_CODE_LENGTH
408 }
409 //========================================================================================================================
410 //sendSystemMessage
411 // send system message to toUser through Supervisor
412 // toUser wild card * is to all users
413 void RemoteWebUsers::sendSystemMessage(const xdaq::ApplicationDescriptor* supervisorDescriptor, const std::string& toUser, const std::string& msg)
414 {
415  SOAPParameters parameters;
416  parameters.addParameter("ToUser" , toUser);
417  parameters.addParameter("Message", msg);
418 
419  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(supervisorDescriptor, "SupervisorSystemMessage",parameters);
420 }
421 
422 
423 //========================================================================================================================
424 //makeSystemLogbookEntry
425 // make system logbook through Supervisor
426 void RemoteWebUsers::makeSystemLogbookEntry(const xdaq::ApplicationDescriptor* supervisorDescriptor, const std::string& entryText)
427 {
428  SOAPParameters parameters;
429  parameters.addParameter("EntryText", entryText);
430 
431  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(supervisorDescriptor, "SupervisorSystemLogbookEntry",parameters);
432 }
433