1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 /*
21  * XSEC
22  *
23  * XSECSOAPRequestorSimple := (Very) Basic implementation of a SOAP
24  *                         HTTP wrapper for testing the client code.
25  *
26  *
27  * $Id: XSECSOAPRequestorSimple.cpp 1833341 2018-06-11 16:25:41Z scantor $
28  *
29  */
30 
31 #include <xsec/framework/XSECError.hpp>
32 #include <xsec/utils/XSECSafeBuffer.hpp>
33 #include <xsec/utils/XSECSOAPRequestorSimple.hpp>
34 #include <xsec/xkms/XKMSConstants.hpp>
35 
36 #ifdef XSEC_XKMS_ENABLED
37 
38 #include "XSECAutoPtr.hpp"
39 #include "XSECDOMUtils.hpp"
40 
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdlib.h>
44 
45 #include <xercesc/dom/DOM.hpp>
46 #include <xercesc/parsers/XercesDOMParser.hpp>
47 #include <xercesc/framework/XMLFormatter.hpp>
48 #include <xercesc/framework/MemBufFormatTarget.hpp>
49 #include <xercesc/util/PlatformUtils.hpp>
50 #include <xercesc/util/XMLNetAccessor.hpp>
51 #include <xercesc/util/XMLString.hpp>
52 #include <xercesc/util/XMLExceptMsgs.hpp>
53 #include <xercesc/util/Janitor.hpp>
54 #include <xercesc/util/XMLUniDefs.hpp>
55 #include <xercesc/framework/MemBufInputSource.hpp>
56 
57 XERCES_CPP_NAMESPACE_USE
58 
59 // --------------------------------------------------------------------------------
60 //           Strings for constructing SOAP envelopes
61 // --------------------------------------------------------------------------------
62 
63 static XMLCh s_prefix[] = {
64 
65 	chLatin_e,
66 	chLatin_n,
67 	chLatin_v,
68 	chNull
69 };
70 
71 static XMLCh s_Envelope[] = {
72 
73 	chLatin_E,
74 	chLatin_n,
75 	chLatin_v,
76 	chLatin_e,
77 	chLatin_l,
78 	chLatin_o,
79 	chLatin_p,
80 	chLatin_e,
81 	chNull
82 };
83 
84 static XMLCh s_Body[] = {
85 
86 	chLatin_B,
87 	chLatin_o,
88 	chLatin_d,
89 	chLatin_y,
90 	chNull
91 };
92 
93 // --------------------------------------------------------------------------------
94 //           Constructors and Destructors
95 // --------------------------------------------------------------------------------
96 
97 
98 /* NOTE: This is initialised via the platform specific code */
99 
~XSECSOAPRequestorSimple()100 XSECSOAPRequestorSimple::~XSECSOAPRequestorSimple() {
101 }
102 
103 
104 // --------------------------------------------------------------------------------
105 //           Wrap and serialise the request message
106 // --------------------------------------------------------------------------------
107 
wrapAndSerialise(DOMDocument * request)108 char * XSECSOAPRequestorSimple::wrapAndSerialise(DOMDocument * request) {
109 
110 	// Prepare the serialiser
111 
112 	XMLCh tempStr[100];
113 	XMLString::transcode("Core", tempStr, 99);
114 	DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
115 	DOMLSSerializer   *theSerializer = ((DOMImplementationLS*)impl)->createLSSerializer();
116 	Janitor<DOMLSSerializer> j_theSerializer(theSerializer);
117 
118 	// Get the config so we can set up pretty printing
119 	DOMConfiguration *dc = theSerializer->getDomConfig();
120 	dc->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, false);
121 
122 	// Now create an output object to format to UTF-8
123 	DOMLSOutput *theOutput = ((DOMImplementationLS*)impl)->createLSOutput();
124 	Janitor<DOMLSOutput> j_theOutput(theOutput);
125 	MemBufFormatTarget *formatTarget = new MemBufFormatTarget;
126 	Janitor<MemBufFormatTarget> j_formatTarget(formatTarget);
127 
128 	theOutput->setEncoding(MAKE_UNICODE_STRING("UTF-8"));
129 	theOutput->setByteStream(formatTarget);
130 
131 	if (m_envelopeType != ENVELOPE_NONE) {
132 
133 		// Create a new document to wrap the request in
134 		safeBuffer str;
135 
136 		makeQName(str, s_prefix, s_Envelope);
137 
138 		DOMDocument *doc;
139 
140 		if (m_envelopeType == ENVELOPE_SOAP11) {
141 			doc = impl->createDocument(
142 				XKMSConstants::s_unicodeStrURISOAP11,
143 						str.rawXMLChBuffer(),
144 						NULL);
145 			DOMElement *rootElem = doc->getDocumentElement();
146 
147 			makeQName(str, s_prefix, s_Body);
148 			DOMElement *body = doc->createElementNS(
149 					XKMSConstants::s_unicodeStrURISOAP11,
150 					str.rawXMLChBuffer());
151 
152 			rootElem->appendChild(body);
153 
154 			// Now replicate the request into the document
155 			DOMElement * reqElement = (DOMElement *) doc->importNode(request->getDocumentElement(), true);
156 			body->appendChild(reqElement);
157 		}
158 		else {
159 			doc = impl->createDocument(
160 				XKMSConstants::s_unicodeStrURISOAP12,
161 						str.rawXMLChBuffer(),
162 						NULL);
163 			DOMElement *rootElem = doc->getDocumentElement();
164 
165 			makeQName(str, s_prefix, s_Body);
166 			DOMElement *body = doc->createElementNS(
167 					XKMSConstants::s_unicodeStrURISOAP12,
168 					str.rawXMLChBuffer());
169 
170 			rootElem->appendChild(body);
171 
172 			// Now replicate the request into the document
173 			DOMElement * reqElement = (DOMElement *) doc->importNode(request->getDocumentElement(), true);
174 			body->appendChild(reqElement);
175 		}
176 
177 
178 		// OK - Now we have the SOAP request as a document, we serialise to a string buffer
179 		// and return
180 
181 		theSerializer->write(doc, theOutput);
182 		doc->release();
183 
184 	}
185 	else {
186 		theSerializer->write(request, theOutput);
187 	}
188 
189 	// Now replicate the buffer
190 	return XMLString::replicate((const char *) formatTarget->getRawBuffer());
191 
192 }
193 
194 // --------------------------------------------------------------------------------
195 //           UnWrap and de-serialise the response message
196 // --------------------------------------------------------------------------------
197 
parseAndUnwrap(const char * buf,unsigned int len)198 DOMDocument * XSECSOAPRequestorSimple::parseAndUnwrap(const char * buf, unsigned int len) {
199 
200 	XercesDOMParser parser;
201 	parser.setDoNamespaces(true);
202 	parser.setLoadExternalDTD(false);
203 
204 	SecurityManager securityManager;
205 	securityManager.setEntityExpansionLimit(XSEC_ENTITY_EXPANSION_LIMIT);
206 	parser.setSecurityManager(&securityManager);
207 
208 	// Create an input source
209 
210 	MemBufInputSource memIS((const XMLByte*) buf, len, "XSECMem");
211 
212 	parser.parse(memIS);
213 	XMLSize_t errorCount = parser.getErrorCount();
214     if (errorCount > 0)
215 		throw XSECException(XSECException::HTTPURIInputStreamError,
216 							"Error parsing response message");
217 
218 	if (m_envelopeType == ENVELOPE_NONE) {
219 
220 		return parser.adoptDocument();
221 
222 	}
223 
224 	DOMDocument * responseDoc = parser.getDocument();
225 
226 	// Must be a SOAP message of some kind - so lets remove the wrapper.
227 	// First create a new document for the Response message
228 
229 	XMLCh tempStr[100];
230 	XMLString::transcode("Core", tempStr, 99);
231 	DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
232 
233 	DOMDocument * retDoc = impl->createDocument();
234 
235 	// Find the base of the response
236 
237 
238 	DOMNode * e = responseDoc->getDocumentElement();
239 
240 	e = e->getFirstChild();
241 
242 	while (e != NULL && (e->getNodeType() != DOMNode::ELEMENT_NODE || !strEquals(e->getLocalName(), "Body")))
243 		e = e->getNextSibling();
244 
245 	if (e == NULL)
246 		throw XSECException(XSECException::HTTPURIInputStreamError,
247 							"Could not find SOAP body");
248 
249 	e = findFirstChildOfType(e, DOMNode::ELEMENT_NODE);
250 
251 	if (e == NULL)
252 		throw XSECException(XSECException::HTTPURIInputStreamError,
253 							"Could not find message within SOAP body");
254 
255 	/* See if this is a soap fault */
256 	if (strEquals(e->getLocalName(), "Fault")) {
257 
258 		// Something has gone wrong somewhere!
259 		safeBuffer sb;
260 		sb.sbTranscodeIn("SOAP Fault : ");
261 
262 		// Find the fault code
263 
264 		e = findFirstElementChild(e);
265 		while (e != NULL && !strEquals(e->getLocalName(), "Code"))
266 			e = findNextElementChild(e);
267 
268 		if (e != NULL) {
269 			DOMNode * c = findFirstElementChild(e);
270 			while (c != NULL && !strEquals(c->getLocalName(), "Value"))
271 				c = findNextElementChild(c);
272 			if (c != NULL) {
273 				DOMNode * t = findFirstChildOfType(c, DOMNode::TEXT_NODE);
274 				if (t != NULL) {
275 					sb.sbXMLChCat(t->getNodeValue());
276 					sb.sbXMLChCat(" : ");
277 				}
278 			}
279 		}
280 
281 		// Find the reason
282 		while (e != NULL && !strEquals(e->getLocalName(), "Reason"))
283 			e = findNextElementChild(e);
284 
285 		if (e != NULL) {
286 			DOMNode * t = findFirstChildOfType(e, DOMNode::TEXT_NODE);
287 			if (t != NULL) {
288 				sb.sbXMLChCat(t->getNodeValue());
289 			}
290 
291 		}
292 
293 		retDoc->release();
294 
295 		XSECAutoPtrChar msg(sb.rawXMLChBuffer());
296 
297 		throw XSECException(XSECException::HTTPURIInputStreamError,
298 							msg.get());
299 	}
300 
301 
302 	retDoc->appendChild(retDoc->importNode(e, true));
303 
304 	return retDoc;
305 
306 }
307 
308 // --------------------------------------------------------------------------------
309 //           Envelope Type handling
310 // --------------------------------------------------------------------------------
311 
setEnvelopeType(envelopeType et)312 void XSECSOAPRequestorSimple::setEnvelopeType(envelopeType et) {
313 
314 	m_envelopeType = et;
315 
316 }
317 
318 #endif /* XSEC_XKMS_ENABLED */
319