View Javadoc
1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.wss4j.stax.test;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.PushbackInputStream;
26  import java.nio.charset.StandardCharsets;
27  import java.util.ArrayList;
28  import java.util.Arrays;
29  import java.util.Collections;
30  import java.util.HashMap;
31  import java.util.List;
32  import java.util.Map;
33  import java.util.UUID;
34  
35  import javax.crypto.KeyGenerator;
36  import javax.crypto.SecretKey;
37  import javax.security.auth.callback.Callback;
38  import javax.security.auth.callback.CallbackHandler;
39  import javax.security.auth.callback.UnsupportedCallbackException;
40  import javax.xml.namespace.QName;
41  import javax.xml.stream.XMLStreamException;
42  import javax.xml.stream.XMLStreamReader;
43  import javax.xml.stream.XMLStreamWriter;
44  import javax.xml.transform.dom.DOMSource;
45  import javax.xml.transform.stream.StreamResult;
46  
47  import org.apache.wss4j.common.WSEncryptionPart;
48  import org.apache.wss4j.common.crypto.CryptoFactory;
49  import org.apache.wss4j.common.ext.Attachment;
50  import org.apache.wss4j.common.ext.AttachmentRequestCallback;
51  import org.apache.wss4j.common.ext.AttachmentResultCallback;
52  import org.apache.wss4j.common.ext.WSSecurityException;
53  import org.apache.wss4j.common.util.AttachmentUtils;
54  import org.apache.wss4j.common.util.KeyUtils;
55  import org.apache.wss4j.common.util.SOAPUtil;
56  import org.apache.wss4j.dom.WSConstants;
57  import org.apache.wss4j.dom.message.WSSecEncrypt;
58  import org.apache.wss4j.dom.message.WSSecHeader;
59  import org.apache.wss4j.stax.ext.WSSConstants;
60  import org.apache.wss4j.stax.ext.WSSSecurityProperties;
61  import org.apache.wss4j.stax.setup.InboundWSSec;
62  import org.apache.wss4j.stax.setup.OutboundWSSec;
63  import org.apache.wss4j.stax.setup.WSSec;
64  import org.apache.wss4j.stax.test.utils.StAX2DOM;
65  import org.apache.wss4j.stax.test.utils.XmlReaderToWriter;
66  import org.apache.xml.security.exceptions.XMLSecurityException;
67  import org.apache.xml.security.stax.ext.SecurePart;
68  import org.apache.xml.security.stax.securityEvent.SecurityEvent;
69  import org.junit.jupiter.api.Test;
70  import org.w3c.dom.Document;
71  import org.w3c.dom.Element;
72  import org.w3c.dom.NodeList;
73  
74  import static org.junit.jupiter.api.Assertions.assertEquals;
75  import static org.junit.jupiter.api.Assertions.assertFalse;
76  import static org.junit.jupiter.api.Assertions.assertNotNull;
77  import static org.junit.jupiter.api.Assertions.assertTrue;
78  import static org.junit.jupiter.api.Assertions.fail;
79  import static org.junit.jupiter.api.Assumptions.assumeFalse;
80  
81  public class AttachmentTest extends AbstractTestBase {
82  
83      private boolean isIBMJdK = System.getProperty("java.vendor").contains("IBM");
84  
85      public AttachmentTest() throws Exception {
86      }
87  
88      protected Map<String, String> getHeaders(String attachmentId) {
89          Map<String, String> headers = new HashMap<>();
90          headers.put(AttachmentUtils.MIME_HEADER_CONTENT_DESCRIPTION, "Attachment");
91          headers.put(AttachmentUtils.MIME_HEADER_CONTENT_DISPOSITION, "attachment; filename=\"fname.ext\"");
92          headers.put(AttachmentUtils.MIME_HEADER_CONTENT_ID, "<attachment=" + attachmentId + ">");
93          headers.put(AttachmentUtils.MIME_HEADER_CONTENT_LOCATION, "http://ws.apache.org");
94          headers.put(AttachmentUtils.MIME_HEADER_CONTENT_TYPE, "text/xml; charset=UTF-8");
95          headers.put("TestHeader", "testHeaderValue");
96          return headers;
97      }
98  
99      protected byte[] readInputStream(InputStream inputStream) throws IOException {
100         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
101         int read = 0;
102         byte[] buf = new byte[4096];
103         while ((read = inputStream.read(buf)) != -1) {
104             byteArrayOutputStream.write(buf, 0, read);
105         }
106         return byteArrayOutputStream.toByteArray();
107     }
108 
109     @Test
110     public void testXMLAttachmentContentSignature() throws Exception {
111 
112         final String attachmentId = UUID.randomUUID().toString();
113         final Attachment attachment = new Attachment();
114         attachment.setMimeType("text/xml");
115         attachment.addHeaders(getHeaders(attachmentId));
116         attachment.setId(attachmentId);
117         attachment.setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
118 
119         ByteArrayOutputStream baos = new ByteArrayOutputStream();
120         {
121             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
122             List<WSSConstants.Action> actions = new ArrayList<>();
123             actions.add(WSSConstants.SIGNATURE);
124             securityProperties.setActions(actions);
125             securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
126             securityProperties.setSignatureUser("transmitter");
127             securityProperties.addSignaturePart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Element));
128             securityProperties.addSignaturePart(new SecurePart("cid:Attachments", SecurePart.Modifier.Content));
129             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
130 
131             AttachmentCallbackHandler attachmentCallbackHandler =
132                 new AttachmentCallbackHandler(Collections.singletonList(attachment));
133             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
134 
135             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
136             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
137             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
138             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
139             xmlStreamWriter.close();
140         }
141 
142         //done signature; now test sig-verification:
143         AttachmentCallbackHandler attachmentCallbackHandler =
144             new AttachmentCallbackHandler(Collections.singletonList(attachment));
145         {
146             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
147             securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
148             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
149 
150             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
151             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
152             Document document = StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
153 
154             NodeList sigReferences = document.getElementsByTagNameNS(WSConstants.SIG_NS, "Reference");
155             assertEquals(2, sigReferences.getLength());
156         }
157         assertFalse(attachmentCallbackHandler.getResponseAttachments().isEmpty());
158         Attachment responseAttachment = attachmentCallbackHandler.getResponseAttachments().get(0);
159 
160         byte[] attachmentBytes = readInputStream(responseAttachment.getSourceStream());
161         assertTrue(Arrays.equals(attachmentBytes, SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
162         assertEquals("text/xml", responseAttachment.getMimeType());
163     }
164 
165     @Test
166     public void testInvalidXMLAttachmentContentSignature() throws Exception {
167 
168         final String attachmentId = UUID.randomUUID().toString();
169         final Attachment attachment = new Attachment();
170         attachment.setMimeType("text/xml");
171         attachment.addHeaders(getHeaders(attachmentId));
172         attachment.setId(attachmentId);
173         attachment.setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
174 
175         ByteArrayOutputStream baos = new ByteArrayOutputStream();
176         {
177             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
178             List<WSSConstants.Action> actions = new ArrayList<>();
179             actions.add(WSSConstants.SIGNATURE);
180             securityProperties.setActions(actions);
181             securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
182             securityProperties.setSignatureUser("transmitter");
183             securityProperties.addSignaturePart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Element));
184             securityProperties.addSignaturePart(new SecurePart("cid:Attachments", SecurePart.Modifier.Content));
185             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
186 
187             AttachmentCallbackHandler attachmentCallbackHandler =
188                 new AttachmentCallbackHandler(Collections.singletonList(attachment));
189             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
190 
191             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
192             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
193             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
194             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
195             xmlStreamWriter.close();
196         }
197 
198         //done signature; now test sig-verification:
199         {
200             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
201             securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
202             securityProperties.setAttachmentCallbackHandler(new CallbackHandler() {
203                 @Override
204                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
205                     if (callbacks[0] instanceof AttachmentRequestCallback) {
206                         AttachmentRequestCallback attachmentRequestCallback = (AttachmentRequestCallback) callbacks[0];
207 
208                         if (!attachment.getId().equals(attachmentRequestCallback.getAttachmentId())) {
209                             throw new RuntimeException("wrong attachment requested");
210                         }
211 
212                         List<Attachment> attachments = new ArrayList<>();
213                         attachment.setSourceStream(new ByteArrayInputStream(
214                                 SOAPUtil.SAMPLE_SOAP_MSG.replace("15", "16").getBytes(StandardCharsets.UTF_8)));
215                         attachments.add(attachment);
216                         attachmentRequestCallback.setAttachments(attachments);
217                     }
218                 }
219             });
220 
221             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
222             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
223             try {
224                 StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
225                 fail("Exception expected");
226             } catch (XMLStreamException e) {
227                 assertTrue(e.getCause() instanceof XMLSecurityException);
228                 assertTrue(e.getCause().getMessage().startsWith("Invalid digest of reference cid:"));
229             }
230         }
231     }
232 
233     @Test
234     public void testXMLAttachmentCompleteSignature() throws Exception {
235 
236         final String attachmentId = UUID.randomUUID().toString();
237         final Attachment attachment = new Attachment();
238         attachment.setMimeType("text/xml");
239         attachment.addHeaders(getHeaders(attachmentId));
240         attachment.setId(attachmentId);
241         attachment.setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
242 
243         ByteArrayOutputStream baos = new ByteArrayOutputStream();
244         {
245             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
246             List<WSSConstants.Action> actions = new ArrayList<>();
247             actions.add(WSSConstants.SIGNATURE);
248             securityProperties.setActions(actions);
249             securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
250             securityProperties.setSignatureUser("transmitter");
251             securityProperties.addSignaturePart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Element));
252             securityProperties.addSignaturePart(new SecurePart("cid:Attachments", SecurePart.Modifier.Element));
253             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
254 
255             AttachmentCallbackHandler attachmentCallbackHandler =
256                 new AttachmentCallbackHandler(Collections.singletonList(attachment));
257             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
258 
259             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
260             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
261             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
262             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
263             xmlStreamWriter.close();
264         }
265 
266         //done signature; now test sig-verification:
267         AttachmentCallbackHandler attachmentCallbackHandler =
268             new AttachmentCallbackHandler(Collections.singletonList(attachment));
269         {
270             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
271             securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
272             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
273 
274             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
275             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
276             Document document = StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
277 
278             NodeList sigReferences = document.getElementsByTagNameNS(WSConstants.SIG_NS, "Reference");
279             assertEquals(2, sigReferences.getLength());
280         }
281 
282         assertFalse(attachmentCallbackHandler.getResponseAttachments().isEmpty());
283         Attachment responseAttachment = attachmentCallbackHandler.getResponseAttachments().get(0);
284 
285         byte[] attachmentBytes = readInputStream(responseAttachment.getSourceStream());
286         assertTrue(Arrays.equals(attachmentBytes, SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
287         assertEquals("text/xml", responseAttachment.getMimeType());
288     }
289 
290     @Test
291     public void testInvalidXMLAttachmentCompleteSignature() throws Exception {
292 
293         final String attachmentId = UUID.randomUUID().toString();
294         final Attachment attachment = new Attachment();
295         attachment.setMimeType("text/xml");
296         attachment.addHeaders(getHeaders(attachmentId));
297         attachment.setId(attachmentId);
298         attachment.setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
299 
300         ByteArrayOutputStream baos = new ByteArrayOutputStream();
301         {
302             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
303             List<WSSConstants.Action> actions = new ArrayList<>();
304             actions.add(WSSConstants.SIGNATURE);
305             securityProperties.setActions(actions);
306             securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
307             securityProperties.setSignatureUser("transmitter");
308             securityProperties.addSignaturePart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Element));
309             securityProperties.addSignaturePart(new SecurePart("cid:Attachments", SecurePart.Modifier.Element));
310             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
311 
312             AttachmentCallbackHandler attachmentCallbackHandler =
313                 new AttachmentCallbackHandler(Collections.singletonList(attachment));
314             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
315 
316             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
317             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
318             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
319             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
320             xmlStreamWriter.close();
321         }
322 
323         //done signature; now test sig-verification:
324         {
325             attachment.addHeader(AttachmentUtils.MIME_HEADER_CONTENT_DESCRIPTION, "Kaputt");
326 
327             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
328             securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
329             securityProperties.setAttachmentCallbackHandler(new CallbackHandler() {
330                 @Override
331                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
332                     if (callbacks[0] instanceof AttachmentRequestCallback) {
333                         AttachmentRequestCallback attachmentRequestCallback = (AttachmentRequestCallback) callbacks[0];
334 
335                         if (!attachment.getId().equals(attachmentRequestCallback.getAttachmentId())) {
336                             throw new RuntimeException("wrong attachment requested");
337                         }
338 
339                         List<Attachment> attachments = new ArrayList<>();
340                         attachments.add(attachment);
341                         attachmentRequestCallback.setAttachments(attachments);
342                     }
343                 }
344             });
345 
346             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
347             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
348             try {
349                 StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
350                 fail("Exception expected");
351             } catch (XMLStreamException e) {
352                 assertTrue(e.getCause() instanceof XMLSecurityException);
353                 assertTrue(e.getCause().getMessage().startsWith("Invalid digest of reference cid:"));
354             }
355         }
356     }
357 
358     @Test
359     public void testMultipleAttachmentCompleteSignature() throws Exception {
360 
361         final String attachment1Id = UUID.randomUUID().toString();
362         final Attachment[] attachment = new Attachment[2];
363         attachment[0] = new Attachment();
364         attachment[0].setMimeType("text/xml");
365         attachment[0].addHeaders(getHeaders(attachment1Id));
366         attachment[0].setId(attachment1Id);
367         attachment[0].setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
368 
369         final String attachment2Id = UUID.randomUUID().toString();
370         attachment[1] = new Attachment();
371         attachment[1].setMimeType("text/plain");
372         attachment[1].addHeaders(getHeaders(attachment2Id));
373         attachment[1].setId(attachment2Id);
374         attachment[1].setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
375 
376         ByteArrayOutputStream baos = new ByteArrayOutputStream();
377         {
378             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
379             List<WSSConstants.Action> actions = new ArrayList<>();
380             actions.add(WSSConstants.SIGNATURE);
381             securityProperties.setActions(actions);
382             securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
383             securityProperties.setSignatureUser("transmitter");
384             securityProperties.addSignaturePart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Element));
385             securityProperties.addSignaturePart(new SecurePart("cid:Attachments", SecurePart.Modifier.Element));
386             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
387 
388             AttachmentCallbackHandler attachmentCallbackHandler =
389                 new AttachmentCallbackHandler(Arrays.asList(attachment));
390             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
391 
392             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
393             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
394             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
395             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
396             xmlStreamWriter.close();
397         }
398 
399         //done signature; now test sig-verification:
400         AttachmentCallbackHandler attachmentCallbackHandler =
401             new AttachmentCallbackHandler(Arrays.asList(attachment));
402         {
403             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
404             securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
405             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
406 
407             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
408             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
409             Document document = StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
410 
411             NodeList sigReferences = document.getElementsByTagNameNS(WSConstants.SIG_NS, "Reference");
412             assertEquals(3, sigReferences.getLength());
413         }
414 
415         assertFalse(attachmentCallbackHandler.getResponseAttachments().isEmpty());
416         Attachment responseAttachment = attachmentCallbackHandler.getResponseAttachments().get(0);
417 
418         byte[] attachmentBytes = readInputStream(responseAttachment.getSourceStream());
419         assertTrue(Arrays.equals(attachmentBytes, SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
420         assertEquals("text/xml", responseAttachment.getMimeType());
421     }
422 
423     @Test
424     public void testXMLAttachmentContentEncryption() throws Exception {
425 
426         final String attachmentId = UUID.randomUUID().toString();
427         final Attachment attachment = new Attachment();
428         attachment.setMimeType("text/xml");
429         attachment.addHeaders(getHeaders(attachmentId));
430         attachment.setId(attachmentId);
431         attachment.setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
432         AttachmentCallbackHandler attachmentCallbackHandler =
433             new AttachmentCallbackHandler(Collections.singletonList(attachment));
434         List<Attachment> encryptedAttachments = attachmentCallbackHandler.getResponseAttachments();
435 
436         ByteArrayOutputStream baos = new ByteArrayOutputStream();
437         {
438             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
439             List<WSSConstants.Action> actions = new ArrayList<>();
440             actions.add(WSSConstants.ENCRYPTION);
441             securityProperties.setActions(actions);
442             securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
443             securityProperties.setEncryptionUser("receiver");
444             securityProperties.addEncryptionPart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Content));
445             securityProperties.addEncryptionPart(new SecurePart("cid:Attachments", SecurePart.Modifier.Content));
446             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
447 
448             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
449             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
450             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
451             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
452             xmlStreamWriter.close();
453 
454             Document securedDoc = documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray()));
455 
456             NodeList references = securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "DataReference");
457             assertEquals(2, references.getLength());
458             NodeList cipherReferences = securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "CipherReference");
459             assertEquals(1, cipherReferences.getLength());
460             NodeList encDatas = securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "EncryptedData");
461             assertEquals(2, encDatas.getLength());
462 
463             NodeList securityHeaderElement = securedDoc.getElementsByTagNameNS(WSConstants.WSSE_NS, "Security");
464             assertEquals(1, securityHeaderElement.getLength());
465             NodeList childs = securityHeaderElement.item(0).getChildNodes();
466             assertEquals(2, childs.getLength());
467             assertEquals(childs.item(0).getLocalName(), "EncryptedKey");
468             assertEquals(childs.item(1).getLocalName(), "EncryptedData");
469         }
470 
471         attachmentCallbackHandler = new AttachmentCallbackHandler(encryptedAttachments);
472         {
473             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
474             securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
475             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
476             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
477 
478             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
479             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
480             StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
481         }
482 
483         assertFalse(attachmentCallbackHandler.getResponseAttachments().isEmpty());
484         Attachment responseAttachment = attachmentCallbackHandler.getResponseAttachments().get(0);
485 
486         byte[] attachmentBytes = readInputStream(responseAttachment.getSourceStream());
487         assertTrue(Arrays.equals(attachmentBytes, SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
488         assertEquals("text/xml", responseAttachment.getMimeType());
489 
490         Map<String, String> attHeaders = responseAttachment.getHeaders();
491         assertEquals(6, attHeaders.size());
492     }
493 
494     @Test
495     public void testXMLAttachmentContentEncryptionGCM() throws Exception {
496         assumeFalse(isIBMJdK);
497 
498         final String attachmentId = UUID.randomUUID().toString();
499         final Attachment attachment = new Attachment();
500         attachment.setMimeType("text/xml");
501         attachment.addHeaders(getHeaders(attachmentId));
502         attachment.setId(attachmentId);
503         attachment.setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
504         AttachmentCallbackHandler attachmentCallbackHandler =
505             new AttachmentCallbackHandler(Collections.singletonList(attachment));
506         List<Attachment> encryptedAttachments = attachmentCallbackHandler.getResponseAttachments();
507 
508         ByteArrayOutputStream baos = new ByteArrayOutputStream();
509         {
510             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
511             List<WSSConstants.Action> actions = new ArrayList<>();
512             actions.add(WSSConstants.ENCRYPTION);
513             securityProperties.setActions(actions);
514             securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
515             securityProperties.setEncryptionUser("receiver");
516             securityProperties.addEncryptionPart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Content));
517             securityProperties.addEncryptionPart(new SecurePart("cid:Attachments", SecurePart.Modifier.Content));
518             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
519             securityProperties.setEncryptionSymAlgorithm(WSSConstants.NS_XENC11_AES128_GCM);
520 
521             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
522             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
523             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
524             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
525             xmlStreamWriter.close();
526 
527             Document securedDoc = documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray()));
528 
529             NodeList references = securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "DataReference");
530             assertEquals(2, references.getLength());
531             NodeList cipherReferences = securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "CipherReference");
532             assertEquals(1, cipherReferences.getLength());
533             NodeList encDatas = securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "EncryptedData");
534             assertEquals(2, encDatas.getLength());
535 
536             NodeList securityHeaderElement = securedDoc.getElementsByTagNameNS(WSConstants.WSSE_NS, "Security");
537             assertEquals(1, securityHeaderElement.getLength());
538             NodeList childs = securityHeaderElement.item(0).getChildNodes();
539             assertEquals(2, childs.getLength());
540             assertEquals(childs.item(0).getLocalName(), "EncryptedKey");
541             assertEquals(childs.item(1).getLocalName(), "EncryptedData");
542         }
543 
544         attachmentCallbackHandler = new AttachmentCallbackHandler(encryptedAttachments);
545         {
546             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
547             securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
548             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
549             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
550 
551             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
552             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
553             StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
554         }
555 
556         assertFalse(attachmentCallbackHandler.getResponseAttachments().isEmpty());
557         Attachment responseAttachment = attachmentCallbackHandler.getResponseAttachments().get(0);
558 
559         byte[] attachmentBytes = readInputStream(responseAttachment.getSourceStream());
560         assertTrue(Arrays.equals(attachmentBytes, SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
561         assertEquals("text/xml", responseAttachment.getMimeType());
562 
563         Map<String, String> attHeaders = responseAttachment.getHeaders();
564         assertEquals(6, attHeaders.size());
565     }
566 
567     @Test
568     public void testInvalidXMLAttachmentContentEncryption() throws Exception {
569         final String attachmentId = UUID.randomUUID().toString();
570         final Attachment attachment = new Attachment();
571         attachment.setMimeType("text/xml");
572         attachment.addHeaders(getHeaders(attachmentId));
573         attachment.setId(attachmentId);
574         attachment.setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
575         AttachmentCallbackHandler attachmentCallbackHandler =
576             new AttachmentCallbackHandler(Collections.singletonList(attachment));
577         List<Attachment> encryptedAttachments = attachmentCallbackHandler.getResponseAttachments();
578 
579         ByteArrayOutputStream baos = new ByteArrayOutputStream();
580         {
581             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
582             List<WSSConstants.Action> actions = new ArrayList<>();
583             actions.add(WSSConstants.ENCRYPTION);
584             securityProperties.setActions(actions);
585             securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
586             securityProperties.setEncryptionUser("receiver");
587             securityProperties.addEncryptionPart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Content));
588             securityProperties.addEncryptionPart(new SecurePart("cid:Attachments", SecurePart.Modifier.Content));
589             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
590 
591             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
592             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
593             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
594             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
595             xmlStreamWriter.close();
596 
597             Document securedDoc = documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray()));
598 
599             NodeList references = securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "DataReference");
600             assertEquals(2, references.getLength());
601             NodeList cipherReferences = securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "CipherReference");
602             assertEquals(1, cipherReferences.getLength());
603             NodeList encDatas = securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "EncryptedData");
604             assertEquals(2, encDatas.getLength());
605 
606             NodeList securityHeaderElement = securedDoc.getElementsByTagNameNS(WSConstants.WSSE_NS, "Security");
607             assertEquals(1, securityHeaderElement.getLength());
608             NodeList childs = securityHeaderElement.item(0).getChildNodes();
609             assertEquals(2, childs.getLength());
610             assertEquals(childs.item(0).getLocalName(), "EncryptedKey");
611             assertEquals(childs.item(1).getLocalName(), "EncryptedData");
612         }
613 
614         final PushbackInputStream pis = new PushbackInputStream(encryptedAttachments.get(0).getSourceStream(), 1);
615         pis.unread('K');
616         encryptedAttachments.get(0).setSourceStream(pis);
617         attachmentCallbackHandler = new AttachmentCallbackHandler(encryptedAttachments);
618         {
619             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
620             securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
621             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
622             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
623 
624             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
625             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
626             StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
627         }
628 
629         assertFalse(attachmentCallbackHandler.getResponseAttachments().isEmpty());
630         Attachment responseAttachment = attachmentCallbackHandler.getResponseAttachments().get(0);
631 
632         // Different behaviour here for different JDKs...
633         try {
634             byte[] attachmentBytes = readInputStream(responseAttachment.getSourceStream());
635             assertFalse(Arrays.equals(attachmentBytes, SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
636             assertEquals("text/xml", responseAttachment.getMimeType());
637 
638             Map<String, String> attHeaders = responseAttachment.getHeaders();
639             assertEquals(6, attHeaders.size());
640         } catch (IOException ex) { //NOPMD
641             // expected
642         }
643     }
644 
645     @Test
646     public void testXMLAttachmentContentEncryptionExternalReferenceList() throws Exception {
647 
648         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
649         WSSecHeader secHeader = new WSSecHeader(doc);
650         secHeader.insertSecurityHeader();
651 
652         WSSecEncrypt encrypt = new WSSecEncrypt(secHeader);
653         encrypt.setUserInfo("receiver", "default");
654         encrypt.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
655 
656         encrypt.getParts().add(new WSEncryptionPart("Body", "http://schemas.xmlsoap.org/soap/envelope/", "Content"));
657         encrypt.getParts().add(new WSEncryptionPart("cid:Attachments", "Content"));
658 
659         String attachmentId = UUID.randomUUID().toString();
660         final Attachment attachment = new Attachment();
661         attachment.setMimeType("text/xml");
662         attachment.addHeaders(getHeaders(attachmentId));
663         attachment.setId(attachmentId);
664         attachment.setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
665         AttachmentCallbackHandler attachmentCallbackHandler =
666             new AttachmentCallbackHandler(Collections.singletonList(attachment));
667         List<Attachment> encryptedAttachments = attachmentCallbackHandler.getResponseAttachments();
668 
669         encrypt.setAttachmentCallbackHandler(attachmentCallbackHandler);
670 
671         KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
672         SecretKey symmetricKey = keyGen.generateKey();
673         encrypt.prepare(CryptoFactory.getInstance("transmitter-crypto.properties"), symmetricKey);
674         Element refs = encrypt.encrypt(symmetricKey);
675         encrypt.addAttachmentEncryptedDataElements();
676         encrypt.addExternalRefElement(refs);
677         encrypt.prependToHeader();
678 
679         NodeList references = doc.getElementsByTagNameNS(WSConstants.ENC_NS, "DataReference");
680         assertEquals(2, references.getLength());
681         NodeList cipherReferences = doc.getElementsByTagNameNS(WSConstants.ENC_NS, "CipherReference");
682         assertEquals(1, cipherReferences.getLength());
683         NodeList encDatas = doc.getElementsByTagNameNS(WSConstants.ENC_NS, "EncryptedData");
684         assertEquals(2, encDatas.getLength());
685 
686         NodeList securityHeaderElement = doc.getElementsByTagNameNS(WSConstants.WSSE_NS, "Security");
687         assertEquals(1, securityHeaderElement.getLength());
688         NodeList childs = securityHeaderElement.item(0).getChildNodes();
689         assertEquals(3, childs.getLength());
690         assertEquals(childs.item(0).getLocalName(), "EncryptedKey");
691         assertEquals(childs.item(1).getLocalName(), "ReferenceList");
692         assertEquals(childs.item(2).getLocalName(), "EncryptedData");
693 
694         ByteArrayOutputStream baos = new ByteArrayOutputStream();
695 
696         javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
697         transformer.transform(new DOMSource(doc), new StreamResult(baos));
698         attachmentCallbackHandler = new AttachmentCallbackHandler(encryptedAttachments);
699         {
700             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
701             securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
702             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
703             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
704 
705             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
706             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
707             StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
708         }
709 
710         assertFalse(attachmentCallbackHandler.getResponseAttachments().isEmpty());
711         Attachment responseAttachment = attachmentCallbackHandler.getResponseAttachments().get(0);
712         byte[] attachmentBytes = readInputStream(responseAttachment.getSourceStream());
713         assertTrue(Arrays.equals(attachmentBytes, SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
714         assertEquals("text/xml", responseAttachment.getMimeType());
715 
716         Map<String, String> attHeaders = responseAttachment.getHeaders();
717         assertEquals(6, attHeaders.size());
718     }
719 
720     @Test
721     public void testXMLAttachmentCompleteEncryption() throws Exception {
722 
723         final String attachmentId = UUID.randomUUID().toString();
724         final Attachment attachment = new Attachment();
725         attachment.setMimeType("text/xml");
726         attachment.addHeaders(getHeaders(attachmentId));
727         attachment.setId(attachmentId);
728         attachment.setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
729 
730         AttachmentCallbackHandler attachmentCallbackHandler =
731             new AttachmentCallbackHandler(Collections.singletonList(attachment));
732         List<Attachment> encryptedAttachments = attachmentCallbackHandler.getResponseAttachments();
733 
734         ByteArrayOutputStream baos = new ByteArrayOutputStream();
735         {
736             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
737             List<WSSConstants.Action> actions = new ArrayList<>();
738             actions.add(WSSConstants.ENCRYPTION);
739             securityProperties.setActions(actions);
740             securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
741             securityProperties.setEncryptionUser("receiver");
742             securityProperties.addEncryptionPart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Content));
743             securityProperties.addEncryptionPart(new SecurePart("cid:Attachments", SecurePart.Modifier.Element));
744             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
745 
746             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
747             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
748             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
749             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
750             xmlStreamWriter.close();
751 
752             Document securedDoc = documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray()));
753 
754             NodeList references = securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "DataReference");
755             assertEquals(2, references.getLength());
756             NodeList cipherReferences = securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "CipherReference");
757             assertEquals(1, cipherReferences.getLength());
758             NodeList encDatas = securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "EncryptedData");
759             assertEquals(2, encDatas.getLength());
760 
761             NodeList securityHeaderElement = securedDoc.getElementsByTagNameNS(WSConstants.WSSE_NS, "Security");
762             assertEquals(1, securityHeaderElement.getLength());
763             NodeList childs = securityHeaderElement.item(0).getChildNodes();
764             assertEquals(2, childs.getLength());
765             assertEquals(childs.item(0).getLocalName(), "EncryptedKey");
766             assertEquals(childs.item(1).getLocalName(), "EncryptedData");
767 
768             assertEquals(1, encryptedAttachments.get(0).getHeaders().size());
769         }
770 
771         attachmentCallbackHandler = new AttachmentCallbackHandler(encryptedAttachments);
772         {
773             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
774             securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
775             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
776             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
777 
778             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
779             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
780             StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
781         }
782 
783         assertFalse(attachmentCallbackHandler.getResponseAttachments().isEmpty());
784         Attachment responseAttachment = attachmentCallbackHandler.getResponseAttachments().get(0);
785         byte[] attachmentBytes = readInputStream(responseAttachment.getSourceStream());
786         assertTrue(Arrays.equals(attachmentBytes, SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
787         assertEquals("text/xml", responseAttachment.getMimeType());
788 
789         Map<String, String> attHeaders = responseAttachment.getHeaders();
790         assertEquals(6, attHeaders.size());
791     }
792 
793     @Test
794     public void testInvalidXMLAttachmentCompleteEncryption() throws Exception {
795 
796         final String attachmentId = UUID.randomUUID().toString();
797         final Attachment attachment = new Attachment();
798         attachment.setMimeType("text/xml");
799         attachment.addHeaders(getHeaders(attachmentId));
800         attachment.setId(attachmentId);
801         attachment.setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
802 
803         AttachmentCallbackHandler attachmentCallbackHandler =
804             new AttachmentCallbackHandler(Collections.singletonList(attachment));
805         List<Attachment> encryptedAttachments = attachmentCallbackHandler.getResponseAttachments();
806 
807         ByteArrayOutputStream baos = new ByteArrayOutputStream();
808         {
809             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
810             List<WSSConstants.Action> actions = new ArrayList<>();
811             actions.add(WSSConstants.ENCRYPTION);
812             securityProperties.setActions(actions);
813             securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
814             securityProperties.setEncryptionUser("receiver");
815             securityProperties.addEncryptionPart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Content));
816             securityProperties.addEncryptionPart(new SecurePart("cid:Attachments", SecurePart.Modifier.Element));
817             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
818 
819             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
820             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
821             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
822             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
823             xmlStreamWriter.close();
824 
825             Document securedDoc = documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray()));
826 
827             NodeList references = securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "DataReference");
828             assertEquals(2, references.getLength());
829             NodeList cipherReferences = securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "CipherReference");
830             assertEquals(1, cipherReferences.getLength());
831             NodeList encDatas = securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "EncryptedData");
832             assertEquals(2, encDatas.getLength());
833 
834             NodeList securityHeaderElement = securedDoc.getElementsByTagNameNS(WSConstants.WSSE_NS, "Security");
835             assertEquals(1, securityHeaderElement.getLength());
836             NodeList childs = securityHeaderElement.item(0).getChildNodes();
837             assertEquals(2, childs.getLength());
838             assertEquals(childs.item(0).getLocalName(), "EncryptedKey");
839             assertEquals(childs.item(1).getLocalName(), "EncryptedData");
840 
841             assertEquals(1, encryptedAttachments.get(0).getHeaders().size());
842         }
843 
844         final PushbackInputStream pis = new PushbackInputStream(encryptedAttachments.get(0).getSourceStream(), 1);
845         pis.unread('K');
846         encryptedAttachments.get(0).setSourceStream(pis);
847         attachmentCallbackHandler = new AttachmentCallbackHandler(encryptedAttachments);
848         {
849             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
850             securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
851             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
852             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
853 
854             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
855             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
856             try {
857                 StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
858             } catch (XMLStreamException e) {
859                 assertTrue(e.getCause() instanceof WSSecurityException);
860                 // assertEquals(e.getCause().getMessage(), "The signature or decryption was invalid");
861                 return;
862             }
863 
864             assertFalse(attachmentCallbackHandler.getResponseAttachments().isEmpty());
865             Attachment responseAttachment = attachmentCallbackHandler.getResponseAttachments().get(0);
866             byte[] attachmentBytes = readInputStream(responseAttachment.getSourceStream());
867             assertFalse(Arrays.equals(attachmentBytes, SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
868             assertEquals("text/xml", responseAttachment.getMimeType());
869 
870         }
871     }
872 
873     @Test
874     public void testMultipleAttachmentCompleteEncryption() throws Exception {
875 
876         final String attachment1Id = UUID.randomUUID().toString();
877         final Attachment[] attachment = new Attachment[2];
878         attachment[0] = new Attachment();
879         attachment[0].setMimeType("text/xml");
880         attachment[0].addHeaders(getHeaders(attachment1Id));
881         attachment[0].setId(attachment1Id);
882         attachment[0].setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
883 
884         final String attachment2Id = UUID.randomUUID().toString();
885         attachment[1] = new Attachment();
886         attachment[1].setMimeType("text/plain");
887         attachment[1].addHeaders(getHeaders(attachment2Id));
888         attachment[1].setId(attachment2Id);
889         attachment[1].setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
890 
891         AttachmentCallbackHandler attachmentCallbackHandler =
892             new AttachmentCallbackHandler(Arrays.asList(attachment));
893         List<Attachment> encryptedAttachments = attachmentCallbackHandler.getResponseAttachments();
894 
895         ByteArrayOutputStream baos = new ByteArrayOutputStream();
896         {
897             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
898             List<WSSConstants.Action> actions = new ArrayList<>();
899             actions.add(WSSConstants.ENCRYPTION);
900             securityProperties.setActions(actions);
901             securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
902             securityProperties.setEncryptionUser("receiver");
903             securityProperties.addEncryptionPart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Content));
904             securityProperties.addEncryptionPart(new SecurePart("cid:Attachments", SecurePart.Modifier.Element));
905             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
906 
907             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
908             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
909             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
910             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
911             xmlStreamWriter.close();
912         }
913 
914         attachmentCallbackHandler = new AttachmentCallbackHandler(encryptedAttachments);
915         {
916             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
917             securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
918             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
919             securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
920 
921             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
922             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
923             StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
924         }
925 
926         assertFalse(attachmentCallbackHandler.getResponseAttachments().isEmpty());
927         Attachment responseAttachment = attachmentCallbackHandler.getResponseAttachments().get(0);
928 
929         byte[] attachment1Bytes = readInputStream(responseAttachment.getSourceStream());
930         assertTrue(Arrays.equals(attachment1Bytes, SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
931         assertEquals("text/xml", responseAttachment.getMimeType());
932         Map<String, String> att1Headers = responseAttachment.getHeaders();
933         assertEquals(6, att1Headers.size());
934 
935         responseAttachment = attachmentCallbackHandler.getResponseAttachments().get(1);
936 
937         byte[] attachment2Bytes = readInputStream(responseAttachment.getSourceStream());
938         assertTrue(Arrays.equals(attachment2Bytes, SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
939         assertEquals("text/plain", responseAttachment.getMimeType());
940         Map<String, String> att2Headers = responseAttachment.getHeaders();
941         assertEquals(6, att2Headers.size());
942     }
943 
944     @Test
945     public void testXMLAttachmentCmplSignCmplEnc() throws Exception {
946 
947         final String attachmentId = UUID.randomUUID().toString();
948         final Attachment[] attachment = new Attachment[1];
949         attachment[0] = new Attachment();
950         attachment[0].setMimeType("text/xml");
951         attachment[0].addHeaders(getHeaders(attachmentId));
952         attachment[0].setId(attachmentId);
953         attachment[0].setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
954 
955         ByteArrayOutputStream baos = new ByteArrayOutputStream();
956         {
957             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
958             List<WSSConstants.Action> actions = new ArrayList<>();
959             actions.add(WSSConstants.SIGNATURE);
960             actions.add(WSSConstants.ENCRYPTION);
961             securityProperties.setActions(actions);
962             securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
963             securityProperties.setSignatureUser("transmitter");
964             securityProperties.addSignaturePart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Element));
965             securityProperties.addSignaturePart(new SecurePart("cid:Attachments", SecurePart.Modifier.Element));
966             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
967 
968             securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
969             securityProperties.setEncryptionUser("receiver");
970             securityProperties.addEncryptionPart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Content));
971             securityProperties.addEncryptionPart(new SecurePart("cid:Attachments", SecurePart.Modifier.Element));
972 
973             securityProperties.setAttachmentCallbackHandler(new CallbackHandler() {
974                 @Override
975                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
976                     if (callbacks[0] instanceof AttachmentRequestCallback) {
977                         AttachmentRequestCallback attachmentRequestCallback = (AttachmentRequestCallback) callbacks[0];
978                         List<Attachment> attachments = new ArrayList<>();
979                         attachments.add(attachment[0]);
980                         attachmentRequestCallback.setAttachments(attachments);
981                     } else {
982                         AttachmentResultCallback attachmentResultCallback = (AttachmentResultCallback) callbacks[0];
983                         attachment[0] = attachmentResultCallback.getAttachment();
984                     }
985                 }
986             });
987 
988             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
989             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
990             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
991             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
992             xmlStreamWriter.close();
993 
994             Document securedDoc = documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray()));
995 
996             NodeList securityHeaderElement = securedDoc.getElementsByTagNameNS(WSConstants.WSSE_NS, "Security");
997             assertEquals(1, securityHeaderElement.getLength());
998             NodeList childs = securityHeaderElement.item(0).getChildNodes();
999             assertEquals(3, childs.getLength());
1000             assertEquals(childs.item(0).getLocalName(), "EncryptedKey");
1001             assertEquals(childs.item(1).getLocalName(), "EncryptedData");
1002             assertEquals(childs.item(2).getLocalName(), "Signature");
1003 
1004             assertEquals(1, attachment[0].getHeaders().size());
1005         }
1006 
1007         {
1008             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
1009             securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
1010             securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
1011             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
1012             securityProperties.setAttachmentCallbackHandler(new CallbackHandler() {
1013                 @Override
1014                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
1015                     if (callbacks[0] instanceof AttachmentRequestCallback) {
1016                         AttachmentRequestCallback attachmentRequestCallback = (AttachmentRequestCallback)callbacks[0];
1017 
1018                         if (!attachment[0].getId().equals(attachmentRequestCallback.getAttachmentId())) {
1019                             throw new RuntimeException("wrong attachment requested");
1020                         }
1021 
1022                         List<Attachment> attachments = new ArrayList<>();
1023                         attachments.add(attachment[0]);
1024                         attachmentRequestCallback.setAttachments(attachments);
1025                     } else {
1026                         AttachmentResultCallback attachmentResultCallback = (AttachmentResultCallback)callbacks[0];
1027                         attachment[0] = attachmentResultCallback.getAttachment();
1028                     }
1029                 }
1030             });
1031 
1032             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
1033             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
1034             StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
1035         }
1036 
1037         byte[] attachmentBytes = readInputStream(attachment[0].getSourceStream());
1038         assertTrue(Arrays.equals(attachmentBytes, SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
1039         assertEquals("text/xml", attachment[0].getMimeType());
1040 
1041         Map<String, String> attHeaders = attachment[0].getHeaders();
1042         assertEquals(6, attHeaders.size());
1043     }
1044 
1045     @Test
1046     public void testInvalidXMLAttachmentCmplSignCmplEnc() throws Exception {
1047 
1048         final String attachmentId = UUID.randomUUID().toString();
1049         final Attachment[] attachment = new Attachment[1];
1050         attachment[0] = new Attachment();
1051         attachment[0].setMimeType("text/xml");
1052         attachment[0].addHeaders(getHeaders(attachmentId));
1053         attachment[0].setId(attachmentId);
1054         attachment[0].setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
1055 
1056         ByteArrayOutputStream baos = new ByteArrayOutputStream();
1057         {
1058             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
1059             List<WSSConstants.Action> actions = new ArrayList<>();
1060             actions.add(WSSConstants.SIGNATURE);
1061             actions.add(WSSConstants.ENCRYPTION);
1062             securityProperties.setActions(actions);
1063             securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
1064             securityProperties.setSignatureUser("transmitter");
1065             securityProperties.addSignaturePart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Element));
1066             securityProperties.addSignaturePart(new SecurePart("cid:Attachments", SecurePart.Modifier.Element));
1067             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
1068 
1069             securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
1070             securityProperties.setEncryptionUser("receiver");
1071             securityProperties.addEncryptionPart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Content));
1072             securityProperties.addEncryptionPart(new SecurePart("cid:Attachments", SecurePart.Modifier.Element));
1073 
1074             securityProperties.setAttachmentCallbackHandler(new CallbackHandler() {
1075                 @Override
1076                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
1077                     if (callbacks[0] instanceof AttachmentRequestCallback) {
1078                         AttachmentRequestCallback attachmentRequestCallback = (AttachmentRequestCallback) callbacks[0];
1079                         List<Attachment> attachments = new ArrayList<>();
1080                         attachments.add(attachment[0]);
1081                         attachmentRequestCallback.setAttachments(attachments);
1082                     } else {
1083                         AttachmentResultCallback attachmentResultCallback = (AttachmentResultCallback) callbacks[0];
1084                         attachment[0] = attachmentResultCallback.getAttachment();
1085                     }
1086                 }
1087             });
1088 
1089             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
1090             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
1091             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
1092             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
1093             xmlStreamWriter.close();
1094         }
1095 
1096         {
1097             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
1098             securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
1099             securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
1100             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
1101             securityProperties.setAttachmentCallbackHandler(new CallbackHandler() {
1102                 @Override
1103                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
1104                     if (callbacks[0] instanceof AttachmentRequestCallback) {
1105                         AttachmentRequestCallback attachmentRequestCallback = (AttachmentRequestCallback) callbacks[0];
1106 
1107                         if (!attachment[0].getId().equals(attachmentRequestCallback.getAttachmentId())) {
1108                             throw new RuntimeException("wrong attachment requested");
1109                         }
1110 
1111                         List<Attachment> attachments = new ArrayList<>();
1112                         attachments.add(attachment[0]);
1113 
1114                         if (attachment[0].getHeaders().size() == 6) {
1115                             //signature callback
1116                             attachment[0].addHeader(AttachmentUtils.MIME_HEADER_CONTENT_DESCRIPTION, "Kaputt");
1117                         }
1118 
1119                         attachmentRequestCallback.setAttachments(attachments);
1120                     } else {
1121                         AttachmentResultCallback attachmentResultCallback = (AttachmentResultCallback) callbacks[0];
1122                         attachment[0] = attachmentResultCallback.getAttachment();
1123                     }
1124                 }
1125             });
1126             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
1127             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
1128             try {
1129                 StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
1130                 fail("Exception expected");
1131             } catch (XMLStreamException e) {
1132                 assertTrue(e.getCause() instanceof XMLSecurityException);
1133                 assertTrue(e.getCause().getMessage().startsWith("Invalid digest of reference cid:"));
1134             }
1135         }
1136     }
1137 
1138     @Test
1139     public void testXMLAttachmentCmplEncCmplSign() throws Exception {
1140 
1141         final String attachmentId = UUID.randomUUID().toString();
1142         final Attachment[] attachment = new Attachment[1];
1143         attachment[0] = new Attachment();
1144         attachment[0].setMimeType("text/xml");
1145         attachment[0].addHeaders(getHeaders(attachmentId));
1146         attachment[0].setId(attachmentId);
1147         attachment[0].setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
1148 
1149         ByteArrayOutputStream baos = new ByteArrayOutputStream();
1150         {
1151             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
1152             List<WSSConstants.Action> actions = new ArrayList<>();
1153             actions.add(WSSConstants.ENCRYPTION);
1154             actions.add(WSSConstants.SIGNATURE);
1155             securityProperties.setActions(actions);
1156             securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
1157             securityProperties.setSignatureUser("transmitter");
1158             securityProperties.addSignaturePart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Element));
1159             securityProperties.addSignaturePart(new SecurePart("cid:Attachments", SecurePart.Modifier.Element));
1160             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
1161 
1162             securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
1163             securityProperties.setEncryptionUser("receiver");
1164             securityProperties.addEncryptionPart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Content));
1165             securityProperties.addEncryptionPart(new SecurePart("cid:Attachments", SecurePart.Modifier.Element));
1166 
1167             securityProperties.setAttachmentCallbackHandler(new CallbackHandler() {
1168                 @Override
1169                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
1170                     if (callbacks[0] instanceof AttachmentRequestCallback) {
1171                         AttachmentRequestCallback attachmentRequestCallback = (AttachmentRequestCallback) callbacks[0];
1172                         List<Attachment> attachments = new ArrayList<>();
1173                         attachments.add(attachment[0]);
1174                         attachmentRequestCallback.setAttachments(attachments);
1175                     } else {
1176                         AttachmentResultCallback attachmentResultCallback = (AttachmentResultCallback) callbacks[0];
1177                         attachment[0] = attachmentResultCallback.getAttachment();
1178                     }
1179                 }
1180             });
1181 
1182             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
1183             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
1184             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
1185             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
1186             xmlStreamWriter.close();
1187 
1188             Document securedDoc = documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray()));
1189 
1190             NodeList securityHeaderElement = securedDoc.getElementsByTagNameNS(WSConstants.WSSE_NS, "Security");
1191             assertEquals(1, securityHeaderElement.getLength());
1192             NodeList childs = securityHeaderElement.item(0).getChildNodes();
1193             assertEquals(3, childs.getLength());
1194             assertEquals(childs.item(0).getLocalName(), "Signature");
1195             assertEquals(childs.item(1).getLocalName(), "EncryptedKey");
1196             assertEquals(childs.item(2).getLocalName(), "EncryptedData");
1197 
1198             assertEquals(1, attachment[0].getHeaders().size());
1199         }
1200 
1201         {
1202             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
1203             securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
1204             securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
1205             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
1206             securityProperties.setAttachmentCallbackHandler(new CallbackHandler() {
1207                 @Override
1208                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
1209                     if (callbacks[0] instanceof AttachmentRequestCallback) {
1210                         AttachmentRequestCallback attachmentRequestCallback = (AttachmentRequestCallback) callbacks[0];
1211 
1212                         if (!attachment[0].getId().equals(attachmentRequestCallback.getAttachmentId())) {
1213                             throw new RuntimeException("wrong attachment requested");
1214                         }
1215 
1216                         List<Attachment> attachments = new ArrayList<>();
1217                         attachments.add(attachment[0]);
1218                         attachmentRequestCallback.setAttachments(attachments);
1219                     } else {
1220                         AttachmentResultCallback attachmentResultCallback = (AttachmentResultCallback) callbacks[0];
1221                         attachment[0] = attachmentResultCallback.getAttachment();
1222                     }
1223                 }
1224             });
1225 
1226             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
1227             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
1228             StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
1229         }
1230 
1231         byte[] attachmentBytes = readInputStream(attachment[0].getSourceStream());
1232         assertTrue(Arrays.equals(attachmentBytes, SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
1233         assertEquals("text/xml", attachment[0].getMimeType());
1234 
1235         Map<String, String> attHeaders = attachment[0].getHeaders();
1236         assertEquals(6, attHeaders.size());
1237     }
1238 
1239     @Test
1240     public void testInvalidXMLAttachmentCmplEncCmplSign() throws Exception {
1241 
1242         final String attachmentId = UUID.randomUUID().toString();
1243         final Attachment[] attachment = new Attachment[1];
1244         attachment[0] = new Attachment();
1245         attachment[0].setMimeType("text/xml");
1246         attachment[0].addHeaders(getHeaders(attachmentId));
1247         attachment[0].setId(attachmentId);
1248         attachment[0].setSourceStream(new ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
1249 
1250         ByteArrayOutputStream baos = new ByteArrayOutputStream();
1251         {
1252             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
1253             List<WSSConstants.Action> actions = new ArrayList<>();
1254             actions.add(WSSConstants.ENCRYPTION);
1255             actions.add(WSSConstants.SIGNATURE);
1256             securityProperties.setActions(actions);
1257             securityProperties.loadSignatureKeyStore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
1258             securityProperties.setSignatureUser("transmitter");
1259             securityProperties.addSignaturePart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Element));
1260             securityProperties.addSignaturePart(new SecurePart("cid:Attachments", SecurePart.Modifier.Element));
1261             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
1262 
1263             securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray());
1264             securityProperties.setEncryptionUser("receiver");
1265             securityProperties.addEncryptionPart(new SecurePart(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Body"), SecurePart.Modifier.Content));
1266             securityProperties.addEncryptionPart(new SecurePart("cid:Attachments", SecurePart.Modifier.Element));
1267 
1268             securityProperties.setAttachmentCallbackHandler(new CallbackHandler() {
1269                 @Override
1270                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
1271                     if (callbacks[0] instanceof AttachmentRequestCallback) {
1272                         AttachmentRequestCallback attachmentRequestCallback = (AttachmentRequestCallback) callbacks[0];
1273                         List<Attachment> attachments = new ArrayList<>();
1274                         attachments.add(attachment[0]);
1275                         attachmentRequestCallback.setAttachments(attachments);
1276                     } else {
1277                         AttachmentResultCallback attachmentResultCallback = (AttachmentResultCallback) callbacks[0];
1278                         attachment[0] = attachmentResultCallback.getAttachment();
1279                     }
1280                 }
1281             });
1282 
1283             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
1284             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
1285             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
1286             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
1287             xmlStreamWriter.close();
1288 
1289             Document securedDoc = documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray()));
1290 
1291             NodeList securityHeaderElement = securedDoc.getElementsByTagNameNS(WSConstants.WSSE_NS, "Security");
1292             assertEquals(1, securityHeaderElement.getLength());
1293             NodeList childs = securityHeaderElement.item(0).getChildNodes();
1294             assertEquals(3, childs.getLength());
1295             assertEquals(childs.item(0).getLocalName(), "Signature");
1296             assertEquals(childs.item(1).getLocalName(), "EncryptedKey");
1297             assertEquals(childs.item(2).getLocalName(), "EncryptedData");
1298         }
1299 
1300         {
1301             final PushbackInputStream pis = new PushbackInputStream(attachment[0].getSourceStream(), 1);
1302             pis.unread('K');
1303             attachment[0].setSourceStream(pis);
1304 
1305             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
1306             securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
1307             securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"), "default".toCharArray());
1308             securityProperties.setCallbackHandler(new CallbackHandlerImpl());
1309             securityProperties.setAttachmentCallbackHandler(new CallbackHandler() {
1310                 @Override
1311                 public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
1312                     if (callbacks[0] instanceof AttachmentRequestCallback) {
1313                         AttachmentRequestCallback attachmentRequestCallback = (AttachmentRequestCallback) callbacks[0];
1314 
1315                         if (!attachment[0].getId().equals(attachmentRequestCallback.getAttachmentId())) {
1316                             throw new RuntimeException("wrong attachment requested");
1317                         }
1318 
1319                         List<Attachment> attachments = new ArrayList<>();
1320                         attachments.add(attachment[0]);
1321                         attachmentRequestCallback.setAttachments(attachments);
1322                     } else {
1323                         AttachmentResultCallback attachmentResultCallback = (AttachmentResultCallback) callbacks[0];
1324                         attachment[0] = attachmentResultCallback.getAttachment();
1325                     }
1326                 }
1327             });
1328 
1329             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
1330             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
1331             try {
1332                 StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
1333                 fail("Exception expected");
1334             } catch (XMLStreamException e) {
1335                 assertNotNull(e.getMessage());
1336             }
1337         }
1338     }
1339 
1340 }