1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.ws.soap.client.http;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStreamWriter;
23 import java.nio.charset.Charset;
24 import java.util.List;
25
26 import net.jcip.annotations.ThreadSafe;
27
28 import org.apache.commons.httpclient.HttpClient;
29 import org.apache.commons.httpclient.HttpStatus;
30 import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
31 import org.apache.commons.httpclient.methods.PostMethod;
32 import org.apache.commons.httpclient.methods.RequestEntity;
33 import org.opensaml.ws.security.SecurityPolicy;
34 import org.opensaml.ws.security.SecurityPolicyResolver;
35 import org.opensaml.ws.soap.client.SOAPClient;
36 import org.opensaml.ws.soap.client.SOAPClientException;
37 import org.opensaml.ws.soap.client.SOAPFaultException;
38 import org.opensaml.ws.soap.client.SOAPMessageContext;
39 import org.opensaml.ws.soap.common.SOAPException;
40 import org.opensaml.ws.soap.soap11.Envelope;
41 import org.opensaml.ws.soap.soap11.Fault;
42 import org.opensaml.xml.Configuration;
43 import org.opensaml.xml.XMLObject;
44 import org.opensaml.xml.io.Marshaller;
45 import org.opensaml.xml.io.MarshallingException;
46 import org.opensaml.xml.io.Unmarshaller;
47 import org.opensaml.xml.io.UnmarshallingException;
48 import org.opensaml.xml.parse.ParserPool;
49 import org.opensaml.xml.parse.XMLParserException;
50 import org.opensaml.xml.security.SecurityException;
51 import org.opensaml.xml.util.XMLHelper;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54 import org.w3c.dom.Element;
55
56
57
58
59
60
61
62
63 @ThreadSafe
64 public class HttpSOAPClient implements SOAPClient {
65
66
67 private final Logger log = LoggerFactory.getLogger(HttpSOAPClient.class);
68
69
70 private HttpClient httpClient;
71
72
73 private ParserPool parserPool;
74
75
76
77
78
79
80
81
82
83 public HttpSOAPClient(HttpClient client, ParserPool parser) {
84 if (client == null) {
85 throw new IllegalArgumentException("HtppClient may not be null");
86 }
87 httpClient = client;
88
89 if (parser == null) {
90 throw new IllegalArgumentException("ParserPool may not be null");
91 }
92 parserPool = parser;
93 }
94
95
96 public void send(String endpoint, SOAPMessageContext messageContext) throws SOAPException, SecurityException {
97 PostMethod post = null;
98 try {
99 post = createPostMethod(endpoint, (HttpSOAPRequestParameters) messageContext.getSOAPRequestParameters(),
100 (Envelope) messageContext.getOutboundMessage());
101
102 int result = httpClient.executeMethod(post);
103 log.debug("Received HTTP status code of {} when POSTing SOAP message to {}", result, endpoint);
104
105 if (result == HttpStatus.SC_OK) {
106 processSuccessfulResponse(post, messageContext);
107 } else if (result == HttpStatus.SC_INTERNAL_SERVER_ERROR) {
108 processFaultResponse(post, messageContext);
109 } else {
110 throw new SOAPClientException("Received " + result + " HTTP response status code from HTTP request to "
111 + endpoint);
112 }
113 } catch (IOException e) {
114 throw new SOAPClientException("Unable to send request to " + endpoint, e);
115 } finally {
116 if (post != null) {
117 post.releaseConnection();
118 }
119 }
120 }
121
122
123
124
125
126
127
128
129
130
131
132
133 protected PostMethod createPostMethod(String endpoint, HttpSOAPRequestParameters requestParams, Envelope message)
134 throws SOAPClientException {
135 log.debug("POSTing SOAP message to {}", endpoint);
136
137 PostMethod post = new PostMethod(endpoint);
138 post.setRequestEntity(createRequestEntity(message, Charset.forName("UTF-8")));
139 if (requestParams != null && requestParams.getSoapAction() != null) {
140 post.setRequestHeader(HttpSOAPRequestParameters.SOAP_ACTION_HEADER, requestParams.getSoapAction());
141 }
142
143 return post;
144 }
145
146
147
148
149
150
151
152
153
154
155
156 protected RequestEntity createRequestEntity(Envelope message, Charset charset) throws SOAPClientException {
157 try {
158 Marshaller marshaller = Configuration.getMarshallerFactory().getMarshaller(message);
159 ByteArrayOutputStream arrayOut = new ByteArrayOutputStream();
160 OutputStreamWriter writer = new OutputStreamWriter(arrayOut, charset);
161
162 if (log.isDebugEnabled()) {
163 log.debug("Outbound SOAP message is:\n" + XMLHelper.prettyPrintXML(marshaller.marshall(message)));
164 }
165 XMLHelper.writeNode(marshaller.marshall(message), writer);
166 return new ByteArrayRequestEntity(arrayOut.toByteArray(), "text/xml");
167 } catch (MarshallingException e) {
168 throw new SOAPClientException("Unable to marshall SOAP envelope", e);
169 }
170 }
171
172
173
174
175
176
177
178
179
180 protected void processSuccessfulResponse(PostMethod httpMethod, SOAPMessageContext messageContext)
181 throws SOAPClientException {
182 try {
183 Envelope response = unmarshallResponse(httpMethod.getResponseBodyAsStream());
184 messageContext.setInboundMessage(response);
185 evaluateSecurityPolicy(messageContext);
186 } catch (IOException e) {
187 throw new SOAPClientException("Unable to read response", e);
188 }
189 }
190
191
192
193
194
195
196
197
198
199
200 protected void processFaultResponse(PostMethod httpMethod, SOAPMessageContext messageContext)
201 throws SOAPClientException, SOAPFaultException {
202 try {
203 Envelope response = unmarshallResponse(httpMethod.getResponseBodyAsStream());
204 messageContext.setInboundMessage(response);
205
206 List<XMLObject> faults = response.getBody().getUnknownXMLObjects(Fault.DEFAULT_ELEMENT_NAME);
207 if (faults.size() < 1) {
208 throw new SOAPClientException("HTTP status code was 500 but SOAP response did not contain a Fault");
209 }
210 Fault fault = (Fault) faults.get(0);
211
212 log.debug("SOAP fault code {} with message {}", fault.getCode().getValue(), fault.getMessage().getValue());
213 SOAPFaultException faultException = new SOAPFaultException("SOAP Fault: " + fault.getCode().getValue()
214 + " Fault Message: " + fault.getMessage().getValue());
215 faultException.setFault(fault);
216 throw faultException;
217 } catch (IOException e) {
218 throw new SOAPClientException("Unable to read response", e);
219 }
220 }
221
222
223
224
225
226
227
228
229
230
231 protected Envelope unmarshallResponse(InputStream responseStream) throws SOAPClientException {
232 try {
233 Element responseElem = parserPool.parse(responseStream).getDocumentElement();
234 if (log.isDebugEnabled()) {
235 log.debug("Inbound SOAP message was:\n" + XMLHelper.prettyPrintXML(responseElem));
236 }
237 Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(responseElem);
238 return (Envelope) unmarshaller.unmarshall(responseElem);
239 } catch (XMLParserException e) {
240 throw new SOAPClientException("Unable to parse the XML within the response", e);
241 } catch (UnmarshallingException e) {
242 throw new SOAPClientException("unable to unmarshall the response DOM", e);
243 }
244 }
245
246
247
248
249
250
251
252
253
254
255 protected void evaluateSecurityPolicy(SOAPMessageContext messageContext) throws SOAPClientException {
256 SecurityPolicyResolver policyResolver = messageContext.getSecurityPolicyResolver();
257 if (policyResolver == null) {
258 return;
259 }
260
261 SecurityPolicy policy = null;
262 try {
263 policy = policyResolver.resolveSingle(messageContext);
264 if (policy == null) {
265 return;
266 }
267 } catch (SecurityException e) {
268 throw new SOAPClientException("Unable to resolve security policy for inbound SOAP response", e);
269 }
270
271 try {
272 log.debug("Evaluating security policy for inbound SOAP response");
273 policy.evaluate(messageContext);
274 } catch (SecurityException e) {
275 throw new SOAPClientException("Inbound SOAP response does not meet security policy", e);
276 }
277 }
278 }