otsdaq  v1_01_03
 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  // __MOUT__ << cookieCode.length() << std::endl;
140  // __MOUT__ << "cookieCode=" << cookieCode << std::endl;
141  // __MOUT__ << 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  //__MOUT__ << "sequence=" << sequence << std::endl;
151  if(!sequence.length())
152  {
153  __MOUT__ << "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  __MOUT__ << "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  //__MOUT__ << 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  std::string tmpUserWithLock = parameters.getValue("UserWithLock");
210  uint8_t tmpUserPermissions;
211  sscanf(parameters.getValue("Permissions").c_str(),"%hhu",&tmpUserPermissions); //unsigned char
212  if(userWithLock) *userWithLock = tmpUserWithLock;
213  if(userPermissions) *userPermissions = tmpUserPermissions;
214 
215  cookieCode = parameters.getValue("CookieCode");
216 
217  //__MOUT__ << "cookieCode=" << cookieCode << std::endl;
218 
219  if(cookieCode.length() != COOKIE_CODE_LENGTH)
220  {
221  *out << RemoteWebUsers::REQ_NO_LOGIN_RESPONSE;
222  return false; //invalid cookie and present sequence, but not correct sequence
223  }
224 
225  if(tmpUserPermissions < permissionsThreshold)
226  {
227  *out << RemoteWebUsers::REQ_NO_PERMISSION_RESPONSE;
228  __MOUT__ << "User has insufficient permissions: " << tmpUserPermissions << "<" <<
229  permissionsThreshold << std::endl;
230  return false;
231  }
232 
233  if(xmldoc) //fill with cookie code tag
234  xmldoc->setHeader(cookieCode);
235 
236  if(!userName && !displayName && !activeSessionIndex && !checkLock && !lockRequired)
237  return true; //done, no need to get user info for cookie
238 
239  //__MOUT__ << "User with Lock: " << tmpUserWithLock << std::endl;
240 
241 
243  //get user info
244  parameters.clear();
245  parameters.addParameter("CookieCode",cookieCode);
246  retMsg = SOAPMessenger::sendWithSOAPReply(gatewaySupervisor,
247  "SupervisorGetUserInfo", parameters);
248 
249  parameters.clear();
250  parameters.addParameter("Username");
251  parameters.addParameter("DisplayName");
252  parameters.addParameter("ActiveSessionIndex");
253  receive(retMsg, parameters);
254  std::string tmpUserName = parameters.getValue("Username");
255  if(userName) *userName = tmpUserName;
256  if(displayName) *displayName = parameters.getValue("DisplayName");
257  if(activeSessionIndex) *activeSessionIndex = strtoul(parameters.getValue("ActiveSessionIndex").c_str(),0,0);
258 
259  if(checkLock && tmpUserWithLock != "" && tmpUserWithLock != tmpUserName)
260  {
261  *out << RemoteWebUsers::REQ_USER_LOCKOUT_RESPONSE;
262  __MOUT__ << "User " << tmpUserName << " is locked out. " << tmpUserWithLock << " has lock." << std::endl;
263  return false;
264  }
265 
266  if(lockRequired && tmpUserWithLock != tmpUserName)
267  {
268  *out << RemoteWebUsers::REQ_LOCK_REQUIRED_RESPONSE;
269  __MOUT__ << "User " << tmpUserName << " must have lock to proceed. (" << tmpUserWithLock << " has lock.)" << std::endl;
270  return false;
271  }
272 
273  return true;
274 }
275 
276 //========================================================================================================================
277 //isWizardMode
278 // return true if in wizard configuration mode
279 bool RemoteWebUsers::isWizardMode(const SupervisorDescriptorInfo& theSupervisorsDescriptorInfo)
280 {
281  return theSupervisorsDescriptorInfo.getWizardDescriptor()?true:false;
282 }
283 
284 //========================================================================================================================
285 //getActiveUserList
286 // if lastUpdateTime is not too recent as spec'd by ACTIVE_USERS_UPDATE_THRESHOLD
287 // if server responds with
288 std::string RemoteWebUsers::getActiveUserList(const xdaq::ApplicationDescriptor* supervisorDescriptor)
289 {
290 
291  if(1 || time(0) - ActiveUserLastUpdateTime_ > ACTIVE_USERS_UPDATE_THRESHOLD) //need to update
292  {
293 
294  __MOUT__ << "Need to update " << std::endl;
295 
296  xoap::MessageReference retMsg = ots::SOAPMessenger::sendWithSOAPReply(supervisorDescriptor,"SupervisorGetActiveUsers");
297 
298 
299  SOAPParameters retParameters("UserList");
300  receive(retMsg, retParameters);
301 
302  ActiveUserLastUpdateTime_ = time(0);
303  return (ActiveUserList_ = retParameters.getValue("UserList"));
304  }
305  else
306  return ActiveUserList_;
307 }
308 
309 //========================================================================================================================
310 //getLastConfigGroup
311 // request last "Configured" or "Started" group, for example
312 // returns empty "" for actionTimeString on failure
313 // returns "Wed Dec 31 18:00:01 1969 CST" for actionTimeString (in CST) if action never has occurred
314 std::pair<std::string /*group name*/, ConfigurationGroupKey> RemoteWebUsers::getLastConfigGroup(
315  const xdaq::ApplicationDescriptor* supervisorDescriptor,
316  const std::string &actionOfLastGroup,
317  std::string &actionTimeString)
318 {
319  actionTimeString = "";
320  xoap::MessageReference retMsg = ots::SOAPMessenger::sendWithSOAPReply(
321  supervisorDescriptor,"SupervisorLastConfigGroupRequest",
322  SOAPParameters("ActionOfLastGroup",actionOfLastGroup));
323 
324 
325  SOAPParameters retParameters;
326  retParameters.addParameter("GroupName");
327  retParameters.addParameter("GroupKey");
328  retParameters.addParameter("GroupAction");
329  retParameters.addParameter("GroupActionTime");
330  receive(retMsg, retParameters);
331 
332  std::pair<std::string /*group name*/, ConfigurationGroupKey> theGroup;
333  if(retParameters.getValue("GroupAction") != actionOfLastGroup) //if action doesn't match.. weird
334  {
335  __MOUT_WARN__ << "Returned group action '" << retParameters.getValue("GroupAction") <<
336  "' does not match requested group action '" << actionOfLastGroup << ".'" << std::endl;
337  return theGroup; //return empty and invalid
338  }
339  //else we have an action match
340 
341  theGroup.first = retParameters.getValue("GroupName");
342  theGroup.second = strtol(retParameters.getValue("GroupKey").c_str(),0,0);
343  actionTimeString = retParameters.getValue("GroupActionTime");
344  return theGroup;
345 }
346 
347 //========================================================================================================================
348 //getUserInfoForCookie
349 // get username and display name for user based on cookie code
350 // return true, if user info gotten successfully
351 // else false
352 bool RemoteWebUsers::getUserInfoForCookie(const xdaq::ApplicationDescriptor* supervisorDescriptor,
353  std::string &cookieCode, std::string *userName, std::string *displayName, uint64_t *activeSessionIndex)
354 {
355  __MOUT__ << std::endl;
356  if(cookieCode.length() != COOKIE_CODE_LENGTH) return false; //return if invalid cookie code
357 
358  // SOAPParametersV parameters(1);
359  // parameters[0].setName("CookieCode"); parameters[0].setValue(cookieCode);
360  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(supervisorDescriptor, "SupervisorGetUserInfo", SOAPParameters("CookieCode",cookieCode));
361 
362  SOAPParameters retParameters;
363  retParameters.addParameter("Username");
364  retParameters.addParameter("DisplayName");
365  retParameters.addParameter("ActiveSessionIndex");
366  receive(retMsg, retParameters);
367  if(userName) *userName = retParameters.getValue("Username");
368  if(displayName) *displayName = retParameters.getValue("DisplayName");
369  if(activeSessionIndex) *activeSessionIndex = strtoul(retParameters.getValue("ActiveSessionIndex").c_str(),0,0);
370 
371  __MOUT__ << "userName " << *userName << std::endl;
372 
373  return true;
374 }
375 
376 //========================================================================================================================
377 //cookieCodeIsActiveForRequest
378 // for external supervisors to check with Supervisor for login
379 bool RemoteWebUsers::cookieCodeIsActiveForRequest(const xdaq::ApplicationDescriptor* supervisorDescriptor,
380  std::string &cookieCode, uint8_t *userPermissions, std::string ip, bool refresh, std::string *userWithLock)
381 {
382  //__MOUT__ << "CookieCode: " << cookieCode << " " << cookieCode.length() << std::endl;
383  if(cookieCode.length() != COOKIE_CODE_LENGTH) return false; //return if invalid cookie code
384 
385  //
386 
387  SOAPParameters parameters;
388  parameters.addParameter("CookieCode",cookieCode);
389  parameters.addParameter("RefreshOption",refresh?"1":"0");
390 
391  //__MOUT__ << "CookieCode: " << cookieCode << std::endl;
392  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(supervisorDescriptor, "SupervisorCookieCheck", parameters);
393 
394 
395  SOAPParameters retParameters;
396  retParameters.addParameter("CookieCode");
397  retParameters.addParameter("Permissions");
398  retParameters.addParameter("UserWithLock");
399  receive(retMsg, retParameters);
400 
401 
402 
403  if(userWithLock) *userWithLock = retParameters.getValue("UserWithLock");
404  if(userPermissions) sscanf(retParameters.getValue("Permissions").c_str(),"%hhu",userPermissions); //unsigned char
405 
406  cookieCode = retParameters.getValue("CookieCode");
407 
408  return cookieCode.length() == COOKIE_CODE_LENGTH; //proper cookieCode has length 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(const xdaq::ApplicationDescriptor* supervisorDescriptor, const std::string& toUser, const std::string& msg)
415 {
416  SOAPParameters parameters;
417  parameters.addParameter("ToUser" , toUser);
418  parameters.addParameter("Message", msg);
419 
420  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(supervisorDescriptor, "SupervisorSystemMessage",parameters);
421 }
422 
423 
424 //========================================================================================================================
425 //makeSystemLogbookEntry
426 // make system logbook through Supervisor
427 void RemoteWebUsers::makeSystemLogbookEntry(const xdaq::ApplicationDescriptor* supervisorDescriptor, const std::string& entryText)
428 {
429  SOAPParameters parameters;
430  parameters.addParameter("EntryText", entryText);
431 
432  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(supervisorDescriptor, "SupervisorSystemLogbookEntry",parameters);
433 }
434