1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.student.security.cxf.interceptors;
17
18 import java.util.*;
19 import java.util.logging.Level;
20 import java.util.logging.Logger;
21
22 import javax.xml.soap.SOAPElement;
23 import javax.xml.soap.SOAPEnvelope;
24 import javax.xml.soap.SOAPException;
25 import javax.xml.soap.SOAPFactory;
26 import javax.xml.soap.SOAPHeader;
27 import javax.xml.soap.SOAPMessage;
28 import javax.xml.soap.SOAPPart;
29
30 import org.apache.cxf.binding.soap.SoapFault;
31 import org.apache.cxf.binding.soap.SoapMessage;
32 import org.apache.cxf.binding.soap.SoapVersion;
33 import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor;
34 import org.apache.cxf.common.i18n.Message;
35 import org.apache.cxf.common.logging.LogUtils;
36 import org.apache.cxf.interceptor.Fault;
37 import org.apache.cxf.phase.Phase;
38 import org.apache.cxf.phase.PhaseInterceptor;
39 import org.apache.cxf.ws.security.wss4j.AbstractWSS4JInterceptor;
40 import org.apache.ws.security.WSConstants;
41 import org.apache.ws.security.WSEncryptionPart;
42 import org.apache.ws.security.WSSConfig;
43 import org.apache.ws.security.WSSecurityException;
44 import org.apache.ws.security.handler.RequestData;
45 import org.apache.ws.security.handler.WSHandlerConstants;
46 import org.apache.ws.security.util.WSSecurityUtil;
47 import org.opensaml.SAMLAssertion;
48 import org.opensaml.SAMLException;
49 import org.w3c.dom.Document;
50 import org.w3c.dom.Element;
51 import org.w3c.dom.Node;
52
53
54
55
56
57
58
59
60
61
62
63
64 public class SamlTokenCxfOutInterceptor extends AbstractWSS4JInterceptor {
65 private static final Logger LOG = LogUtils
66 .getL7dLogger(SamlTokenCxfOutInterceptor.class);
67
68 private static final Logger TIME_LOG = LogUtils
69 .getL7dLogger(SamlTokenCxfOutInterceptor.class,
70 null,
71 SamlTokenCxfOutInterceptor.class.getName() + "-Time");
72 private SamlTokenCxfOutInterceptorInternal ending;
73 private SAAJOutInterceptor saajOut = new SAAJOutInterceptor();
74 private boolean mtomEnabled;
75
76
77
78
79 private ThreadLocal<Map<String,String>> samlPropertiesHolder = new ThreadLocal<Map<String,String>>();
80 private ThreadLocal<SAMLAssertion> samlAssertionHolder = new ThreadLocal<SAMLAssertion>();;
81
82 public SamlTokenCxfOutInterceptor() {
83 super();
84 setPhase(Phase.PRE_PROTOCOL);
85 getAfter().add(SAAJOutInterceptor.class.getName());
86
87 ending = createEndingInterceptor();
88 }
89
90 public SamlTokenCxfOutInterceptor(Map<String, Object> props) {
91 this();
92 setProperties(props);
93 }
94
95 public boolean isAllowMTOM() {
96 return mtomEnabled;
97 }
98
99
100
101
102
103 public void setAllowMTOM(boolean allowMTOM) {
104 this.mtomEnabled = allowMTOM;
105 }
106
107 public void handleMessage(SoapMessage mc) throws Fault {
108
109
110 if (!mtomEnabled) {
111 mc.put(org.apache.cxf.message.Message.MTOM_ENABLED, false);
112 }
113
114 if (mc.getContent(SOAPMessage.class) == null) {
115 saajOut.handleMessage(mc);
116 }
117
118 mc.getInterceptorChain().add(ending);
119 }
120 public void handleFault(SoapMessage message) {
121 saajOut.handleFault(message);
122 }
123
124 public final SamlTokenCxfOutInterceptorInternal createEndingInterceptor() {
125 return new SamlTokenCxfOutInterceptorInternal();
126 }
127
128 final class SamlTokenCxfOutInterceptorInternal
129 implements PhaseInterceptor<SoapMessage> {
130 public SamlTokenCxfOutInterceptorInternal() {
131 super();
132 }
133
134 public void handleMessage(SoapMessage mc) throws Fault {
135
136 String wsuId = handleMessageUserSAML(mc);
137
138 boolean doDebug = LOG.isLoggable(Level.FINE);
139 boolean doTimeDebug = TIME_LOG.isLoggable(Level.FINE);
140 SoapVersion version = mc.getVersion();
141
142 long t0 = 0;
143 long t1 = 0;
144 long t2 = 0;
145
146 if (doTimeDebug) {
147 t0 = System.currentTimeMillis();
148 }
149
150 if (doDebug) {
151 LOG.fine("SamlTokenCxfOutInterceptor: enter handleMessage()");
152 }
153
154
155
156
157 RequestData reqData = new RequestData();
158
159 reqData.setMsgContext(mc);
160
161
162
163
164
165 try {
166
167
168
169 Vector actions = new Vector();
170 String action = getString(WSHandlerConstants.ACTION, mc);
171 if (action == null) {
172 throw new SoapFault(new Message("NO_ACTION", LOG), version
173 .getReceiver());
174 }
175
176 int doAction = WSSecurityUtil.decodeAction(action, actions);
177 if (doAction == WSConstants.NO_SECURITY) {
178 return;
179 }
180
181
182
183
184
185 reqData.setUsername((String) getOption(WSHandlerConstants.USER));
186 if (reqData.getUsername() == null
187 || reqData.getUsername().equals("")) {
188 String username = (String) getProperty(reqData.getMsgContext(),
189 WSHandlerConstants.USER);
190 if (username != null) {
191 reqData.setUsername(username);
192 }
193 }
194
195
196
197
198
199
200 if ((doAction & (WSConstants.SIGN | WSConstants.UT | WSConstants.UT_SIGN)) != 0
201 && (reqData.getUsername() == null
202 || reqData.getUsername().equals(""))) {
203
204
205
206
207 throw new SoapFault(new Message("NO_USERNAME", LOG), version
208 .getReceiver());
209 }
210 if (doDebug) {
211 LOG.fine("Action: " + doAction);
212 LOG.fine("Actor: " + reqData.getActor());
213 }
214
215
216
217
218
219
220
221
222
223
224
225
226 SOAPMessage saaj = mc.getContent(SOAPMessage.class);
227
228 if (saaj == null) {
229 LOG.warning("SAAJOutHandler must be enabled for WS-Security!");
230 throw new SoapFault(new Message("NO_SAAJ_DOC", LOG), version
231 .getReceiver());
232 }
233
234 Document doc = saaj.getSOAPPart();
235
236
237
238
239 if (mc == null) {
240 return;
241 }
242
243 if (doTimeDebug) {
244 t1 = System.currentTimeMillis();
245 }
246
247
248
249 WSEncryptionPart encP = new WSEncryptionPart(wsuId);
250 reqData.getSignatureParts().add(encP);
251
252 WSEncryptionPart encPBody = new WSEncryptionPart("Body",
253 doc.getDocumentElement().getNamespaceURI(), "Content");
254 reqData.getSignatureParts().add(encPBody);
255
256
257 doSenderAction(doAction, doc, reqData, actions, Boolean.TRUE
258 .equals(getProperty(mc, org.apache.cxf.message.Message.REQUESTOR_ROLE)));
259
260 if (doTimeDebug) {
261 t2 = System.currentTimeMillis();
262 TIME_LOG.fine("Send request: total= " + (t2 - t0)
263 + " request preparation= " + (t1 - t0)
264 + " request processing= " + (t2 - t1)
265 + "\n");
266 }
267
268 if (doDebug) {
269 LOG.fine("SamlTokenCxfOutInterceptor: exit handleMessage()");
270 }
271 } catch (WSSecurityException e) {
272 throw new SoapFault(new Message("SECURITY_FAILED", LOG), e, version
273 .getSender());
274 } finally {
275 reqData.clear();
276 reqData = null;
277 }
278 }
279
280 public Set<String> getAfter() {
281 return Collections.emptySet();
282 }
283
284 public Set<String> getBefore() {
285 return Collections.emptySet();
286 }
287
288 public String getId() {
289 return SamlTokenCxfOutInterceptorInternal.class.getName();
290 }
291
292 public String getPhase() {
293 return Phase.POST_PROTOCOL;
294 }
295
296 @Override
297 public Collection<PhaseInterceptor<? extends org.apache.cxf.message.Message>> getAdditionalInterceptors() {
298 return null;
299 }
300
301 public void handleFault(SoapMessage message) {
302
303 }
304
305
306 public String handleMessageUserSAML(SoapMessage msg) throws Fault {
307 String wsuId = null;
308 Node assertionNode = null;
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369 try{
370 assertionNode = getSamlAssertion().toDOM();
371 } catch(SAMLException se){
372 Logger log = Logger.getLogger(SamlTokenCxfOutInterceptor.class.getName());
373 throw new Fault("Error when adding SAML Attributes or Attribute Statement : ", log, se);
374 }
375
376 try{
377
378 SOAPMessage soapMsg = msg.getContent(SOAPMessage.class);
379 SOAPPart doc = soapMsg.getSOAPPart();
380 SOAPEnvelope envelope = doc.getEnvelope();
381 envelope.addHeader();
382 SOAPHeader soapHeader = soapMsg.getSOAPHeader();
383
384
385 SOAPFactory soapFactory = SOAPFactory.newInstance();
386
387
388 SOAPElement wsseSecurity = soapFactory.createElement("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
389
390
391 if(assertionNode.getNodeType() == Node.ELEMENT_NODE ){
392 Element assertionElement = (Element)assertionNode;
393
394
395 wsuId = setWsuId(assertionElement);
396
397 SOAPElement assertionSOAP = soapFactory.createElement(assertionElement);
398 wsseSecurity.addChildElement(assertionSOAP);
399 }
400
401 soapHeader.addChildElement(wsseSecurity);
402 } catch(SOAPException se){
403 throw new Fault(se);
404 }
405 return wsuId;
406 }
407
408 protected String setWsuId(Element bodyElement) {
409 String id = bodyElement.getAttributeNS(WSConstants.WSU_NS, "Id");
410
411 if ((id == null) || (id.length() == 0)) {
412 id = WSSConfig.getNewInstance().getIdAllocator().createId("id-", bodyElement);
413 String prefix =
414 WSSecurityUtil.setNamespace(bodyElement, WSConstants.WSU_NS, WSConstants.WSU_PREFIX);
415 bodyElement.setAttributeNS(WSConstants.WSU_NS, prefix + ":Id", id);
416 }
417 return id;
418 }
419 }
420
421 public void setSamlProperties(Map<String, String> samlProperties){
422
423 this.samlPropertiesHolder.set(samlProperties);
424 }
425
426 public Map<String, String> getSamlProperties() {
427
428 return this.samlPropertiesHolder.get();
429 }
430
431 public SAMLAssertion getSamlAssertion() {
432 return this.samlAssertionHolder.get();
433 }
434
435 public void setSamlAssertion(SAMLAssertion samlAssertion) {
436 this.samlAssertionHolder.set(samlAssertion);
437 }
438 }