This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch 2_4_x-fixes
in repository https://gitbox.apache.org/repos/asf/ws-wss4j.git


The following commit(s) were added to refs/heads/2_4_x-fixes by this push:
     new 539021600 Make sure for Attachment-Complete the mime type is read from 
the encrypted header (#688)
539021600 is described below

commit 53902160095c2bf72eef94fac8d7ddedaa838226
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Mon Sep 14 10:13:06 2026 +0100

    Make sure for Attachment-Complete the mime type is read from the encrypted 
header (#688)
---
 .../org/apache/wss4j/dom/util/EncryptionUtils.java |  17 ++-
 .../apache/wss4j/dom/message/AttachmentTest.java   | 128 +++++++++++++++--
 .../processor/input/DecryptInputProcessor.java     |  16 ++-
 .../org/apache/wss4j/stax/test/AttachmentTest.java | 154 +++++++++++++++++++--
 4 files changed, 285 insertions(+), 30 deletions(-)

diff --git 
a/ws-security-dom/src/main/java/org/apache/wss4j/dom/util/EncryptionUtils.java 
b/ws-security-dom/src/main/java/org/apache/wss4j/dom/util/EncryptionUtils.java
index 9dd55f07f..e5692d1ab 100644
--- 
a/ws-security-dom/src/main/java/org/apache/wss4j/dom/util/EncryptionUtils.java
+++ 
b/ws-security-dom/src/main/java/org/apache/wss4j/dom/util/EncryptionUtils.java
@@ -54,7 +54,9 @@ import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public final class EncryptionUtils {
 
@@ -349,14 +351,21 @@ public final class EncryptionUtils {
 
             Attachment resultAttachment = new Attachment();
             resultAttachment.setId(attachment.getId());
-            resultAttachment.setMimeType(encData.getAttributeNS(null, 
"MimeType"));
             resultAttachment.setSourceStream(attachmentInputStream);
-            resultAttachment.addHeaders(attachment.getHeaders());
 
             String typeStr = encData.getAttributeNS(null, "Type");
             if 
(WSConstants.SWA_ATTACHMENT_ENCRYPTED_DATA_TYPE_COMPLETE.equals(typeStr)) {
-                AttachmentUtils.readAndReplaceEncryptedAttachmentHeaders(
-                        resultAttachment.getHeaders(), attachmentInputStream);
+                Map<String, String> protectedHeaders = new HashMap<>();
+                
AttachmentUtils.readAndReplaceEncryptedAttachmentHeaders(protectedHeaders, 
attachmentInputStream);
+                String contentType = 
protectedHeaders.get(AttachmentUtils.MIME_HEADER_CONTENT_TYPE);
+                if (contentType == null) {
+                    throw new 
WSSecurityException(WSSecurityException.ErrorCode.FAILED_CHECK);
+                }
+                resultAttachment.setMimeType(contentType);
+                resultAttachment.addHeaders(protectedHeaders);
+            } else {
+                resultAttachment.setMimeType(encData.getAttributeNS(null, 
"MimeType"));
+                resultAttachment.addHeaders(attachment.getHeaders());
             }
 
             AttachmentResultCallback attachmentResultCallback = new 
AttachmentResultCallback();
diff --git 
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/AttachmentTest.java
 
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/AttachmentTest.java
index 9eab6c6fd..68a0751af 100644
--- 
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/AttachmentTest.java
+++ 
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/AttachmentTest.java
@@ -725,10 +725,10 @@ public class AttachmentTest {
 
         byte[] attachmentBytes = 
readInputStream(responseAttachment.getSourceStream());
         assertTrue(Arrays.equals(attachmentBytes, 
SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
-        assertEquals("text/xml", responseAttachment.getMimeType());
+        assertEquals("text/xml; charset=UTF-8", 
responseAttachment.getMimeType());
 
         Map<String, String> attHeaders = responseAttachment.getHeaders();
-        assertEquals(6, attHeaders.size());
+        assertEquals(5, attHeaders.size());
     }
 
     @Test
@@ -785,6 +785,112 @@ public class AttachmentTest {
         assertEquals("text/xml", responseAttachment.getMimeType());
     }
 
+    // Regression test for CWE-345: a wire attacker cannot forge the delivered 
MIME type of an
+    // Attachment-Complete encrypted attachment by tampering with the 
unauthenticated
+    // xenc:EncryptedData/@MimeType attribute - the MIME type must be sourced 
from the
+    // encrypted (protected) Content-Type header instead.
+    @Test
+    public void 
testXMLAttachmentCompleteEncryptionTamperedMimeTypeAttributeIgnored() throws 
Exception {
+        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+        WSSecHeader secHeader = new WSSecHeader(doc);
+        secHeader.insertSecurityHeader();
+
+        WSSecEncrypt encrypt = new WSSecEncrypt(secHeader);
+        encrypt.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", 
"security");
+        encrypt.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
+
+        encrypt.getParts().add(new WSEncryptionPart("Body", 
"http://schemas.xmlsoap.org/soap/envelope/";, "Content"));
+        encrypt.getParts().add(new WSEncryptionPart("cid:Attachments", 
"Element"));
+
+        String attachmentId = UUID.randomUUID().toString();
+        final Attachment attachment = new Attachment();
+        attachment.setMimeType("text/xml");
+        attachment.addHeaders(getHeaders(attachmentId));
+        attachment.setId(attachmentId);
+        attachment.setSourceStream(new 
ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
+
+        AttachmentCallbackHandler attachmentCallbackHandler =
+            new 
AttachmentCallbackHandler(Collections.singletonList(attachment));
+        encrypt.setAttachmentCallbackHandler(attachmentCallbackHandler);
+        List<Attachment> encryptedAttachments = 
attachmentCallbackHandler.getResponseAttachments();
+
+        KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
+        SecretKey symmetricKey = keyGen.generateKey();
+        Document encryptedDoc = encrypt.build(crypto, symmetricKey);
+
+        // Simulate a wire attacker rewriting the unauthenticated @MimeType 
attribute
+        NodeList encDatas = 
encryptedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "EncryptedData");
+        Element attachmentEncData = null;
+        for (int i = 0; i < encDatas.getLength(); i++) {
+            Element encData = (Element) encDatas.item(i);
+            if 
(WSConstants.SWA_ATTACHMENT_ENCRYPTED_DATA_TYPE_COMPLETE.equals(encData.getAttributeNS(null,
 "Type"))) {
+                attachmentEncData = encData;
+                break;
+            }
+        }
+        assertFalse(attachmentEncData == null);
+        attachmentEncData.setAttributeNS(null, "MimeType", 
"application/malicious");
+        encryptedAttachments.get(0).getHeaders().put("X-Attacker-Controlled", 
"forged");
+
+        if (LOG.isDebugEnabled()) {
+            String outputString = 
XMLUtils.prettyDocumentToString(encryptedDoc);
+            LOG.debug(outputString);
+        }
+
+        attachmentCallbackHandler = new 
AttachmentCallbackHandler(encryptedAttachments);
+        verify(encryptedDoc, attachmentCallbackHandler);
+
+        
assertFalse(attachmentCallbackHandler.getResponseAttachments().isEmpty());
+        Attachment responseAttachment = 
attachmentCallbackHandler.getResponseAttachments().get(0);
+
+        byte[] attachmentBytes = 
readInputStream(responseAttachment.getSourceStream());
+        assertTrue(Arrays.equals(attachmentBytes, 
SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
+        assertEquals("text/xml; charset=UTF-8", 
responseAttachment.getMimeType());
+        assertFalse(responseAttachment.getHeaders().containsKey("TestHeader"));
+        
assertFalse(responseAttachment.getHeaders().containsKey("X-Attacker-Controlled"));
+    }
+
+    // Regression test for CWE-345: if the protected header block (inside the 
ciphertext) does
+    // not contain a Content-Type header, decryption of an Attachment-Complete 
attachment must
+    // fail closed rather than falling back to the unauthenticated @MimeType 
attribute.
+    @Test
+    public void 
testXMLAttachmentCompleteEncryptionMissingProtectedContentType() throws 
Exception {
+        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+        WSSecHeader secHeader = new WSSecHeader(doc);
+        secHeader.insertSecurityHeader();
+
+        WSSecEncrypt encrypt = new WSSecEncrypt(secHeader);
+        encrypt.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", 
"security");
+        encrypt.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
+
+        encrypt.getParts().add(new WSEncryptionPart("Body", 
"http://schemas.xmlsoap.org/soap/envelope/";, "Content"));
+        encrypt.getParts().add(new WSEncryptionPart("cid:Attachments", 
"Element"));
+
+        String attachmentId = UUID.randomUUID().toString();
+        final Attachment attachment = new Attachment();
+        attachment.setMimeType("text/xml");
+        Map<String, String> headers = getHeaders(attachmentId);
+        headers.remove(AttachmentUtils.MIME_HEADER_CONTENT_TYPE);
+        attachment.addHeaders(headers);
+        attachment.setId(attachmentId);
+        attachment.setSourceStream(new 
ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
+
+        AttachmentCallbackHandler attachmentCallbackHandler =
+            new 
AttachmentCallbackHandler(Collections.singletonList(attachment));
+        encrypt.setAttachmentCallbackHandler(attachmentCallbackHandler);
+        List<Attachment> encryptedAttachments = 
attachmentCallbackHandler.getResponseAttachments();
+
+        KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_128);
+        SecretKey symmetricKey = keyGen.generateKey();
+        Document encryptedDoc = encrypt.build(crypto, symmetricKey);
+
+        final AttachmentCallbackHandler finalAttachmentCallbackHandler =
+            new AttachmentCallbackHandler(encryptedAttachments);
+        WSSecurityException exception = 
org.junit.jupiter.api.Assertions.assertThrows(
+            WSSecurityException.class, () -> verify(encryptedDoc, 
finalAttachmentCallbackHandler));
+        assertEquals(WSSecurityException.ErrorCode.FAILED_CHECK, 
exception.getErrorCode());
+    }
+
     @Test
     public void testMultipleAttachmentCompleteEncryption() throws Exception {
         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
@@ -835,17 +941,17 @@ public class AttachmentTest {
 
         byte[] attachment1Bytes = 
readInputStream(responseAttachment.getSourceStream());
         assertTrue(Arrays.equals(attachment1Bytes, 
SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
-        assertEquals("text/xml", responseAttachment.getMimeType());
+        assertEquals("text/xml; charset=UTF-8", 
responseAttachment.getMimeType());
         Map<String, String> att1Headers = responseAttachment.getHeaders();
-        assertEquals(6, att1Headers.size());
+        assertEquals(5, att1Headers.size());
 
         responseAttachment = 
attachmentCallbackHandler.getResponseAttachments().get(1);
         byte[] attachment2Bytes = 
readInputStream(responseAttachment.getSourceStream());
         assertTrue(Arrays.equals(attachment2Bytes, 
SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
-        assertEquals("text/plain", responseAttachment.getMimeType());
+        assertEquals("text/xml; charset=UTF-8", 
responseAttachment.getMimeType());
 
         Map<String, String> att2Headers = responseAttachment.getHeaders();
-        assertEquals(6, att2Headers.size());
+        assertEquals(5, att2Headers.size());
     }
 
     @Test
@@ -909,10 +1015,10 @@ public class AttachmentTest {
 
         byte[] attachmentBytes = 
readInputStream(responseAttachment.getSourceStream());
         assertTrue(Arrays.equals(attachmentBytes, 
SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
-        assertEquals("text/xml", responseAttachment.getMimeType());
+        assertEquals("text/xml; charset=UTF-8", 
responseAttachment.getMimeType());
 
         Map<String, String> attHeaders = responseAttachment.getHeaders();
-        assertEquals(6, attHeaders.size());
+        assertEquals(5, attHeaders.size());
     }
 
     @Test
@@ -998,7 +1104,7 @@ public class AttachmentTest {
                         List<Attachment> attachments = new ArrayList<>();
                         attachments.add(attachment[0]);
 
-                        if (attachment[0].getHeaders().size() == 6) {
+                        if (attachment[0].getHeaders().size() == 5) {
                             //signature callback
                             
attachment[0].addHeader(AttachmentUtils.MIME_HEADER_CONTENT_DESCRIPTION, 
"Kaputt");
                         }
@@ -1077,10 +1183,10 @@ public class AttachmentTest {
 
         byte[] attachmentBytes = 
readInputStream(responseAttachment.getSourceStream());
         assertTrue(Arrays.equals(attachmentBytes, 
SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
-        assertEquals("text/xml", responseAttachment.getMimeType());
+        assertEquals("text/xml; charset=UTF-8", 
responseAttachment.getMimeType());
 
         Map<String, String> attHeaders = responseAttachment.getHeaders();
-        assertEquals(6, attHeaders.size());
+        assertEquals(5, attHeaders.size());
     }
 
     @Test
diff --git 
a/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/DecryptInputProcessor.java
 
b/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/DecryptInputProcessor.java
index 1a2b2dbd9..1068d8515 100644
--- 
a/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/DecryptInputProcessor.java
+++ 
b/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/DecryptInputProcessor.java
@@ -24,6 +24,7 @@ import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.security.Key;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -359,17 +360,24 @@ public class DecryptInputProcessor extends 
AbstractDecryptInputProcessor {
 
             Attachment resultAttachment = new Attachment();
             resultAttachment.setId(attachment.getId());
-            resultAttachment.setMimeType(encryptedDataType.getMimeType());
             resultAttachment.setSourceStream(attachmentInputStream);
-            resultAttachment.addHeaders(attachment.getHeaders());
 
             if 
(WSSConstants.SWA_ATTACHMENT_ENCRYPTED_DATA_TYPE_COMPLETE.equals(encryptedDataType.getType()))
 {
+                Map<String, String> protectedHeaders = new HashMap<>();
                 try {
-                    AttachmentUtils.readAndReplaceEncryptedAttachmentHeaders(
-                        resultAttachment.getHeaders(), attachmentInputStream);
+                    
AttachmentUtils.readAndReplaceEncryptedAttachmentHeaders(protectedHeaders, 
attachmentInputStream);
                 } catch (IOException e) {
                     throw new 
WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, e);
                 }
+                String contentType = 
protectedHeaders.get(AttachmentUtils.MIME_HEADER_CONTENT_TYPE);
+                if (contentType == null) {
+                    throw new 
WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
+                }
+                resultAttachment.setMimeType(contentType);
+                resultAttachment.addHeaders(protectedHeaders);
+            } else {
+                resultAttachment.setMimeType(encryptedDataType.getMimeType());
+                resultAttachment.addHeaders(attachment.getHeaders());
             }
 
             AttachmentResultCallback attachmentResultCallback = new 
AttachmentResultCallback();
diff --git 
a/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/AttachmentTest.java 
b/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/AttachmentTest.java
index 62d21dd8c..99eb15f4c 100644
--- 
a/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/AttachmentTest.java
+++ 
b/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/AttachmentTest.java
@@ -784,10 +784,10 @@ public class AttachmentTest extends AbstractTestBase {
         Attachment responseAttachment = 
attachmentCallbackHandler.getResponseAttachments().get(0);
         byte[] attachmentBytes = 
readInputStream(responseAttachment.getSourceStream());
         assertTrue(Arrays.equals(attachmentBytes, 
SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
-        assertEquals("text/xml", responseAttachment.getMimeType());
+        assertEquals("text/xml; charset=UTF-8", 
responseAttachment.getMimeType());
 
         Map<String, String> attHeaders = responseAttachment.getHeaders();
-        assertEquals(6, attHeaders.size());
+        assertEquals(5, attHeaders.size());
     }
 
     @Test
@@ -870,6 +870,138 @@ public class AttachmentTest extends AbstractTestBase {
         }
     }
 
+    // Regression test for CWE-345: a wire attacker cannot forge the delivered 
MIME type of an
+    // Attachment-Complete encrypted attachment by tampering with the 
unauthenticated
+    // xenc:EncryptedData/@MimeType attribute - the MIME type must be sourced 
from the
+    // encrypted (protected) Content-Type header instead.
+    @Test
+    public void 
testXMLAttachmentCompleteEncryptionTamperedMimeTypeAttributeIgnored() throws 
Exception {
+
+        final String attachmentId = UUID.randomUUID().toString();
+        final Attachment attachment = new Attachment();
+        attachment.setMimeType("text/xml");
+        attachment.addHeaders(getHeaders(attachmentId));
+        attachment.setId(attachmentId);
+        attachment.setSourceStream(new 
ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
+
+        AttachmentCallbackHandler attachmentCallbackHandler =
+            new 
AttachmentCallbackHandler(Collections.singletonList(attachment));
+        List<Attachment> encryptedAttachments = 
attachmentCallbackHandler.getResponseAttachments();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        {
+            WSSSecurityProperties securityProperties = new 
WSSSecurityProperties();
+            List<WSSConstants.Action> actions = new ArrayList<>();
+            actions.add(WSSConstants.ENCRYPTION);
+            securityProperties.setActions(actions);
+            
securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"),
 "default".toCharArray());
+            securityProperties.setEncryptionUser("receiver");
+            securityProperties.addEncryptionPart(new SecurePart(new 
QName("http://schemas.xmlsoap.org/soap/envelope/";, "Body"), 
SecurePart.Modifier.Content));
+            securityProperties.addEncryptionPart(new 
SecurePart("cid:Attachments", SecurePart.Modifier.Element));
+            
securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
+
+            OutboundWSSec wsSecOut = 
WSSec.getOutboundWSSec(securityProperties);
+            XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, 
StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
+            XMLStreamReader xmlStreamReader = 
xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
+            XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
+            xmlStreamWriter.close();
+        }
+
+        // Simulate a wire attacker rewriting the unauthenticated @MimeType 
attribute
+        Document securedDoc = 
documentBuilderFactory.newDocumentBuilder().parse(new 
ByteArrayInputStream(baos.toByteArray()));
+        NodeList encDatas = 
securedDoc.getElementsByTagNameNS(WSConstants.ENC_NS, "EncryptedData");
+        Element attachmentEncData = null;
+        for (int i = 0; i < encDatas.getLength(); i++) {
+            Element encData = (Element) encDatas.item(i);
+            if 
(WSConstants.SWA_ATTACHMENT_ENCRYPTED_DATA_TYPE_COMPLETE.equals(encData.getAttributeNS(null,
 "Type"))) {
+                attachmentEncData = encData;
+                break;
+            }
+        }
+        assertFalse(attachmentEncData == null);
+        attachmentEncData.setAttributeNS(null, "MimeType", 
"application/malicious");
+        encryptedAttachments.get(0).getHeaders().put("X-Attacker-Controlled", 
"forged");
+
+        ByteArrayOutputStream tamperedBaos = new ByteArrayOutputStream();
+        javax.xml.transform.TransformerFactory.newInstance().newTransformer()
+            .transform(new DOMSource(securedDoc), new 
StreamResult(tamperedBaos));
+
+        attachmentCallbackHandler = new 
AttachmentCallbackHandler(encryptedAttachments);
+        {
+            WSSSecurityProperties securityProperties = new 
WSSSecurityProperties();
+            
securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"),
 "default".toCharArray());
+            securityProperties.setCallbackHandler(new CallbackHandlerImpl());
+            
securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
+
+            InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
+            XMLStreamReader xmlStreamReader = 
wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new 
ByteArrayInputStream(tamperedBaos.toByteArray())));
+            StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), 
xmlStreamReader);
+        }
+
+        
assertFalse(attachmentCallbackHandler.getResponseAttachments().isEmpty());
+        Attachment responseAttachment = 
attachmentCallbackHandler.getResponseAttachments().get(0);
+        byte[] attachmentBytes = 
readInputStream(responseAttachment.getSourceStream());
+        assertTrue(Arrays.equals(attachmentBytes, 
SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
+        assertEquals("text/xml; charset=UTF-8", 
responseAttachment.getMimeType());
+        assertFalse(responseAttachment.getHeaders().containsKey("TestHeader"));
+        
assertFalse(responseAttachment.getHeaders().containsKey("X-Attacker-Controlled"));
+    }
+
+    // Regression test for CWE-345: if the protected header block (inside the 
ciphertext) does
+    // not contain a Content-Type header, decryption of an Attachment-Complete 
attachment must
+    // fail closed rather than falling back to the unauthenticated MimeType 
attribute.
+    @Test
+    public void 
testXMLAttachmentCompleteEncryptionMissingProtectedContentType() throws 
Exception {
+
+        final String attachmentId = UUID.randomUUID().toString();
+        final Attachment attachment = new Attachment();
+        attachment.setMimeType("text/xml");
+        Map<String, String> headers = getHeaders(attachmentId);
+        headers.remove(AttachmentUtils.MIME_HEADER_CONTENT_TYPE);
+        attachment.addHeaders(headers);
+        attachment.setId(attachmentId);
+        attachment.setSourceStream(new 
ByteArrayInputStream(SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
+
+        AttachmentCallbackHandler attachmentCallbackHandler =
+            new 
AttachmentCallbackHandler(Collections.singletonList(attachment));
+        List<Attachment> encryptedAttachments = 
attachmentCallbackHandler.getResponseAttachments();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        {
+            WSSSecurityProperties securityProperties = new 
WSSSecurityProperties();
+            List<WSSConstants.Action> actions = new ArrayList<>();
+            actions.add(WSSConstants.ENCRYPTION);
+            securityProperties.setActions(actions);
+            
securityProperties.loadEncryptionKeystore(this.getClass().getClassLoader().getResource("transmitter.jks"),
 "default".toCharArray());
+            securityProperties.setEncryptionUser("receiver");
+            securityProperties.addEncryptionPart(new SecurePart(new 
QName("http://schemas.xmlsoap.org/soap/envelope/";, "Body"), 
SecurePart.Modifier.Content));
+            securityProperties.addEncryptionPart(new 
SecurePart("cid:Attachments", SecurePart.Modifier.Element));
+            
securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
+
+            OutboundWSSec wsSecOut = 
WSSec.getOutboundWSSec(securityProperties);
+            XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, 
StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
+            XMLStreamReader xmlStreamReader = 
xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
+            XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
+            xmlStreamWriter.close();
+        }
+
+        attachmentCallbackHandler = new 
AttachmentCallbackHandler(encryptedAttachments);
+        WSSSecurityProperties securityProperties = new WSSSecurityProperties();
+        
securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"),
 "default".toCharArray());
+        securityProperties.setCallbackHandler(new CallbackHandlerImpl());
+        
securityProperties.setAttachmentCallbackHandler(attachmentCallbackHandler);
+
+        InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
+        XMLStreamReader xmlStreamReader = 
wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new 
ByteArrayInputStream(baos.toByteArray())));
+        try {
+            StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), 
xmlStreamReader);
+            fail("Expected a WSSecurityException due to the missing protected 
Content-Type header");
+        } catch (XMLStreamException e) {
+            assertTrue(e.getCause() instanceof WSSecurityException);
+            assertEquals(WSSecurityException.ErrorCode.INVALID_SECURITY, 
((WSSecurityException) e.getCause()).getErrorCode());
+        }
+    }
+
     @Test
     public void testMultipleAttachmentCompleteEncryption() throws Exception {
 
@@ -928,17 +1060,17 @@ public class AttachmentTest extends AbstractTestBase {
 
         byte[] attachment1Bytes = 
readInputStream(responseAttachment.getSourceStream());
         assertTrue(Arrays.equals(attachment1Bytes, 
SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
-        assertEquals("text/xml", responseAttachment.getMimeType());
+        assertEquals("text/xml; charset=UTF-8", 
responseAttachment.getMimeType());
         Map<String, String> att1Headers = responseAttachment.getHeaders();
-        assertEquals(6, att1Headers.size());
+        assertEquals(5, att1Headers.size());
 
         responseAttachment = 
attachmentCallbackHandler.getResponseAttachments().get(1);
 
         byte[] attachment2Bytes = 
readInputStream(responseAttachment.getSourceStream());
         assertTrue(Arrays.equals(attachment2Bytes, 
SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
-        assertEquals("text/plain", responseAttachment.getMimeType());
+        assertEquals("text/xml; charset=UTF-8", 
responseAttachment.getMimeType());
         Map<String, String> att2Headers = responseAttachment.getHeaders();
-        assertEquals(6, att2Headers.size());
+        assertEquals(5, att2Headers.size());
     }
 
     @Test
@@ -1036,10 +1168,10 @@ public class AttachmentTest extends AbstractTestBase {
 
         byte[] attachmentBytes = 
readInputStream(attachment[0].getSourceStream());
         assertTrue(Arrays.equals(attachmentBytes, 
SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
-        assertEquals("text/xml", attachment[0].getMimeType());
+        assertEquals("text/xml; charset=UTF-8", attachment[0].getMimeType());
 
         Map<String, String> attHeaders = attachment[0].getHeaders();
-        assertEquals(6, attHeaders.size());
+        assertEquals(5, attHeaders.size());
     }
 
     @Test
@@ -1111,7 +1243,7 @@ public class AttachmentTest extends AbstractTestBase {
                         List<Attachment> attachments = new ArrayList<>();
                         attachments.add(attachment[0]);
 
-                        if (attachment[0].getHeaders().size() == 6) {
+                        if (attachment[0].getHeaders().size() == 5) {
                             //signature callback
                             
attachment[0].addHeader(AttachmentUtils.MIME_HEADER_CONTENT_DESCRIPTION, 
"Kaputt");
                         }
@@ -1230,10 +1362,10 @@ public class AttachmentTest extends AbstractTestBase {
 
         byte[] attachmentBytes = 
readInputStream(attachment[0].getSourceStream());
         assertTrue(Arrays.equals(attachmentBytes, 
SOAPUtil.SAMPLE_SOAP_MSG.getBytes(StandardCharsets.UTF_8)));
-        assertEquals("text/xml", attachment[0].getMimeType());
+        assertEquals("text/xml; charset=UTF-8", attachment[0].getMimeType());
 
         Map<String, String> attHeaders = attachment[0].getHeaders();
-        assertEquals(6, attHeaders.size());
+        assertEquals(5, attHeaders.size());
     }
 
     @Test

Reply via email to