title: Accessing WCF Web Service From Apache CXF (MTOM + WS-Security)
body: <p>I've been struggling with this problem for quite a bit of time, and have not been able to solve it yet, despite looking around everywhere.</p>
  
  <p>Scenario details (code, config and other stuff is posted at the end):</p>
  
  <ol>
  <li>WCF Web Service (.NET 4), exposing two endpoints: one unsecured and one secured using Message Security and UserName authentication (using Membership infrastructure) -- No Transport Security.</li>
  <li>Both endpoints use MTOM encoding; all classed referred to by the WSDL are marked with the MessageContract attribute, and members with MessageBodyMember attribute.</li>
  <li>Configuration on WCF bindings has 'establishSecurityContext' and 'negotiateServiceCredential' set to false.</li>
  <li>WCF service protected with a self-signed certificate for encryption purposes.</li>
  <li>Attempting access from Java client using Apache CXF 2.5.1. I have setup the certificate into a KeyStore accesible from the classpath.</li>
  </ol>
  
  <p>The results:</p>
  
  <ol>
  <li>Accessing the Web Service from a .NET client works fine</li>
  <li>Accessing the unsecured endpoint from Apache CXF works fine both with and without MTOM encoding.</li>
  <li>Accessing the secured endpoint (without MTOM) from Apache CXF works fine. CXF tracing indicates that the encryption/decryption process is carried on normally.</li>
  <li>Once MTOM was activated in WCF, the problem arose. We were able to determine that in the WCF side, the reception of the message, its processing and generation/encryption of the response happens normally.</li>
  <li>It is during the reception of the message in CXF that the problem happens. It looks to us that CXF is not deserializing the MTOM attachment properly before trying to decrypt the message; hence, the decryption logic founds that the message still has an element to decrypt in the response, but founds an empty element to decrypt and fails. We tried to add a RECEIVE phase interceptor to initialize attachments, to no avail (fails trying to find the boundary marker in the multipart response).</li>
  <li>Using Fiddler, we found that the response looks well formed, with an attachment referred</li>
  </ol>
  
  <p>CODE/CONFIG/STUFF:</p>
  
  <p>Web.Config (shortened for clarity):</p>
  
  <pre><code>  &lt;system.serviceModel&gt;
      &lt;!-- Services --&gt;
      &lt;services&gt;
        &lt;service name="TestServices.Services.TestService" behaviorConfiguration="TestService.Basic"&gt;
          &lt;!-- Plain (unsecured) endpoint --&gt;
          &lt;endpoint address="" binding="wsHttpBinding" bindingConfiguration="TestService.Basic" name="TestService.Basic"
                    contract="TestServices.Interfaces.ITestService" bindingNamespace="http://searchtechnologies.com/cpa/wcfinterop"/&gt;
          &lt;!-- Secure endpoint --&gt;
          &lt;endpoint address="/secure" binding="wsHttpBinding" bindingConfiguration="TestService.Secure" name="TestService.Secure"
                    contract="TestServices.Interfaces.ITestService" bindingNamespace="http://searchtechnologies.com/cpa/wcfinterop"/&gt;
        &lt;/service&gt;
      &lt;/services&gt;
      &lt;!-- Bindings --&gt;
      &lt;bindings&gt;
        &lt;wsHttpBinding&gt;
          &lt;binding name="TestService.Basic" messageEncoding="Mtom"&gt;
            &lt;security mode="None"&gt;
              &lt;message clientCredentialType="None"/&gt;
              &lt;transport clientCredentialType="None"/&gt;
            &lt;/security&gt;
          &lt;/binding&gt;
          &lt;binding name="TestService.Secure" messageEncoding="Mtom"&gt;
            &lt;security mode="Message"&gt;
              &lt;message clientCredentialType="UserName" establishSecurityContext="false" negotiateServiceCredential="false"/&gt;
              &lt;transport clientCredentialType="None"/&gt;
            &lt;/security&gt;
          &lt;/binding&gt;
        &lt;/wsHttpBinding&gt;
      &lt;/bindings&gt;
      &lt;!-- Behaviors --&gt;
      &lt;behaviors&gt;
        &lt;serviceBehaviors&gt;
          &lt;behavior name="TestService.Basic"&gt;
            &lt;serviceMetadata httpGetEnabled="true"/&gt;
            &lt;serviceDebug includeExceptionDetailInFaults="true"/&gt;
            &lt;serviceCredentials&gt;
              &lt;serviceCertificate storeName="My" storeLocation="LocalMachine" x509FindType="FindBySubjectName" findValue="equiros-PC2.search.local"/&gt;
              &lt;userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="SqlProvider"/&gt;
            &lt;/serviceCredentials&gt;
          &lt;/behavior&gt;
        &lt;/serviceBehaviors&gt;
      &lt;/behaviors&gt;
  </code></pre>
  
  <p>The Java client code (portions omitted for clarity):</p>
  
  <pre><code>  private static void secureTest() {
      try {
        logger.debug("Secure test starting. Instatiating service");
        // service instantiation
        TestService service = new TestService();
        ITestService port = service.getTestServiceSecure();
        // request creation
        BasicRequest request = objectFactory.createBasicRequest();
        request.setStringData("String data");
        request.setIntegerData("Integer data");
        // setup logging
        setupInterceptors(port);
        // setup security &amp; binding
        setupBinding(port);
        // service call
        logger.debug("Attempting service call");
        BasicResponse response = port.simpleOperation(request);
        logger.debug("Call success!!!");
        logger.debug(String.format("Response data: str: %1$s; int: %2$s",
            response.getStringData(), response.getIntegerData()));
      } catch (Exception e) {
        logger.error("Error during service invocation", e);
      }
    }
  
    private static void setupInterceptors(ITestService port) {
      Client proxy = JaxWsClientProxy.getClient(port);
      proxy.getInInterceptors().add(new LoggingInInterceptor());
      proxy.getOutInterceptors().add(new LoggingOutInterceptor());
    }
  
    private static void setupBinding(ITestService port) {
      javax.xml.ws.BindingProvider bp = (javax.xml.ws.BindingProvider) port;
      SOAPBinding binding = (SOAPBinding) bp.getBinding();
      binding.setMTOMEnabled(true);
      Map&lt;String, Object&gt; context = bp.getRequestContext();
      context.put("ws-security.username", "systemadmin");
      context.put("ws-security.password", "Pass@word1");
      context.put("ws-security.encryption.properties",
          "clientKeystore.properties");
      context.put("ws-security.encryption.username", "serviceKey");
    }
  </code></pre>
  
  <p>The error trace (decryption phase only):</p>
  
  <pre><code>[main] DEBUG org.apache.ws.security.components.crypto.CryptoFactory  - Using Crypto Engine [class org.apache.ws.security.components.crypto.Merlin]
  [main] DEBUG org.apache.ws.security.util.Loader  - Trying to find [clientKeystore.jks] using sun.misc.Launcher$AppClassLoader@2a340e class loader.
  [main] DEBUG org.apache.ws.security.components.crypto.Merlin  - The KeyStore clientKeystore.jks of type jks has been loaded
  [main] DEBUG org.apache.ws.security.processor.TimestampProcessor  - Found Timestamp list element
  [main] DEBUG org.apache.ws.security.message.token.Timestamp  - Current time: 2012-02-07T22:52:22.852Z
  [main] DEBUG org.apache.ws.security.message.token.Timestamp  - Timestamp created: 2012-02-07T22:52:22.641Z
  [main] DEBUG org.apache.ws.security.message.token.Timestamp  - Timestamp expires: 2012-02-07T22:57:22.641Z
  [main] DEBUG org.apache.ws.security.message.token.Timestamp  - Validation of Timestamp: Everything is ok
  [main] DEBUG org.apache.ws.security.message.token.DerivedKeyToken  - DerivedKeyToken: created : element constructor
  [main] DEBUG org.apache.ws.security.message.token.DerivedKeyToken  - DerivedKeyToken: created : element constructor
  [main] DEBUG org.apache.ws.security.processor.ReferenceListProcessor  - Found reference list element
  [main] DEBUG org.apache.ws.security.processor.ReferenceListProcessor  - Found data reference: _3
  [main] DEBUG org.apache.ws.security.processor.X509Util  - Sym Enc Algo: http://www.w3.org/2001/04/xmlenc#aes256-cbc
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Getting XMLCipher with transformation
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Constructing XMLCipher...
  [main] DEBUG org.apache.xml.security.algorithms.JCEMapper  - Request for URI http://www.w3.org/2001/04/xmlenc#aes256-cbc
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - cipher._algorithm = AES/CBC/ISO10126Padding
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Initializing XMLCipher...
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - opmode = DECRYPT_MODE
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Processing source element...
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Decrypting element...
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Decrypting to ByteArray...
  [main] DEBUG org.apache.xml.security.utils.ElementProxy  - setElement("KeyInfo", "null")
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Encrypted octets:
  x1eLqhngbuRTq2XJIkcTdzyu1UFb4eV0kwno04/w4yW0HiY6RyYa7OHqniV63aaxgZPxm0NOK2ZUgjggtkM0O9myJ6ZJOFxCLmqREjQMD+mFW+WuTSEZ5cgc3SFule3MmryqoStNLsmzM8t5yaT3drF1ctT7DJQnV6W858WwpD+Dw+WYmO0RaUlgsfbTnWiBvCZ8yyCzvgmZTMGr8y9LXnwaw+FsspReuMpcIOsqU9LE5u5uW5ZJglgn5cv/8XWikD3TwNzqL+7qAVN8R6WnXgUmb1DuX5lx4cyxlwcLnkfOQKbGrwGvKJUY47ohAgKH
  [main] DEBUG org.apache.xml.security.algorithms.JCEMapper  - Request for URI http://www.w3.org/2001/04/xmlenc#aes256-cbc
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - JCE Algorithm = AES/CBC/ISO10126Padding
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Decrypted octets:
  &lt;BasicResponse xmlns="http://searchtechnologies.com/cpa/wcfinterop/data"&gt;&lt;DateTimeData&gt;0001-01-02T00:00:00&lt;/DateTimeData&gt;&lt;IntegerData&gt;Integer data&lt;/IntegerData&gt;&lt;StringData&gt;String data&lt;/StringData&gt;&lt;/BasicResponse&gt;
  [main] DEBUG org.apache.ws.security.processor.ReferenceListProcessor  - Found data reference: _6
  [main] DEBUG org.apache.ws.security.processor.X509Util  - Sym Enc Algo: http://www.w3.org/2001/04/xmlenc#aes256-cbc
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Getting XMLCipher with transformation
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Constructing XMLCipher...
  [main] DEBUG org.apache.xml.security.algorithms.JCEMapper  - Request for URI http://www.w3.org/2001/04/xmlenc#aes256-cbc
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - cipher._algorithm = AES/CBC/ISO10126Padding
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Initializing XMLCipher...
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - opmode = DECRYPT_MODE
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Processing source element...
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Decrypting element...
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Decrypting to ByteArray...
  [main] DEBUG org.apache.xml.security.utils.ElementProxy  - setElement("KeyInfo", "null")
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - Encrypted octets:
  
  [main] DEBUG org.apache.xml.security.algorithms.JCEMapper  - Request for URI http://www.w3.org/2001/04/xmlenc#aes256-cbc
  [main] DEBUG org.apache.xml.security.encryption.XMLCipher  - JCE Algorithm = AES/CBC/ISO10126Padding
  Feb 07, 2012 4:52:22 PM org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor handleMessage
  WARNING: 
  org.apache.ws.security.WSSecurityException: The signature or decryption was invalid
      at org.apache.ws.security.processor.ReferenceListProcessor.decryptEncryptedData(ReferenceListProcessor.java:298)
      at org.apache.ws.security.processor.ReferenceListProcessor.decryptDataRefEmbedded(ReferenceListProcessor.java:159)
      at org.apache.ws.security.processor.ReferenceListProcessor.handleReferenceList(ReferenceListProcessor.java:93)
      at org.apache.ws.security.processor.ReferenceListProcessor.handleToken(ReferenceListProcessor.java:60)
      at org.apache.ws.security.WSSecurityEngine.processSecurityHeader(WSSecurityEngine.java:396)
      at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:249)
      at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:85)
      at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
      at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:799)
      at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1627)
      at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1494)
      at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1402)
      at org.apache.cxf.io.CacheAndWriteOutputStream.postClose(CacheAndWriteOutputStream.java:47)
      at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:195)
      at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
      at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:649)
      at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
      at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
      at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:533)
      at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:463)
      at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:366)
      at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:319)
      at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:88)
      at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:134)
      at $Proxy33.simpleOperation(Unknown Source)
      at com.searchtechnologies.wcfinterop.TestServiceClient.secureTest(TestServiceClient.java:74)
      at com.searchtechnologies.wcfinterop.TestServiceClient.main(TestServiceClient.java:32)
  Caused by: java.lang.ArrayIndexOutOfBoundsException
      at java.lang.System.arraycopy(Native Method)
      at org.apache.xml.security.encryption.XMLCipher.decryptToByteArray(Unknown Source)
      at org.apache.xml.security.encryption.XMLCipher.decryptElement(Unknown Source)
      at org.apache.xml.security.encryption.XMLCipher.doFinal(Unknown Source)
      at org.apache.ws.security.processor.ReferenceListProcessor.decryptEncryptedData(ReferenceListProcessor.java:296)
      ... 26 more
  
  Feb 07, 2012 4:52:22 PM org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging
  WARNING: Interceptor for {http://searchtechnologies.com/cpa/wcfinterop}TestService#{http://searchtechnologies.com/cpa/wcfinterop}SimpleOperation has thrown exception, unwinding now
  org.apache.cxf.binding.soap.SoapFault: The signature or decryption was invalid
      at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.createSoapFault(WSS4JInInterceptor.java:643)
      at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:308)
      at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:85)
      at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
      at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:799)
      at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1627)
      at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1494)
      at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1402)
      at org.apache.cxf.io.CacheAndWriteOutputStream.postClose(CacheAndWriteOutputStream.java:47)
      at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:195)
      at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
      at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:649)
      at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
      at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
      at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:533)
      at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:463)
      at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:366)
      at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:319)
      at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:88)
      at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:134)
      at $Proxy33.simpleOperation(Unknown Source)
      at com.searchtechnologies.wcfinterop.TestServiceClient.secureTest(TestServiceClient.java:74)
      at com.searchtechnologies.wcfinterop.TestServiceClient.main(TestServiceClient.java:32)
  Caused by: org.apache.ws.security.WSSecurityException: The signature or decryption was invalid
      at org.apache.ws.security.processor.ReferenceListProcessor.decryptEncryptedData(ReferenceListProcessor.java:298)
      at org.apache.ws.security.processor.ReferenceListProcessor.decryptDataRefEmbedded(ReferenceListProcessor.java:159)
      at org.apache.ws.security.processor.ReferenceListProcessor.handleReferenceList(ReferenceListProcessor.java:93)
      at org.apache.ws.security.processor.ReferenceListProcessor.handleToken(ReferenceListProcessor.java:60)
      at org.apache.ws.security.WSSecurityEngine.processSecurityHeader(WSSecurityEngine.java:396)
      at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:249)
      ... 21 more
  Caused by: java.lang.ArrayIndexOutOfBoundsException
      at java.lang.System.arraycopy(Native Method)
      at org.apache.xml.security.encryption.XMLCipher.decryptToByteArray(Unknown Source)
      at org.apache.xml.security.encryption.XMLCipher.decryptElement(Unknown Source)
      at org.apache.xml.security.encryption.XMLCipher.doFinal(Unknown Source)
      at org.apache.ws.security.processor.ReferenceListProcessor.decryptEncryptedData(ReferenceListProcessor.java:296)
      ... 26 more
  
  [main] ERROR com.searchtechnologies.wcfinterop.TestServiceClient  - Error during service invocation
  java.lang.NullPointerException
      at com.sun.xml.internal.messaging.saaj.soap.impl.ElementImpl.addTextNode(ElementImpl.java:439)
      at com.sun.xml.internal.messaging.saaj.soap.ver1_2.Fault1_2Impl.setFaultRole(Fault1_2Impl.java:323)
      at com.sun.xml.internal.messaging.saaj.soap.ver1_2.Fault1_2Impl.setFaultActor(Fault1_2Impl.java:559)
      at org.apache.cxf.jaxws.JaxWsClientProxy.createSoapFault(JaxWsClientProxy.java:219)
      at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:152)
      at $Proxy33.simpleOperation(Unknown Source)
      at com.searchtechnologies.wcfinterop.TestServiceClient.secureTest(TestServiceClient.java:74)
      at com.searchtechnologies.wcfinterop.TestServiceClient.main(TestServiceClient.java:32)
  </code></pre>
  
  <p>As you can see, it looks like when CxF tries to decode the element which references the attachment, it finds its contents empty, and fails.</p>
  
  <p>Any help will be <em>deeply</em> appreciated.</p>
  
  <p>Couldn't post the WSDL because of size constraints. Available on request if necessary.</p>
  
  <p>Regards,</p>
  
  <p>Eduardo Quiros-Campos</p>