1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.ws.soap.security.xwss;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.util.Arrays;
22 import java.util.Hashtable;
23 import javax.security.auth.callback.Callback;
24 import javax.security.auth.callback.CallbackHandler;
25 import javax.security.auth.callback.UnsupportedCallbackException;
26 import javax.xml.soap.SOAPMessage;
27
28 import com.sun.xml.wss.ProcessingContext;
29 import com.sun.xml.wss.XWSSProcessor;
30 import com.sun.xml.wss.XWSSProcessorFactory;
31 import com.sun.xml.wss.XWSSecurityException;
32 import com.sun.xml.wss.impl.WssSoapFaultException;
33
34 import org.springframework.beans.factory.InitializingBean;
35 import org.springframework.core.io.Resource;
36 import org.springframework.util.Assert;
37 import org.springframework.ws.context.MessageContext;
38 import org.springframework.ws.soap.SoapMessage;
39 import org.springframework.ws.soap.saaj.SaajSoapMessage;
40 import org.springframework.ws.soap.security.AbstractWsSecurityInterceptor;
41 import org.springframework.ws.soap.security.WsSecurityValidationException;
42 import org.springframework.ws.soap.security.callback.CleanupCallback;
43 import org.springframework.ws.soap.security.xwss.callback.XwssCallbackHandlerChain;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 public class XwsSecurityInterceptor extends AbstractWsSecurityInterceptor implements InitializingBean {
69
70 private XWSSProcessor processor;
71
72 private CallbackHandler callbackHandler;
73
74 private Resource policyConfiguration;
75
76
77
78
79
80
81
82
83 public void setCallbackHandler(CallbackHandler callbackHandler) {
84 this.callbackHandler = callbackHandler;
85 }
86
87
88
89
90
91
92
93
94 public void setCallbackHandlers(CallbackHandler[] callbackHandler) {
95 this.callbackHandler = new XwssCallbackHandlerChain(callbackHandler);
96 }
97
98
99 public void setPolicyConfiguration(Resource policyConfiguration) {
100 this.policyConfiguration = policyConfiguration;
101 }
102
103 public void afterPropertiesSet() throws Exception {
104 Assert.notNull(policyConfiguration, "policyConfiguration is required");
105 Assert.isTrue(policyConfiguration.exists(), "policyConfiguration [" + policyConfiguration + "] does not exist");
106 Assert.notNull(callbackHandler, "callbackHandler is required");
107 XWSSProcessorFactory processorFactory = XWSSProcessorFactory.newInstance();
108 InputStream is = null;
109 try {
110 if (logger.isInfoEnabled()) {
111 logger.info("Loading policy configuration from from '" + policyConfiguration + "'");
112 }
113 is = policyConfiguration.getInputStream();
114 processor = processorFactory.createProcessorForSecurityConfiguration(is, callbackHandler);
115 }
116 finally {
117 if (is != null) {
118 is.close();
119 }
120 }
121 }
122
123
124
125
126
127
128
129
130 @Override
131 protected void secureMessage(SoapMessage soapMessage, MessageContext messageContext)
132 throws XwsSecuritySecurementException {
133 Assert.isTrue(soapMessage instanceof SaajSoapMessage, "XwsSecurityInterceptor requires a SaajSoapMessage. " +
134 "Use a SaajSoapMessageFactory to create the SOAP messages.");
135 SaajSoapMessage saajSoapMessage = (SaajSoapMessage) soapMessage;
136 try {
137 ProcessingContext context = processor.createProcessingContext(saajSoapMessage.getSaajMessage());
138 SOAPMessage result = processor.secureOutboundMessage(context);
139 saajSoapMessage.setSaajMessage(result);
140 }
141 catch (XWSSecurityException ex) {
142 throw new XwsSecuritySecurementException(ex.getMessage(), ex);
143 }
144 catch (WssSoapFaultException ex) {
145 throw new XwsSecurityFaultException(ex.getFaultCode(), ex.getFaultString(), ex.getFaultActor());
146 }
147 }
148
149
150
151
152
153
154
155
156 @Override
157 protected void validateMessage(SoapMessage soapMessage, MessageContext messageContext)
158 throws WsSecurityValidationException {
159 Assert.isTrue(soapMessage instanceof SaajSoapMessage, "XwsSecurityInterceptor requires a SaajSoapMessage. " +
160 "Use a SaajSoapMessageFactory to create the SOAP messages.");
161 SaajSoapMessage saajSoapMessage = (SaajSoapMessage) soapMessage;
162 try {
163 ProcessingContext context = processor.createProcessingContext(saajSoapMessage.getSaajMessage());
164 SOAPMessage result = processor.verifyInboundMessage(context);
165 saajSoapMessage.setSaajMessage(result);
166 }
167 catch (XWSSecurityException ex) {
168 throw new XwsSecurityValidationException(ex.getMessage(), ex);
169 }
170 catch (WssSoapFaultException ex) {
171 throw new XwsSecurityFaultException(ex.getFaultCode(), ex.getFaultString(), ex.getFaultActor());
172 }
173 }
174
175 private SOAPMessage verifyInboundMessage(ProcessingContext context)
176 throws XWSSecurityException {
177 try {
178 return processor.verifyInboundMessage(context);
179 }
180 catch (XWSSecurityException ex) {
181 Throwable cause = ex.getCause();
182 if (cause instanceof NullPointerException) {
183 StackTraceElement[] stackTrace = cause.getStackTrace();
184 if (stackTrace.length >= 1 &&
185 Hashtable.class.getName().equals(stackTrace[0].getClassName())) {
186 return verifyInboundMessage(context);
187 }
188 }
189 throw ex;
190 }
191 }
192
193 @Override
194 protected void cleanUp() {
195 if (callbackHandler != null) {
196 try {
197 CleanupCallback cleanupCallback = new CleanupCallback();
198 callbackHandler.handle(new Callback[]{cleanupCallback});
199 }
200 catch (IOException ex) {
201 logger.warn("Cleanup callback resulted in IOException", ex);
202 }
203 catch (UnsupportedCallbackException ex) {
204
205 }
206 }
207 }
208 }