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