soapservice.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #pragma warning( disable : 4786)
  14. #include "esphttp.hpp"
  15. //ESP Bindings
  16. #include "platform.h"
  17. #include <xpp/XmlPullParser.h>
  18. #include <xjx/xjxpp.hpp>
  19. #include "SOAP/Platform/soapservice.hpp"
  20. #include "http/platform/httpservice.hpp"
  21. #include "bindutil.hpp"
  22. #include "authenticate.hpp"
  23. #include <memory>
  24. using namespace std;
  25. using namespace xpp;
  26. #ifdef _DEBUG
  27. //#define DEBUG_SOAP_
  28. #endif
  29. int CSoapService::processHeader(CHeader* header, IEspContext* ctx)
  30. {
  31. int num = header->getNumBlocks();
  32. if(ctx == NULL)
  33. return 0;
  34. int returnValue = 0;
  35. bool authenticated = !ctx->toBeAuthenticated();
  36. for (int i = 0; i < num; i++)
  37. {
  38. IRpcMessage* oneblock = header->getHeaderBlock(i);
  39. if(oneblock == NULL)
  40. continue;
  41. if(strcmp(oneblock->get_name(), "Security") == 0)
  42. {
  43. bool encodeXML = oneblock->getEncodeXml();
  44. oneblock->setEncodeXml(false);
  45. StringBuffer username, password,realm;
  46. oneblock->get_value("UsernameToken/Username", username);
  47. oneblock->get_value("UsernameToken/Password", password);
  48. oneblock->get_value("RealmToken/Realm", realm);
  49. oneblock->setEncodeXml(encodeXML);
  50. //DBGLOG("username=%s, password=%s", username.str(), password.str());
  51. if(username.length() > 0)
  52. {
  53. ctx->setUserID(username.str());
  54. ctx->setPassword(password.str());
  55. if(realm.length()>0)
  56. ctx->setRealm(realm.str());
  57. ISecManager* secmgr = ctx->querySecManager();
  58. if(secmgr != NULL)
  59. {
  60. ISecUser *user = ctx->queryUser();
  61. if(user==NULL)
  62. {
  63. user = secmgr->createUser(username.str());
  64. ctx->setUser(user);
  65. }
  66. if(user == NULL)
  67. {
  68. WARNLOG("Couldn't create ISecUser object for %s", username.str());
  69. }
  70. user->setName(username.str());
  71. user->credentials().setPassword(password.str());
  72. if(realm.length()>0)
  73. user->setRealm(realm.str());
  74. }
  75. if(ctx->toBeAuthenticated())
  76. {
  77. if(stricmp(m_soapbinding->getTransportType(), "http") == 0)
  78. {
  79. EspHttpBinding* httpbinding = dynamic_cast<EspHttpBinding*>(m_soapbinding.get());
  80. authenticated = httpbinding->doAuth(ctx);
  81. }
  82. else
  83. {
  84. authenticated = false;
  85. }
  86. if(!authenticated)
  87. returnValue = SOAP_AUTHENTICATION_ERROR;
  88. break;
  89. }
  90. }
  91. }
  92. }
  93. if (returnValue == 0)
  94. {
  95. if (authenticated)
  96. {
  97. if (ctx->toBeAuthenticated())
  98. ctx->setAuthStatus(AUTH_STATUS_OK); //May be changed to AUTH_STATUS_NOACCESS if failed in feature level authorization.
  99. return 0;
  100. }
  101. returnValue = SOAP_AUTHENTICATION_REQUIRED;
  102. }
  103. StringBuffer peerStr;
  104. ctx->getPeer(peerStr);
  105. const char* userId = ctx->queryUserId();
  106. VStringBuffer msg("SOAP request from %s@%s.", (userId&&*userId)?userId:"unknown", (peerStr.length()>0)?peerStr.str():"unknown");
  107. if (returnValue == SOAP_AUTHENTICATION_ERROR)
  108. msg.append(" User authentication failed");
  109. else
  110. msg.append(" User authentication required");
  111. ctx->setAuthStatus(AUTH_STATUS_FAIL);
  112. DBGLOG("%s", msg.str());
  113. return returnValue;
  114. }
  115. int CSoapService::processRequest(ISoapMessage &req, ISoapMessage& resp)
  116. {
  117. CSoapRequest& request = *(dynamic_cast<CSoapRequest*>(&req));
  118. CSoapResponse& response = *(dynamic_cast<CSoapResponse*>(&resp));
  119. IEspContext* ctx = req.queryContext();
  120. StringBuffer requeststr;
  121. Owned<CMimeMultiPart> multipart;
  122. if(Utils::strncasecmp(request.get_content_type(), HTTP_TYPE_SOAP, strlen(HTTP_TYPE_SOAP))==0 || Utils::strncasecmp(request.get_content_type(), HTTP_TYPE_TEXT_XML, strlen(HTTP_TYPE_TEXT_XML))==0)
  123. {
  124. requeststr.append(request.get_text());
  125. }
  126. else if (Utils::strncasecmp(request.get_content_type(), HTTP_TYPE_JSON, strlen(HTTP_TYPE_JSON))==0)
  127. {
  128. requeststr.append(request.get_text());
  129. }
  130. else if(!Utils::strncasecmp(request.get_content_type(), HTTP_TYPE_MULTIPART_RELATED, strlen(HTTP_TYPE_MULTIPART_RELATED)))
  131. {
  132. multipart.setown(LINK(request.queryMultiPart()));
  133. CMimeBodyPart* rootpart = multipart->queryRootPart();
  134. if(rootpart != NULL)
  135. rootpart->getContent(requeststr);
  136. else
  137. throw MakeStringException(-1, "MultiPart root is NULL");
  138. }
  139. else
  140. {
  141. throw MakeStringException(-1, "Request type %s not supported", request.get_content_type());
  142. }
  143. OwnedPtr<XJXPullParser> xpp;
  144. int bufSize = requeststr.length();
  145. //Parse the content
  146. if (ctx && ctx->getResponseFormat()==ESPSerializationJSON)
  147. xpp.setown(new CJsonPullParser(true));
  148. else
  149. {
  150. XmlPullParser* ptr = nullptr;
  151. xpp.setown((ptr = new XmlPullParser()));
  152. ptr->setSupportNamespaces(true);
  153. }
  154. xpp->setInput(requeststr.str(), bufSize);
  155. int type;
  156. StartTag stag;
  157. EndTag etag;
  158. StringBuffer peerStr;
  159. ctx->getPeer(peerStr);
  160. const char* userId = ctx->queryUserId();
  161. Owned<CRpcResponse> rpc_response;
  162. rpc_response.setown(new CRpcResponse);
  163. rpc_response->setContext(req.queryContext());
  164. rpc_response->setHttpResp(response.getHttpResp());
  165. Owned<CRpcCall>rpc_call;
  166. rpc_call.setown(new CRpcCall);
  167. rpc_call->setContext(req.queryContext());
  168. rpc_call->setHttpReq(request.getHttpReq());
  169. if (ctx && ctx->getResponseFormat()==ESPSerializationJSON)
  170. {
  171. rpc_call->preunmarshall(xpp.get());
  172. rpc_call->unmarshall(xpp.get(), multipart.get());
  173. DBGLOG("JSON method <%s> from %s@%s.", rpc_call->get_name(), (userId&&*userId)?userId:"unknown",
  174. (peerStr.length()>0)?peerStr.str():"unknown");
  175. ctx->setHTTPMethod("JSON");
  176. }
  177. else
  178. {
  179. Owned<CEnvelope> req_envelope;
  180. req_envelope.setown(new CEnvelope);
  181. while ((type = xpp->next()) != XmlPullParser::END_DOCUMENT)
  182. {
  183. if (type == XmlPullParser::START_TAG) {
  184. xpp->readStartTag(stag);
  185. if (!stricmp(stag.getLocalName(), SOAP_ENVELOPE_NAME))
  186. {
  187. req_envelope->unmarshall(xpp.get());
  188. break;
  189. }
  190. }
  191. }
  192. CHeader* req_header = req_envelope->get_header();
  193. if (req_header != NULL)
  194. {
  195. // As headers are normally for common uses like authentication and routing, let's process it here
  196. // instead of in binding.
  197. int ret = processHeader(req_header, ctx);
  198. if (ret != 0 )
  199. {
  200. response.set_status(ret);
  201. return 0;
  202. }
  203. }
  204. CBody* req_body = req_envelope->get_body();
  205. try {
  206. req_body->nextRpcMessage(rpc_call.get());
  207. rpc_call->unmarshall(xpp.get(), multipart.get());
  208. } catch (XmlPullParserException& e) {
  209. response.set_status(SOAP_CLIENT_ERROR);
  210. response.set_err(e.getMessage().c_str());
  211. DBGLOG("SOAP request from %s@%s. Parsing xml error: %s. Offending XML: [%s]", (userId&&*userId)?userId:"unknown",
  212. (peerStr.length()>0)?peerStr.str():"unknown", e.getMessage().c_str(), requeststr.str());
  213. return 0;
  214. } catch (...) {
  215. response.set_status(SOAP_CLIENT_ERROR);
  216. response.set_err("Unknown error when parsing soap body XML");
  217. ERRLOG("SOAP request from %s@%s. Unknown error when parsing: %s", (userId&&*userId)?userId:"unknown",
  218. (peerStr.length()>0)?peerStr.str():"unknown", requeststr.str());
  219. return 0;
  220. }
  221. DBGLOG("SOAP method <%s> from %s@%s.", rpc_call->get_name(), (userId&&*userId)?userId:"unknown",
  222. (peerStr.length()>0)?peerStr.str():"unknown");
  223. ctx->setHTTPMethod("SOAP");
  224. }
  225. ctx->setServiceMethod(rpc_call->get_name());
  226. // call the rpc and set the response
  227. if(m_soapbinding != NULL)
  228. m_soapbinding->processRequest(rpc_call, rpc_response);
  229. if (!response.getHttpResp() || !response.getHttpResp()->getRespSent())
  230. {
  231. response.set_status(rpc_response->get_status());
  232. response.set_err(rpc_response->get_err());
  233. //JSON content would've been sent, except certain errors, which don't need the following
  234. if (!(ctx && ctx->getResponseFormat()==ESPSerializationJSON))
  235. {
  236. Owned<CBody> res_body = new CBody;
  237. res_body->add_rpcmessage(rpc_response.get());
  238. Owned<CEnvelope> res_envelope;
  239. res_envelope.setown(new CEnvelope(NULL, res_body.getLink()));
  240. Owned<CMimeMultiPart> resp_multipart;
  241. resp_multipart.setown(new CMimeMultiPart("1.0", "", "MIME_boundary", "text/xml", "soaproot"));
  242. res_envelope->marshall(resp_multipart);
  243. StringBuffer contenttype;
  244. StringBuffer responsestr;
  245. resp_multipart->serialize(contenttype, responsestr);
  246. response.set_content_type(contenttype.str());
  247. response.set_text(responsestr.str());
  248. }
  249. }
  250. return 0;
  251. }