1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.ws.soap.security;
18
19 import java.util.Iterator;
20 import java.util.Locale;
21 import javax.xml.namespace.QName;
22
23 import org.springframework.util.Assert;
24 import org.springframework.ws.client.WebServiceClientException;
25 import org.springframework.ws.client.support.interceptor.ClientInterceptor;
26 import org.springframework.ws.context.MessageContext;
27 import org.springframework.ws.server.EndpointExceptionResolver;
28 import org.springframework.ws.soap.SoapBody;
29 import org.springframework.ws.soap.SoapFault;
30 import org.springframework.ws.soap.SoapHeader;
31 import org.springframework.ws.soap.SoapHeaderElement;
32 import org.springframework.ws.soap.SoapMessage;
33 import org.springframework.ws.soap.server.SoapEndpointInterceptor;
34 import org.springframework.ws.soap.soap11.Soap11Body;
35
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38
39
40
41
42
43
44
45
46
47
48
49
50
51 public abstract class AbstractWsSecurityInterceptor implements SoapEndpointInterceptor, ClientInterceptor {
52
53
54 protected final Log logger = LogFactory.getLog(getClass());
55
56 protected static final QName WS_SECURITY_NAME =
57 new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security");
58
59 private boolean secureResponse = true;
60
61 private boolean validateRequest = true;
62
63 private boolean secureRequest = true;
64
65 private boolean validateResponse = true;
66
67 private boolean skipValidationIfNoHeaderPresent = false;
68
69 private EndpointExceptionResolver exceptionResolver;
70
71
72 public void setValidateRequest(boolean validateRequest) {
73 this.validateRequest = validateRequest;
74 }
75
76
77 public void setSecureResponse(boolean secureResponse) {
78 this.secureResponse = secureResponse;
79 }
80
81
82 public void setSecureRequest(boolean secureRequest) {
83 this.secureRequest = secureRequest;
84 }
85
86
87 public void setValidateResponse(boolean validateResponse) {
88 this.validateResponse = validateResponse;
89 }
90
91
92 public void setExceptionResolver(EndpointExceptionResolver exceptionResolver) {
93 this.exceptionResolver = exceptionResolver;
94 }
95
96
97 public void setSkipValidationIfNoHeaderPresent(
98 boolean skipValidationIfNoHeaderPresent) {
99 this.skipValidationIfNoHeaderPresent = skipValidationIfNoHeaderPresent;
100 }
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 public final boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
117 if (validateRequest) {
118 Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest());
119 if(skipValidationIfNoHeaderPresent && !isSecurityHeaderPresent((SoapMessage) messageContext.getRequest())){
120 return true;
121 }
122 try {
123 validateMessage((SoapMessage) messageContext.getRequest(), messageContext);
124 return true;
125 }
126 catch (WsSecurityValidationException ex) {
127 return handleValidationException(ex, messageContext);
128 }
129 catch (WsSecurityFaultException ex) {
130 return handleFaultException(ex, messageContext);
131 }
132 }
133 else {
134 return true;
135 }
136 }
137
138
139
140
141
142
143
144
145
146
147
148 public final boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
149 boolean result = true;
150 try {
151 if (secureResponse) {
152 Assert.isTrue(messageContext.hasResponse(), "MessageContext contains no response");
153 Assert.isInstanceOf(SoapMessage.class, messageContext.getResponse());
154 try {
155 secureMessage((SoapMessage) messageContext.getResponse(), messageContext);
156 }
157 catch (WsSecuritySecurementException ex) {
158 result = handleSecurementException(ex, messageContext);
159 }
160 catch (WsSecurityFaultException ex) {
161 result = handleFaultException(ex, messageContext);
162 }
163 }
164 }
165 finally {
166 if (!result) {
167 messageContext.clearResponse();
168 }
169 }
170 return result;
171 }
172
173
174 public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
175 return true;
176 }
177
178 public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) {
179 cleanUp();
180 }
181
182 public boolean understands(SoapHeaderElement headerElement) {
183 return WS_SECURITY_NAME.equals(headerElement.getName());
184 }
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199 public final boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
200 if (secureRequest) {
201 Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest());
202 try {
203 secureMessage((SoapMessage) messageContext.getRequest(), messageContext);
204 return true;
205 }
206 catch (WsSecuritySecurementException ex) {
207 return handleSecurementException(ex, messageContext);
208 }
209 catch (WsSecurityFaultException ex) {
210 return handleFaultException(ex, messageContext);
211 }
212 }
213 else {
214 return true;
215 }
216 }
217
218
219
220
221
222
223
224
225
226
227 public final boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
228 if (validateResponse) {
229 Assert.isTrue(messageContext.hasResponse(), "MessageContext contains no response");
230 Assert.isInstanceOf(SoapMessage.class, messageContext.getResponse());
231 if(skipValidationIfNoHeaderPresent && !isSecurityHeaderPresent((SoapMessage) messageContext.getRequest())){
232 return true;
233 }
234 try {
235 validateMessage((SoapMessage) messageContext.getResponse(), messageContext);
236 return true;
237 }
238 catch (WsSecurityValidationException ex) {
239 return handleValidationException(ex, messageContext);
240 }
241 catch (WsSecurityFaultException ex) {
242 return handleFaultException(ex, messageContext);
243 }
244 }
245 else {
246 return true;
247 }
248 }
249
250
251 public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
252 return true;
253 }
254
255
256
257
258
259
260
261
262
263 protected boolean handleSecurementException(WsSecuritySecurementException ex, MessageContext messageContext) {
264 if (logger.isErrorEnabled()) {
265 logger.error("Could not secure response: " + ex.getMessage(), ex);
266 }
267 return false;
268 }
269
270
271
272
273
274
275
276
277
278
279 protected boolean handleValidationException(WsSecurityValidationException ex, MessageContext messageContext) {
280 if (logger.isWarnEnabled()) {
281 logger.warn("Could not validate request: " + ex.getMessage());
282 }
283 if (exceptionResolver != null) {
284 exceptionResolver.resolveException(messageContext, null, ex);
285 }
286 else {
287 if (logger.isDebugEnabled()) {
288 logger.debug("No exception resolver present, creating basic soap fault");
289 }
290 SoapBody response = ((SoapMessage) messageContext.getResponse()).getSoapBody();
291 response.addClientOrSenderFault(ex.getMessage(), Locale.ENGLISH);
292 }
293 return false;
294 }
295
296
297
298
299
300
301
302
303
304 protected boolean handleFaultException(WsSecurityFaultException ex, MessageContext messageContext) {
305 if (logger.isWarnEnabled()) {
306 logger.warn("Could not handle request: " + ex.getMessage());
307 }
308 SoapBody response = ((SoapMessage) messageContext.getResponse()).getSoapBody();
309 SoapFault fault;
310 if (response instanceof Soap11Body) {
311 fault = ((Soap11Body) response).addFault(ex.getFaultCode(), ex.getFaultString(), Locale.ENGLISH);
312 }
313 else {
314 fault = response.addClientOrSenderFault(ex.getFaultString(), Locale.ENGLISH);
315 }
316 fault.setFaultActorOrRole(ex.getFaultActor());
317 return false;
318 }
319
320
321
322
323
324
325
326
327 protected abstract void validateMessage(SoapMessage soapMessage, MessageContext messageContext)
328 throws WsSecurityValidationException;
329
330
331
332
333
334
335
336
337 protected abstract void secureMessage(SoapMessage soapMessage, MessageContext messageContext)
338 throws WsSecuritySecurementException;
339
340 protected abstract void cleanUp();
341
342
343
344
345 private boolean isSecurityHeaderPresent(SoapMessage message) {
346 SoapHeader soapHeader = message.getSoapHeader();
347 if(soapHeader == null){
348 return false;
349 }
350 Iterator<SoapHeaderElement> elements = soapHeader.examineAllHeaderElements();
351 while(elements.hasNext()){
352 SoapHeaderElement e = elements.next();
353 if(e.getName().equals(WS_SECURITY_NAME)){
354 return true;
355 }
356 }
357 return false;
358 }
359 }